Initial commit: New MoreminiMore website with fresh design

This commit is contained in:
MoreminiMore
2026-04-22 01:59:05 +07:00
commit 76409638cc
14010 changed files with 2052041 additions and 0 deletions

77
node_modules/@libsql/hrana-client/lib-esm/batch.d.ts generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import type { RowsResult, RowResult, ValueResult, StmtResult } from "./result.js";
import type * as proto from "./shared/proto.js";
import type { InStmt } from "./stmt.js";
import { Stream } from "./stream.js";
/** A builder for creating a batch and executing it on the server. */
export declare class Batch {
#private;
/** @private */
_stream: Stream;
/** @private */
_steps: Array<BatchStepState>;
/** @private */
constructor(stream: Stream, useCursor: boolean);
/** Return a builder for adding a step to the batch. */
step(): BatchStep;
/** Execute the batch. */
execute(): Promise<void>;
}
interface BatchStepState {
proto: proto.BatchStep;
callback(stepResult: proto.StmtResult | undefined, stepError: proto.Error | undefined): void;
}
/** A builder for adding a step to the batch. */
export declare class BatchStep {
#private;
/** @private */
_batch: Batch;
/** @private */
_index: number | undefined;
/** @private */
constructor(batch: Batch);
/** Add the condition that needs to be satisfied to execute the statement. If you use this method multiple
* times, we join the conditions with a logical AND. */
condition(cond: BatchCond): this;
/** Add a statement that returns rows. */
query(stmt: InStmt): Promise<RowsResult | undefined>;
/** Add a statement that returns at most a single row. */
queryRow(stmt: InStmt): Promise<RowResult | undefined>;
/** Add a statement that returns at most a single value. */
queryValue(stmt: InStmt): Promise<ValueResult | undefined>;
/** Add a statement without returning rows. */
run(stmt: InStmt): Promise<StmtResult | undefined>;
}
export declare class BatchCond {
/** @private */
_batch: Batch;
/** @private */
_proto: proto.BatchCond;
/** @private */
constructor(batch: Batch, proto: proto.BatchCond);
/** Create a condition that evaluates to true when the given step executes successfully.
*
* If the given step fails error or is skipped because its condition evaluated to false, this
* condition evaluates to false.
*/
static ok(step: BatchStep): BatchCond;
/** Create a condition that evaluates to true when the given step fails.
*
* If the given step succeeds or is skipped because its condition evaluated to false, this condition
* evaluates to false.
*/
static error(step: BatchStep): BatchCond;
/** Create a condition that is a logical negation of another condition.
*/
static not(cond: BatchCond): BatchCond;
/** Create a condition that is a logical AND of other conditions.
*/
static and(batch: Batch, conds: Array<BatchCond>): BatchCond;
/** Create a condition that is a logical OR of other conditions.
*/
static or(batch: Batch, conds: Array<BatchCond>): BatchCond;
/** Create a condition that evaluates to true when the SQL connection is in autocommit mode (not inside an
* explicit transaction). This requires protocol version 3 or higher.
*/
static isAutocommit(batch: Batch): BatchCond;
}
export {};

271
node_modules/@libsql/hrana-client/lib-esm/batch.js generated vendored Normal file
View File

@@ -0,0 +1,271 @@
import { ProtoError, MisuseError } from "./errors.js";
import { stmtResultFromProto, rowsResultFromProto, rowResultFromProto, valueResultFromProto, errorFromProto, } from "./result.js";
import { stmtToProto } from "./stmt.js";
import { impossible } from "./util.js";
/** A builder for creating a batch and executing it on the server. */
export class Batch {
/** @private */
_stream;
#useCursor;
/** @private */
_steps;
#executed;
/** @private */
constructor(stream, useCursor) {
this._stream = stream;
this.#useCursor = useCursor;
this._steps = [];
this.#executed = false;
}
/** Return a builder for adding a step to the batch. */
step() {
return new BatchStep(this);
}
/** Execute the batch. */
execute() {
if (this.#executed) {
throw new MisuseError("This batch has already been executed");
}
this.#executed = true;
const batch = {
steps: this._steps.map((step) => step.proto),
};
if (this.#useCursor) {
return executeCursor(this._stream, this._steps, batch);
}
else {
return executeRegular(this._stream, this._steps, batch);
}
}
}
function executeRegular(stream, steps, batch) {
return stream._batch(batch).then((result) => {
for (let step = 0; step < steps.length; ++step) {
const stepResult = result.stepResults.get(step);
const stepError = result.stepErrors.get(step);
steps[step].callback(stepResult, stepError);
}
});
}
async function executeCursor(stream, steps, batch) {
const cursor = await stream._openCursor(batch);
try {
let nextStep = 0;
let beginEntry = undefined;
let rows = [];
for (;;) {
const entry = await cursor.next();
if (entry === undefined) {
break;
}
if (entry.type === "step_begin") {
if (entry.step < nextStep || entry.step >= steps.length) {
throw new ProtoError("Server produced StepBeginEntry for unexpected step");
}
else if (beginEntry !== undefined) {
throw new ProtoError("Server produced StepBeginEntry before terminating previous step");
}
for (let step = nextStep; step < entry.step; ++step) {
steps[step].callback(undefined, undefined);
}
nextStep = entry.step + 1;
beginEntry = entry;
rows = [];
}
else if (entry.type === "step_end") {
if (beginEntry === undefined) {
throw new ProtoError("Server produced StepEndEntry but no step is active");
}
const stmtResult = {
cols: beginEntry.cols,
rows,
affectedRowCount: entry.affectedRowCount,
lastInsertRowid: entry.lastInsertRowid,
};
steps[beginEntry.step].callback(stmtResult, undefined);
beginEntry = undefined;
rows = [];
}
else if (entry.type === "step_error") {
if (beginEntry === undefined) {
if (entry.step >= steps.length) {
throw new ProtoError("Server produced StepErrorEntry for unexpected step");
}
for (let step = nextStep; step < entry.step; ++step) {
steps[step].callback(undefined, undefined);
}
}
else {
if (entry.step !== beginEntry.step) {
throw new ProtoError("Server produced StepErrorEntry for unexpected step");
}
beginEntry = undefined;
rows = [];
}
steps[entry.step].callback(undefined, entry.error);
nextStep = entry.step + 1;
}
else if (entry.type === "row") {
if (beginEntry === undefined) {
throw new ProtoError("Server produced RowEntry but no step is active");
}
rows.push(entry.row);
}
else if (entry.type === "error") {
throw errorFromProto(entry.error);
}
else if (entry.type === "none") {
throw new ProtoError("Server produced unrecognized CursorEntry");
}
else {
throw impossible(entry, "Impossible CursorEntry");
}
}
if (beginEntry !== undefined) {
throw new ProtoError("Server closed Cursor before terminating active step");
}
for (let step = nextStep; step < steps.length; ++step) {
steps[step].callback(undefined, undefined);
}
}
finally {
cursor.close();
}
}
/** A builder for adding a step to the batch. */
export class BatchStep {
/** @private */
_batch;
#conds;
/** @private */
_index;
/** @private */
constructor(batch) {
this._batch = batch;
this.#conds = [];
this._index = undefined;
}
/** Add the condition that needs to be satisfied to execute the statement. If you use this method multiple
* times, we join the conditions with a logical AND. */
condition(cond) {
this.#conds.push(cond._proto);
return this;
}
/** Add a statement that returns rows. */
query(stmt) {
return this.#add(stmt, true, rowsResultFromProto);
}
/** Add a statement that returns at most a single row. */
queryRow(stmt) {
return this.#add(stmt, true, rowResultFromProto);
}
/** Add a statement that returns at most a single value. */
queryValue(stmt) {
return this.#add(stmt, true, valueResultFromProto);
}
/** Add a statement without returning rows. */
run(stmt) {
return this.#add(stmt, false, stmtResultFromProto);
}
#add(inStmt, wantRows, fromProto) {
if (this._index !== undefined) {
throw new MisuseError("This BatchStep has already been added to the batch");
}
const stmt = stmtToProto(this._batch._stream._sqlOwner(), inStmt, wantRows);
let condition;
if (this.#conds.length === 0) {
condition = undefined;
}
else if (this.#conds.length === 1) {
condition = this.#conds[0];
}
else {
condition = { type: "and", conds: this.#conds.slice() };
}
const proto = { stmt, condition };
return new Promise((outputCallback, errorCallback) => {
const callback = (stepResult, stepError) => {
if (stepResult !== undefined && stepError !== undefined) {
errorCallback(new ProtoError("Server returned both result and error"));
}
else if (stepError !== undefined) {
errorCallback(errorFromProto(stepError));
}
else if (stepResult !== undefined) {
outputCallback(fromProto(stepResult, this._batch._stream.intMode));
}
else {
outputCallback(undefined);
}
};
this._index = this._batch._steps.length;
this._batch._steps.push({ proto, callback });
});
}
}
export class BatchCond {
/** @private */
_batch;
/** @private */
_proto;
/** @private */
constructor(batch, proto) {
this._batch = batch;
this._proto = proto;
}
/** Create a condition that evaluates to true when the given step executes successfully.
*
* If the given step fails error or is skipped because its condition evaluated to false, this
* condition evaluates to false.
*/
static ok(step) {
return new BatchCond(step._batch, { type: "ok", step: stepIndex(step) });
}
/** Create a condition that evaluates to true when the given step fails.
*
* If the given step succeeds or is skipped because its condition evaluated to false, this condition
* evaluates to false.
*/
static error(step) {
return new BatchCond(step._batch, { type: "error", step: stepIndex(step) });
}
/** Create a condition that is a logical negation of another condition.
*/
static not(cond) {
return new BatchCond(cond._batch, { type: "not", cond: cond._proto });
}
/** Create a condition that is a logical AND of other conditions.
*/
static and(batch, conds) {
for (const cond of conds) {
checkCondBatch(batch, cond);
}
return new BatchCond(batch, { type: "and", conds: conds.map(e => e._proto) });
}
/** Create a condition that is a logical OR of other conditions.
*/
static or(batch, conds) {
for (const cond of conds) {
checkCondBatch(batch, cond);
}
return new BatchCond(batch, { type: "or", conds: conds.map(e => e._proto) });
}
/** Create a condition that evaluates to true when the SQL connection is in autocommit mode (not inside an
* explicit transaction). This requires protocol version 3 or higher.
*/
static isAutocommit(batch) {
batch._stream.client()._ensureVersion(3, "BatchCond.isAutocommit()");
return new BatchCond(batch, { type: "is_autocommit" });
}
}
function stepIndex(step) {
if (step._index === undefined) {
throw new MisuseError("Cannot add a condition referencing a step that has not been added to the batch");
}
return step._index;
}
function checkCondBatch(expectedBatch, cond) {
if (cond._batch !== expectedBatch) {
throw new MisuseError("Cannot mix BatchCond objects for different Batch objects");
}
}

View File

@@ -0,0 +1,8 @@
export declare class ByteQueue {
#private;
constructor(initialCap: number);
get length(): number;
data(): Uint8Array;
push(chunk: Uint8Array): void;
shift(length: number): void;
}

View File

@@ -0,0 +1,45 @@
export class ByteQueue {
#array;
#shiftPos;
#pushPos;
constructor(initialCap) {
this.#array = new Uint8Array(new ArrayBuffer(initialCap));
this.#shiftPos = 0;
this.#pushPos = 0;
}
get length() {
return this.#pushPos - this.#shiftPos;
}
data() {
return this.#array.slice(this.#shiftPos, this.#pushPos);
}
push(chunk) {
this.#ensurePush(chunk.byteLength);
this.#array.set(chunk, this.#pushPos);
this.#pushPos += chunk.byteLength;
}
#ensurePush(pushLength) {
if (this.#pushPos + pushLength <= this.#array.byteLength) {
return;
}
const filledLength = this.#pushPos - this.#shiftPos;
if (filledLength + pushLength <= this.#array.byteLength &&
2 * this.#pushPos >= this.#array.byteLength) {
this.#array.copyWithin(0, this.#shiftPos, this.#pushPos);
}
else {
let newCap = this.#array.byteLength;
do {
newCap *= 2;
} while (filledLength + pushLength > newCap);
const newArray = new Uint8Array(new ArrayBuffer(newCap));
newArray.set(this.#array.slice(this.#shiftPos, this.#pushPos), 0);
this.#array = newArray;
}
this.#pushPos = filledLength;
this.#shiftPos = 0;
}
shift(length) {
this.#shiftPos += length;
}
}

28
node_modules/@libsql/hrana-client/lib-esm/client.d.ts generated vendored Normal file
View File

@@ -0,0 +1,28 @@
import type { Stream } from "./stream.js";
import type { IntMode } from "./value.js";
export type ProtocolVersion = 1 | 2 | 3;
export type ProtocolEncoding = "json" | "protobuf";
/** A client for the Hrana protocol (a "database connection pool"). */
export declare abstract class Client {
/** @private */
constructor();
/** Get the protocol version negotiated with the server. */
abstract getVersion(): Promise<ProtocolVersion>;
/** @private */
abstract _ensureVersion(minVersion: ProtocolVersion, feature: string): void;
/** Open a {@link Stream}, a stream for executing SQL statements. */
abstract openStream(): Stream;
/** Immediately close the client.
*
* This closes the client immediately, aborting any pending operations.
*/
abstract close(): void;
/** True if the client is closed. */
abstract get closed(): boolean;
/** Representation of integers returned from the database. See {@link IntMode}.
*
* This value is inherited by {@link Stream} objects created with {@link openStream}, but you can
* override the integer mode for every stream by setting {@link Stream.intMode} on the stream.
*/
intMode: IntMode;
}

13
node_modules/@libsql/hrana-client/lib-esm/client.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
/** A client for the Hrana protocol (a "database connection pool"). */
export class Client {
/** @private */
constructor() {
this.intMode = "number";
}
/** Representation of integers returned from the database. See {@link IntMode}.
*
* This value is inherited by {@link Stream} objects created with {@link openStream}, but you can
* override the integer mode for every stream by setting {@link Stream.intMode} on the stream.
*/
intMode;
}

View File

@@ -0,0 +1,9 @@
import type * as proto from "./shared/proto.js";
export declare abstract class Cursor {
/** Fetch the next entry from the cursor. */
abstract next(): Promise<proto.CursorEntry | undefined>;
/** Close the cursor. */
abstract close(): void;
/** True if the cursor is closed. */
abstract get closed(): boolean;
}

2
node_modules/@libsql/hrana-client/lib-esm/cursor.js generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export class Cursor {
}

View File

@@ -0,0 +1,12 @@
import type * as proto from "./shared/proto.js";
export interface DescribeResult {
paramNames: Array<string | undefined>;
columns: Array<DescribeColumn>;
isExplain: boolean;
isReadonly: boolean;
}
export interface DescribeColumn {
name: string;
decltype: string | undefined;
}
export declare function describeResultFromProto(result: proto.DescribeResult): DescribeResult;

View File

@@ -0,0 +1,8 @@
export function describeResultFromProto(result) {
return {
paramNames: result.params.map((p) => p.name),
columns: result.cols,
isExplain: result.isExplain,
isReadonly: result.isReadonly,
};
}

View File

@@ -0,0 +1,4 @@
export { readJsonObject } from "./json/decode.js";
export { writeJsonObject } from "./json/encode.js";
export { readProtobufMessage } from "./protobuf/decode.js";
export { writeProtobufMessage } from "./protobuf/encode.js";

View File

@@ -0,0 +1,4 @@
export { readJsonObject } from "./json/decode.js";
export { writeJsonObject } from "./json/encode.js";
export { readProtobufMessage } from "./protobuf/decode.js";
export { writeProtobufMessage } from "./protobuf/encode.js";

View File

@@ -0,0 +1,13 @@
export type Value = Obj | Array<Value> | string | number | true | false | null;
export type Obj = {
[key: string]: Value | undefined;
};
export type ObjectFun<T> = (obj: Obj) => T;
export declare function string(value: Value | undefined): string;
export declare function stringOpt(value: Value | undefined): string | undefined;
export declare function number(value: Value | undefined): number;
export declare function boolean(value: Value | undefined): boolean;
export declare function array(value: Value | undefined): Array<Value>;
export declare function object(value: Value | undefined): Obj;
export declare function arrayObjectsMap<T>(value: Value | undefined, fun: ObjectFun<T>): Array<T>;
export declare function readJsonObject<T>(value: unknown, fun: ObjectFun<T>): T;

View File

@@ -0,0 +1,59 @@
import { ProtoError } from "../../errors.js";
export function string(value) {
if (typeof value === "string") {
return value;
}
throw typeError(value, "string");
}
export function stringOpt(value) {
if (value === null || value === undefined) {
return undefined;
}
else if (typeof value === "string") {
return value;
}
throw typeError(value, "string or null");
}
export function number(value) {
if (typeof value === "number") {
return value;
}
throw typeError(value, "number");
}
export function boolean(value) {
if (typeof value === "boolean") {
return value;
}
throw typeError(value, "boolean");
}
export function array(value) {
if (Array.isArray(value)) {
return value;
}
throw typeError(value, "array");
}
export function object(value) {
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
return value;
}
throw typeError(value, "object");
}
export function arrayObjectsMap(value, fun) {
return array(value).map((elemValue) => fun(object(elemValue)));
}
function typeError(value, expected) {
if (value === undefined) {
return new ProtoError(`Expected ${expected}, but the property was missing`);
}
let received = typeof value;
if (value === null) {
received = "null";
}
else if (Array.isArray(value)) {
received = "array";
}
return new ProtoError(`Expected ${expected}, received ${received}`);
}
export function readJsonObject(value, fun) {
return fun(object(value));
}

View File

@@ -0,0 +1,14 @@
export type ObjectFun<T> = (w: ObjectWriter, value: T) => void;
export declare class ObjectWriter {
#private;
constructor(output: Array<string>);
begin(): void;
end(): void;
string(name: string, value: string): void;
stringRaw(name: string, value: string): void;
number(name: string, value: number): void;
boolean(name: string, value: boolean): void;
object<T>(name: string, value: T, valueFun: ObjectFun<T>): void;
arrayObjects<T>(name: string, values: Array<T>, valueFun: ObjectFun<T>): void;
}
export declare function writeJsonObject<T>(value: T, fun: ObjectFun<T>): string;

View File

@@ -0,0 +1,72 @@
export class ObjectWriter {
#output;
#isFirst;
constructor(output) {
this.#output = output;
this.#isFirst = false;
}
begin() {
this.#output.push('{');
this.#isFirst = true;
}
end() {
this.#output.push('}');
this.#isFirst = false;
}
#key(name) {
if (this.#isFirst) {
this.#output.push('"');
this.#isFirst = false;
}
else {
this.#output.push(',"');
}
this.#output.push(name);
this.#output.push('":');
}
string(name, value) {
this.#key(name);
this.#output.push(JSON.stringify(value));
}
stringRaw(name, value) {
this.#key(name);
this.#output.push('"');
this.#output.push(value);
this.#output.push('"');
}
number(name, value) {
this.#key(name);
this.#output.push("" + value);
}
boolean(name, value) {
this.#key(name);
this.#output.push(value ? "true" : "false");
}
object(name, value, valueFun) {
this.#key(name);
this.begin();
valueFun(this, value);
this.end();
}
arrayObjects(name, values, valueFun) {
this.#key(name);
this.#output.push('[');
for (let i = 0; i < values.length; ++i) {
if (i !== 0) {
this.#output.push(',');
}
this.begin();
valueFun(this, values[i]);
this.end();
}
this.#output.push(']');
}
}
export function writeJsonObject(value, fun) {
const output = [];
const writer = new ObjectWriter(output);
writer.begin();
fun(writer, value);
writer.end();
return output.join("");
}

View File

@@ -0,0 +1,32 @@
export interface MessageDef<T> {
default(): T;
[tag: number]: (r: FieldReader, msg: T) => T | void;
}
declare class MessageReader {
#private;
constructor(array: Uint8Array);
varint(): number;
varintBig(): bigint;
bytes(length: number): Uint8Array;
double(): number;
skipVarint(): void;
skip(count: number): void;
eof(): boolean;
}
export declare class FieldReader {
#private;
constructor(reader: MessageReader);
setup(wireType: number): void;
bytes(): Uint8Array;
string(): string;
message<T>(def: MessageDef<T>): T;
int32(): number;
uint32(): number;
bool(): boolean;
uint64(): bigint;
sint64(): bigint;
double(): number;
maybeSkip(): void;
}
export declare function readProtobufMessage<T>(data: Uint8Array, def: MessageDef<T>): T;
export {};

View File

@@ -0,0 +1,150 @@
import { ProtoError } from "../../errors.js";
import { VARINT, FIXED_64, LENGTH_DELIMITED, FIXED_32 } from "./util.js";
class MessageReader {
#array;
#view;
#pos;
constructor(array) {
this.#array = array;
this.#view = new DataView(array.buffer, array.byteOffset, array.byteLength);
this.#pos = 0;
}
varint() {
let value = 0;
for (let shift = 0;; shift += 7) {
const byte = this.#array[this.#pos++];
value |= (byte & 0x7f) << shift;
if (!(byte & 0x80)) {
break;
}
}
return value;
}
varintBig() {
let value = 0n;
for (let shift = 0n;; shift += 7n) {
const byte = this.#array[this.#pos++];
value |= BigInt(byte & 0x7f) << shift;
if (!(byte & 0x80)) {
break;
}
}
return value;
}
bytes(length) {
const array = new Uint8Array(this.#array.buffer, this.#array.byteOffset + this.#pos, length);
this.#pos += length;
return array;
}
double() {
const value = this.#view.getFloat64(this.#pos, true);
this.#pos += 8;
return value;
}
skipVarint() {
for (;;) {
const byte = this.#array[this.#pos++];
if (!(byte & 0x80)) {
break;
}
}
}
skip(count) {
this.#pos += count;
}
eof() {
return this.#pos >= this.#array.byteLength;
}
}
export class FieldReader {
#reader;
#wireType;
constructor(reader) {
this.#reader = reader;
this.#wireType = -1;
}
setup(wireType) {
this.#wireType = wireType;
}
#expect(expectedWireType) {
if (this.#wireType !== expectedWireType) {
throw new ProtoError(`Expected wire type ${expectedWireType}, got ${this.#wireType}`);
}
this.#wireType = -1;
}
bytes() {
this.#expect(LENGTH_DELIMITED);
const length = this.#reader.varint();
return this.#reader.bytes(length);
}
string() {
return new TextDecoder().decode(this.bytes());
}
message(def) {
return readProtobufMessage(this.bytes(), def);
}
int32() {
this.#expect(VARINT);
return this.#reader.varint();
}
uint32() {
return this.int32();
}
bool() {
return this.int32() !== 0;
}
uint64() {
this.#expect(VARINT);
return this.#reader.varintBig();
}
sint64() {
const value = this.uint64();
return (value >> 1n) ^ (-(value & 1n));
}
double() {
this.#expect(FIXED_64);
return this.#reader.double();
}
maybeSkip() {
if (this.#wireType < 0) {
return;
}
else if (this.#wireType === VARINT) {
this.#reader.skipVarint();
}
else if (this.#wireType === FIXED_64) {
this.#reader.skip(8);
}
else if (this.#wireType === LENGTH_DELIMITED) {
const length = this.#reader.varint();
this.#reader.skip(length);
}
else if (this.#wireType === FIXED_32) {
this.#reader.skip(4);
}
else {
throw new ProtoError(`Unexpected wire type ${this.#wireType}`);
}
this.#wireType = -1;
}
}
export function readProtobufMessage(data, def) {
const msgReader = new MessageReader(data);
const fieldReader = new FieldReader(msgReader);
let value = def.default();
while (!msgReader.eof()) {
const key = msgReader.varint();
const tag = key >> 3;
const wireType = key & 0x7;
fieldReader.setup(wireType);
const tagFun = def[tag];
if (tagFun !== undefined) {
const returnedValue = tagFun(fieldReader, value);
if (returnedValue !== undefined) {
value = returnedValue;
}
}
fieldReader.maybeSkip();
}
return value;
}

View File

@@ -0,0 +1,15 @@
export type MessageFun<T> = (w: MessageWriter, msg: T) => void;
export declare class MessageWriter {
#private;
constructor();
bytes(tag: number, value: Uint8Array): void;
string(tag: number, value: string): void;
message<T>(tag: number, value: T, fun: MessageFun<T>): void;
int32(tag: number, value: number): void;
uint32(tag: number, value: number): void;
bool(tag: number, value: boolean): void;
sint64(tag: number, value: bigint): void;
double(tag: number, value: number): void;
data(): Uint8Array;
}
export declare function writeProtobufMessage<T>(value: T, fun: MessageFun<T>): Uint8Array;

View File

@@ -0,0 +1,95 @@
import { VARINT, FIXED_64, LENGTH_DELIMITED } from "./util.js";
export class MessageWriter {
#buf;
#array;
#view;
#pos;
constructor() {
this.#buf = new ArrayBuffer(256);
this.#array = new Uint8Array(this.#buf);
this.#view = new DataView(this.#buf);
this.#pos = 0;
}
#ensure(extra) {
if (this.#pos + extra <= this.#buf.byteLength) {
return;
}
let newCap = this.#buf.byteLength;
while (newCap < this.#pos + extra) {
newCap *= 2;
}
const newBuf = new ArrayBuffer(newCap);
const newArray = new Uint8Array(newBuf);
const newView = new DataView(newBuf);
newArray.set(new Uint8Array(this.#buf, 0, this.#pos));
this.#buf = newBuf;
this.#array = newArray;
this.#view = newView;
}
#varint(value) {
this.#ensure(5);
value = 0 | value;
do {
let byte = value & 0x7f;
value >>>= 7;
byte |= (value ? 0x80 : 0);
this.#array[this.#pos++] = byte;
} while (value);
}
#varintBig(value) {
this.#ensure(10);
value = value & 0xffffffffffffffffn;
do {
let byte = Number(value & 0x7fn);
value >>= 7n;
byte |= (value ? 0x80 : 0);
this.#array[this.#pos++] = byte;
} while (value);
}
#tag(tag, wireType) {
this.#varint((tag << 3) | wireType);
}
bytes(tag, value) {
this.#tag(tag, LENGTH_DELIMITED);
this.#varint(value.byteLength);
this.#ensure(value.byteLength);
this.#array.set(value, this.#pos);
this.#pos += value.byteLength;
}
string(tag, value) {
this.bytes(tag, new TextEncoder().encode(value));
}
message(tag, value, fun) {
const writer = new MessageWriter();
fun(writer, value);
this.bytes(tag, writer.data());
}
int32(tag, value) {
this.#tag(tag, VARINT);
this.#varint(value);
}
uint32(tag, value) {
this.int32(tag, value);
}
bool(tag, value) {
this.int32(tag, value ? 1 : 0);
}
sint64(tag, value) {
this.#tag(tag, VARINT);
this.#varintBig((value << 1n) ^ (value >> 63n));
}
double(tag, value) {
this.#tag(tag, FIXED_64);
this.#ensure(8);
this.#view.setFloat64(this.#pos, value, true);
this.#pos += 8;
}
data() {
return new Uint8Array(this.#buf, 0, this.#pos);
}
}
export function writeProtobufMessage(value, fun) {
const w = new MessageWriter();
fun(w, value);
return w.data();
}

View File

@@ -0,0 +1,7 @@
export type WireType = 0 | 1 | 2 | 3 | 4 | 5;
export declare const VARINT: WireType;
export declare const FIXED_64: WireType;
export declare const LENGTH_DELIMITED: WireType;
export declare const GROUP_START: WireType;
export declare const GROUP_END: WireType;
export declare const FIXED_32: WireType;

View File

@@ -0,0 +1,6 @@
export const VARINT = 0;
export const FIXED_64 = 1;
export const LENGTH_DELIMITED = 2;
export const GROUP_START = 3;
export const GROUP_END = 4;
export const FIXED_32 = 5;

60
node_modules/@libsql/hrana-client/lib-esm/errors.d.ts generated vendored Normal file
View File

@@ -0,0 +1,60 @@
import type * as proto from "./shared/proto.js";
/** Generic error produced by the Hrana client. */
export declare class ClientError extends Error {
/** @private */
constructor(message: string);
}
/** Error thrown when the server violates the protocol. */
export declare class ProtoError extends ClientError {
/** @private */
constructor(message: string);
}
/** Error thrown when the server returns an error response. */
export declare class ResponseError extends ClientError {
code: string | undefined;
/** @internal */
proto: proto.Error;
/** @private */
constructor(message: string, protoError: proto.Error);
}
/** Error thrown when the client or stream is closed. */
export declare class ClosedError extends ClientError {
/** @private */
constructor(message: string, cause: Error | undefined);
}
/** Error thrown when the environment does not seem to support WebSockets. */
export declare class WebSocketUnsupportedError extends ClientError {
/** @private */
constructor(message: string);
}
/** Error thrown when we encounter a WebSocket error. */
export declare class WebSocketError extends ClientError {
/** @private */
constructor(message: string);
}
/** Error thrown when the HTTP server returns an error response. */
export declare class HttpServerError extends ClientError {
status: number;
/** @private */
constructor(message: string, status: number);
}
/** Error thrown when a libsql URL is not valid. */
export declare class LibsqlUrlParseError extends ClientError {
/** @private */
constructor(message: string);
}
/** Error thrown when the protocol version is too low to support a feature. */
export declare class ProtocolVersionError extends ClientError {
/** @private */
constructor(message: string);
}
/** Error thrown when an internal client error happens. */
export declare class InternalError extends ClientError {
/** @private */
constructor(message: string);
}
/** Error thrown when the API is misused. */
export declare class MisuseError extends ClientError {
/** @private */
constructor(message: string);
}

102
node_modules/@libsql/hrana-client/lib-esm/errors.js generated vendored Normal file
View File

@@ -0,0 +1,102 @@
/** Generic error produced by the Hrana client. */
export class ClientError extends Error {
/** @private */
constructor(message) {
super(message);
this.name = "ClientError";
}
}
/** Error thrown when the server violates the protocol. */
export class ProtoError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "ProtoError";
}
}
/** Error thrown when the server returns an error response. */
export class ResponseError extends ClientError {
code;
/** @internal */
proto;
/** @private */
constructor(message, protoError) {
super(message);
this.name = "ResponseError";
this.code = protoError.code;
this.proto = protoError;
this.stack = undefined;
}
}
/** Error thrown when the client or stream is closed. */
export class ClosedError extends ClientError {
/** @private */
constructor(message, cause) {
if (cause !== undefined) {
super(`${message}: ${cause}`);
this.cause = cause;
}
else {
super(message);
}
this.name = "ClosedError";
}
}
/** Error thrown when the environment does not seem to support WebSockets. */
export class WebSocketUnsupportedError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "WebSocketUnsupportedError";
}
}
/** Error thrown when we encounter a WebSocket error. */
export class WebSocketError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "WebSocketError";
}
}
/** Error thrown when the HTTP server returns an error response. */
export class HttpServerError extends ClientError {
status;
/** @private */
constructor(message, status) {
super(message);
this.status = status;
this.name = "HttpServerError";
}
}
/** Error thrown when a libsql URL is not valid. */
export class LibsqlUrlParseError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "LibsqlUrlParseError";
}
}
/** Error thrown when the protocol version is too low to support a feature. */
export class ProtocolVersionError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "ProtocolVersionError";
}
}
/** Error thrown when an internal client error happens. */
export class InternalError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "InternalError";
}
}
/** Error thrown when the API is misused. */
export class MisuseError extends ClientError {
/** @private */
constructor(message) {
super(message);
this.name = "MisuseError";
}
}

View File

@@ -0,0 +1,34 @@
/// <reference types="node" />
import type { ProtocolVersion, ProtocolEncoding } from "../client.js";
import { Client } from "../client.js";
import { HttpStream } from "./stream.js";
export type Endpoint = {
versionPath: string;
pipelinePath: string;
cursorPath: string | undefined;
version: ProtocolVersion;
encoding: ProtocolEncoding;
};
export declare const checkEndpoints: Array<Endpoint>;
/** A client for the Hrana protocol over HTTP. */
export declare class HttpClient extends Client {
#private;
/** @private */
_endpointPromise: Promise<Endpoint>;
/** @private */
_endpoint: Endpoint | undefined;
/** @private */
constructor(url: URL, jwt: string | undefined, customFetch: unknown | undefined, protocolVersion?: ProtocolVersion);
/** Get the protocol version supported by the server. */
getVersion(): Promise<ProtocolVersion>;
/** @private */
_ensureVersion(minVersion: ProtocolVersion, feature: string): void;
/** Open a {@link HttpStream}, a stream for executing SQL statements. */
openStream(): HttpStream;
/** @private */
_streamClosed(stream: HttpStream): void;
/** Close the client and all its streams. */
close(): void;
/** True if the client is closed. */
get closed(): boolean;
}

View File

@@ -0,0 +1,124 @@
import { fetch, Request } from "@libsql/isomorphic-fetch";
import { Client } from "../client.js";
import { ClientError, ClosedError, ProtocolVersionError } from "../errors.js";
import { HttpStream } from "./stream.js";
export const checkEndpoints = [
{
versionPath: "v3-protobuf",
pipelinePath: "v3-protobuf/pipeline",
cursorPath: "v3-protobuf/cursor",
version: 3,
encoding: "protobuf",
},
/*
{
versionPath: "v3",
pipelinePath: "v3/pipeline",
cursorPath: "v3/cursor",
version: 3,
encoding: "json",
},
*/
];
const fallbackEndpoint = {
versionPath: "v2",
pipelinePath: "v2/pipeline",
cursorPath: undefined,
version: 2,
encoding: "json",
};
/** A client for the Hrana protocol over HTTP. */
export class HttpClient extends Client {
#url;
#jwt;
#fetch;
#closed;
#streams;
/** @private */
_endpointPromise;
/** @private */
_endpoint;
/** @private */
constructor(url, jwt, customFetch, protocolVersion = 2) {
super();
this.#url = url;
this.#jwt = jwt;
this.#fetch = customFetch ?? fetch;
this.#closed = undefined;
this.#streams = new Set();
if (protocolVersion == 3) {
this._endpointPromise = findEndpoint(this.#fetch, this.#url);
this._endpointPromise.then((endpoint) => this._endpoint = endpoint, (error) => this.#setClosed(error));
}
else {
this._endpointPromise = Promise.resolve(fallbackEndpoint);
this._endpointPromise.then((endpoint) => this._endpoint = endpoint, (error) => this.#setClosed(error));
}
}
/** Get the protocol version supported by the server. */
async getVersion() {
if (this._endpoint !== undefined) {
return this._endpoint.version;
}
return (await this._endpointPromise).version;
}
// Make sure that the negotiated version is at least `minVersion`.
/** @private */
_ensureVersion(minVersion, feature) {
if (minVersion <= fallbackEndpoint.version) {
return;
}
else if (this._endpoint === undefined) {
throw new ProtocolVersionError(`${feature} is supported only on protocol version ${minVersion} and higher, ` +
"but the version supported by the HTTP server is not yet known. " +
"Use Client.getVersion() to wait until the version is available.");
}
else if (this._endpoint.version < minVersion) {
throw new ProtocolVersionError(`${feature} is supported only on protocol version ${minVersion} and higher, ` +
`but the HTTP server only supports version ${this._endpoint.version}.`);
}
}
/** Open a {@link HttpStream}, a stream for executing SQL statements. */
openStream() {
if (this.#closed !== undefined) {
throw new ClosedError("Client is closed", this.#closed);
}
const stream = new HttpStream(this, this.#url, this.#jwt, this.#fetch);
this.#streams.add(stream);
return stream;
}
/** @private */
_streamClosed(stream) {
this.#streams.delete(stream);
}
/** Close the client and all its streams. */
close() {
this.#setClosed(new ClientError("Client was manually closed"));
}
/** True if the client is closed. */
get closed() {
return this.#closed !== undefined;
}
#setClosed(error) {
if (this.#closed !== undefined) {
return;
}
this.#closed = error;
for (const stream of Array.from(this.#streams)) {
stream._setClosed(new ClosedError("Client was closed", error));
}
}
}
async function findEndpoint(customFetch, clientUrl) {
const fetch = customFetch;
for (const endpoint of checkEndpoints) {
const url = new URL(endpoint.versionPath, clientUrl);
const request = new Request(url.toString(), { method: "GET" });
const response = await fetch(request);
await response.arrayBuffer();
if (response.ok) {
return endpoint;
}
}
return fallbackEndpoint;
}

View File

@@ -0,0 +1,19 @@
import type { Response } from "@libsql/isomorphic-fetch";
import type { ProtocolEncoding } from "../client.js";
import { Cursor } from "../cursor.js";
import type * as proto from "./proto.js";
import type { HttpStream } from "./stream.js";
export declare class HttpCursor extends Cursor {
#private;
/** @private */
constructor(stream: HttpStream, encoding: ProtocolEncoding);
open(response: Response): Promise<proto.CursorRespBody>;
/** Fetch the next entry from the cursor. */
next(): Promise<proto.CursorEntry | undefined>;
/** Close the cursor. */
close(): void;
/** @private */
_setClosed(error: Error): void;
/** True if the cursor is closed. */
get closed(): boolean;
}

View File

@@ -0,0 +1,135 @@
import { ByteQueue } from "../byte_queue.js";
import { Cursor } from "../cursor.js";
import * as jsond from "../encoding/json/decode.js";
import * as protobufd from "../encoding/protobuf/decode.js";
import { ClientError, ClosedError, ProtoError, InternalError } from "../errors.js";
import { impossible } from "../util.js";
import { CursorRespBody as json_CursorRespBody } from "./json_decode.js";
import { CursorRespBody as protobuf_CursorRespBody } from "./protobuf_decode.js";
import { CursorEntry as json_CursorEntry } from "../shared/json_decode.js";
import { CursorEntry as protobuf_CursorEntry } from "../shared/protobuf_decode.js";
export class HttpCursor extends Cursor {
#stream;
#encoding;
#reader;
#queue;
#closed;
#done;
/** @private */
constructor(stream, encoding) {
super();
this.#stream = stream;
this.#encoding = encoding;
this.#reader = undefined;
this.#queue = new ByteQueue(16 * 1024);
this.#closed = undefined;
this.#done = false;
}
async open(response) {
if (response.body === null) {
throw new ProtoError("No response body for cursor request");
}
this.#reader = response.body.getReader();
const respBody = await this.#nextItem(json_CursorRespBody, protobuf_CursorRespBody);
if (respBody === undefined) {
throw new ProtoError("Empty response to cursor request");
}
return respBody;
}
/** Fetch the next entry from the cursor. */
next() {
return this.#nextItem(json_CursorEntry, protobuf_CursorEntry);
}
/** Close the cursor. */
close() {
this._setClosed(new ClientError("Cursor was manually closed"));
}
/** @private */
_setClosed(error) {
if (this.#closed !== undefined) {
return;
}
this.#closed = error;
this.#stream._cursorClosed(this);
if (this.#reader !== undefined) {
this.#reader.cancel();
}
}
/** True if the cursor is closed. */
get closed() {
return this.#closed !== undefined;
}
async #nextItem(jsonFun, protobufDef) {
for (;;) {
if (this.#done) {
return undefined;
}
else if (this.#closed !== undefined) {
throw new ClosedError("Cursor is closed", this.#closed);
}
if (this.#encoding === "json") {
const jsonData = this.#parseItemJson();
if (jsonData !== undefined) {
const jsonText = new TextDecoder().decode(jsonData);
const jsonValue = JSON.parse(jsonText);
return jsond.readJsonObject(jsonValue, jsonFun);
}
}
else if (this.#encoding === "protobuf") {
const protobufData = this.#parseItemProtobuf();
if (protobufData !== undefined) {
return protobufd.readProtobufMessage(protobufData, protobufDef);
}
}
else {
throw impossible(this.#encoding, "Impossible encoding");
}
if (this.#reader === undefined) {
throw new InternalError("Attempted to read from HTTP cursor before it was opened");
}
const { value, done } = await this.#reader.read();
if (done && this.#queue.length === 0) {
this.#done = true;
}
else if (done) {
throw new ProtoError("Unexpected end of cursor stream");
}
else {
this.#queue.push(value);
}
}
}
#parseItemJson() {
const data = this.#queue.data();
const newlineByte = 10;
const newlinePos = data.indexOf(newlineByte);
if (newlinePos < 0) {
return undefined;
}
const jsonData = data.slice(0, newlinePos);
this.#queue.shift(newlinePos + 1);
return jsonData;
}
#parseItemProtobuf() {
const data = this.#queue.data();
let varintValue = 0;
let varintLength = 0;
for (;;) {
if (varintLength >= data.byteLength) {
return undefined;
}
const byte = data[varintLength];
varintValue |= (byte & 0x7f) << (7 * varintLength);
varintLength += 1;
if (!(byte & 0x80)) {
break;
}
}
if (data.byteLength < varintLength + varintValue) {
return undefined;
}
const protobufData = data.slice(varintLength, varintLength + varintValue);
this.#queue.shift(varintLength + varintValue);
return protobufData;
}
}

View File

@@ -0,0 +1,4 @@
import * as d from "../encoding/json/decode.js";
import * as proto from "./proto.js";
export declare function PipelineRespBody(obj: d.Obj): proto.PipelineRespBody;
export declare function CursorRespBody(obj: d.Obj): proto.CursorRespBody;

View File

@@ -0,0 +1,62 @@
import { ProtoError } from "../errors.js";
import * as d from "../encoding/json/decode.js";
import { Error, StmtResult, BatchResult, DescribeResult } from "../shared/json_decode.js";
export function PipelineRespBody(obj) {
const baton = d.stringOpt(obj["baton"]);
const baseUrl = d.stringOpt(obj["base_url"]);
const results = d.arrayObjectsMap(obj["results"], StreamResult);
return { baton, baseUrl, results };
}
function StreamResult(obj) {
const type = d.string(obj["type"]);
if (type === "ok") {
const response = StreamResponse(d.object(obj["response"]));
return { type: "ok", response };
}
else if (type === "error") {
const error = Error(d.object(obj["error"]));
return { type: "error", error };
}
else {
throw new ProtoError("Unexpected type of StreamResult");
}
}
function StreamResponse(obj) {
const type = d.string(obj["type"]);
if (type === "close") {
return { type: "close" };
}
else if (type === "execute") {
const result = StmtResult(d.object(obj["result"]));
return { type: "execute", result };
}
else if (type === "batch") {
const result = BatchResult(d.object(obj["result"]));
return { type: "batch", result };
}
else if (type === "sequence") {
return { type: "sequence" };
}
else if (type === "describe") {
const result = DescribeResult(d.object(obj["result"]));
return { type: "describe", result };
}
else if (type === "store_sql") {
return { type: "store_sql" };
}
else if (type === "close_sql") {
return { type: "close_sql" };
}
else if (type === "get_autocommit") {
const isAutocommit = d.boolean(obj["is_autocommit"]);
return { type: "get_autocommit", isAutocommit };
}
else {
throw new ProtoError("Unexpected type of StreamResponse");
}
}
export function CursorRespBody(obj) {
const baton = d.stringOpt(obj["baton"]);
const baseUrl = d.stringOpt(obj["base_url"]);
return { baton, baseUrl };
}

View File

@@ -0,0 +1,4 @@
import * as e from "../encoding/json/encode.js";
import * as proto from "./proto.js";
export declare function PipelineReqBody(w: e.ObjectWriter, msg: proto.PipelineReqBody): void;
export declare function CursorReqBody(w: e.ObjectWriter, msg: proto.CursorReqBody): void;

View File

@@ -0,0 +1,55 @@
import { Stmt, Batch } from "../shared/json_encode.js";
import { impossible } from "../util.js";
export function PipelineReqBody(w, msg) {
if (msg.baton !== undefined) {
w.string("baton", msg.baton);
}
w.arrayObjects("requests", msg.requests, StreamRequest);
}
function StreamRequest(w, msg) {
w.stringRaw("type", msg.type);
if (msg.type === "close") {
// do nothing
}
else if (msg.type === "execute") {
w.object("stmt", msg.stmt, Stmt);
}
else if (msg.type === "batch") {
w.object("batch", msg.batch, Batch);
}
else if (msg.type === "sequence") {
if (msg.sql !== undefined) {
w.string("sql", msg.sql);
}
if (msg.sqlId !== undefined) {
w.number("sql_id", msg.sqlId);
}
}
else if (msg.type === "describe") {
if (msg.sql !== undefined) {
w.string("sql", msg.sql);
}
if (msg.sqlId !== undefined) {
w.number("sql_id", msg.sqlId);
}
}
else if (msg.type === "store_sql") {
w.number("sql_id", msg.sqlId);
w.string("sql", msg.sql);
}
else if (msg.type === "close_sql") {
w.number("sql_id", msg.sqlId);
}
else if (msg.type === "get_autocommit") {
// do nothing
}
else {
throw impossible(msg, "Impossible type of StreamRequest");
}
}
export function CursorReqBody(w, msg) {
if (msg.baton !== undefined) {
w.string("baton", msg.baton);
}
w.object("batch", msg.batch, Batch);
}

View File

@@ -0,0 +1,95 @@
export * from "../shared/proto.js";
import { int32, Error, Stmt, StmtResult, Batch, BatchResult, DescribeResult } from "../shared/proto.js";
export type PipelineReqBody = {
baton: string | undefined;
requests: Array<StreamRequest>;
};
export type PipelineRespBody = {
baton: string | undefined;
baseUrl: string | undefined;
results: Array<StreamResult>;
};
export type StreamResult = {
type: "none";
} | StreamResultOk | StreamResultError;
export type StreamResultOk = {
type: "ok";
response: StreamResponse;
};
export type StreamResultError = {
type: "error";
error: Error;
};
export type CursorReqBody = {
baton: string | undefined;
batch: Batch;
};
export type CursorRespBody = {
baton: string | undefined;
baseUrl: string | undefined;
};
export type StreamRequest = CloseStreamReq | ExecuteStreamReq | BatchStreamReq | SequenceStreamReq | DescribeStreamReq | StoreSqlStreamReq | CloseSqlStreamReq | GetAutocommitStreamReq;
export type StreamResponse = {
type: "none";
} | CloseStreamResp | ExecuteStreamResp | BatchStreamResp | SequenceStreamResp | DescribeStreamResp | StoreSqlStreamResp | CloseSqlStreamResp | GetAutocommitStreamResp;
export type CloseStreamReq = {
type: "close";
};
export type CloseStreamResp = {
type: "close";
};
export type ExecuteStreamReq = {
type: "execute";
stmt: Stmt;
};
export type ExecuteStreamResp = {
type: "execute";
result: StmtResult;
};
export type BatchStreamReq = {
type: "batch";
batch: Batch;
};
export type BatchStreamResp = {
type: "batch";
result: BatchResult;
};
export type SequenceStreamReq = {
type: "sequence";
sql: string | undefined;
sqlId: int32 | undefined;
};
export type SequenceStreamResp = {
type: "sequence";
};
export type DescribeStreamReq = {
type: "describe";
sql: string | undefined;
sqlId: int32 | undefined;
};
export type DescribeStreamResp = {
type: "describe";
result: DescribeResult;
};
export type StoreSqlStreamReq = {
type: "store_sql";
sqlId: int32;
sql: string;
};
export type StoreSqlStreamResp = {
type: "store_sql";
};
export type CloseSqlStreamReq = {
type: "close_sql";
sqlId: int32;
};
export type CloseSqlStreamResp = {
type: "close_sql";
};
export type GetAutocommitStreamReq = {
type: "get_autocommit";
};
export type GetAutocommitStreamResp = {
type: "get_autocommit";
isAutocommit: boolean;
};

View File

@@ -0,0 +1,2 @@
// Types for the structures specific to Hrana over HTTP.
export * from "../shared/proto.js";

View File

@@ -0,0 +1,4 @@
import * as d from "../encoding/protobuf/decode.js";
import * as proto from "./proto.js";
export declare const PipelineRespBody: d.MessageDef<proto.PipelineRespBody>;
export declare const CursorRespBody: d.MessageDef<proto.CursorRespBody>;

View File

@@ -0,0 +1,44 @@
import { Error, StmtResult, BatchResult, DescribeResult } from "../shared/protobuf_decode.js";
export const PipelineRespBody = {
default() { return { baton: undefined, baseUrl: undefined, results: [] }; },
1(r, msg) { msg.baton = r.string(); },
2(r, msg) { msg.baseUrl = r.string(); },
3(r, msg) { msg.results.push(r.message(StreamResult)); },
};
const StreamResult = {
default() { return { type: "none" }; },
1(r) { return { type: "ok", response: r.message(StreamResponse) }; },
2(r) { return { type: "error", error: r.message(Error) }; },
};
const StreamResponse = {
default() { return { type: "none" }; },
1(r) { return { type: "close" }; },
2(r) { return r.message(ExecuteStreamResp); },
3(r) { return r.message(BatchStreamResp); },
4(r) { return { type: "sequence" }; },
5(r) { return r.message(DescribeStreamResp); },
6(r) { return { type: "store_sql" }; },
7(r) { return { type: "close_sql" }; },
8(r) { return r.message(GetAutocommitStreamResp); },
};
const ExecuteStreamResp = {
default() { return { type: "execute", result: StmtResult.default() }; },
1(r, msg) { msg.result = r.message(StmtResult); },
};
const BatchStreamResp = {
default() { return { type: "batch", result: BatchResult.default() }; },
1(r, msg) { msg.result = r.message(BatchResult); },
};
const DescribeStreamResp = {
default() { return { type: "describe", result: DescribeResult.default() }; },
1(r, msg) { msg.result = r.message(DescribeResult); },
};
const GetAutocommitStreamResp = {
default() { return { type: "get_autocommit", isAutocommit: false }; },
1(r, msg) { msg.isAutocommit = r.bool(); },
};
export const CursorRespBody = {
default() { return { baton: undefined, baseUrl: undefined }; },
1(r, msg) { msg.baton = r.string(); },
2(r, msg) { msg.baseUrl = r.string(); },
};

View File

@@ -0,0 +1,4 @@
import * as e from "../encoding/protobuf/encode.js";
import * as proto from "./proto.js";
export declare function PipelineReqBody(w: e.MessageWriter, msg: proto.PipelineReqBody): void;
export declare function CursorReqBody(w: e.MessageWriter, msg: proto.CursorReqBody): void;

View File

@@ -0,0 +1,78 @@
import { Stmt, Batch } from "../shared/protobuf_encode.js";
import { impossible } from "../util.js";
export function PipelineReqBody(w, msg) {
if (msg.baton !== undefined) {
w.string(1, msg.baton);
}
for (const req of msg.requests) {
w.message(2, req, StreamRequest);
}
}
function StreamRequest(w, msg) {
if (msg.type === "close") {
w.message(1, msg, CloseStreamReq);
}
else if (msg.type === "execute") {
w.message(2, msg, ExecuteStreamReq);
}
else if (msg.type === "batch") {
w.message(3, msg, BatchStreamReq);
}
else if (msg.type === "sequence") {
w.message(4, msg, SequenceStreamReq);
}
else if (msg.type === "describe") {
w.message(5, msg, DescribeStreamReq);
}
else if (msg.type === "store_sql") {
w.message(6, msg, StoreSqlStreamReq);
}
else if (msg.type === "close_sql") {
w.message(7, msg, CloseSqlStreamReq);
}
else if (msg.type === "get_autocommit") {
w.message(8, msg, GetAutocommitStreamReq);
}
else {
throw impossible(msg, "Impossible type of StreamRequest");
}
}
function CloseStreamReq(_w, _msg) {
}
function ExecuteStreamReq(w, msg) {
w.message(1, msg.stmt, Stmt);
}
function BatchStreamReq(w, msg) {
w.message(1, msg.batch, Batch);
}
function SequenceStreamReq(w, msg) {
if (msg.sql !== undefined) {
w.string(1, msg.sql);
}
if (msg.sqlId !== undefined) {
w.int32(2, msg.sqlId);
}
}
function DescribeStreamReq(w, msg) {
if (msg.sql !== undefined) {
w.string(1, msg.sql);
}
if (msg.sqlId !== undefined) {
w.int32(2, msg.sqlId);
}
}
function StoreSqlStreamReq(w, msg) {
w.int32(1, msg.sqlId);
w.string(2, msg.sql);
}
function CloseSqlStreamReq(w, msg) {
w.int32(1, msg.sqlId);
}
function GetAutocommitStreamReq(_w, _msg) {
}
export function CursorReqBody(w, msg) {
if (msg.baton !== undefined) {
w.string(1, msg.baton);
}
w.message(2, msg.batch, Batch);
}

View File

@@ -0,0 +1,45 @@
/// <reference types="node" />
import type { fetch } from "@libsql/isomorphic-fetch";
import type { SqlOwner, ProtoSql } from "../sql.js";
import { Sql } from "../sql.js";
import { Stream } from "../stream.js";
import type { HttpClient } from "./client.js";
import { HttpCursor } from "./cursor.js";
import type * as proto from "./proto.js";
export declare class HttpStream extends Stream implements SqlOwner {
#private;
/** @private */
constructor(client: HttpClient, baseUrl: URL, jwt: string | undefined, customFetch: typeof fetch);
/** Get the {@link HttpClient} object that this stream belongs to. */
client(): HttpClient;
/** @private */
_sqlOwner(): SqlOwner;
/** Cache a SQL text on the server. */
storeSql(sql: string): Sql;
/** @private */
_closeSql(sqlId: number): void;
/** @private */
_execute(stmt: proto.Stmt): Promise<proto.StmtResult>;
/** @private */
_batch(batch: proto.Batch): Promise<proto.BatchResult>;
/** @private */
_describe(protoSql: ProtoSql): Promise<proto.DescribeResult>;
/** @private */
_sequence(protoSql: ProtoSql): Promise<void>;
/** Check whether the SQL connection underlying this stream is in autocommit state (i.e., outside of an
* explicit transaction). This requires protocol version 3 or higher.
*/
getAutocommit(): Promise<boolean>;
/** @private */
_openCursor(batch: proto.Batch): Promise<HttpCursor>;
/** @private */
_cursorClosed(cursor: HttpCursor): void;
/** Immediately close the stream. */
close(): void;
/** Gracefully close the stream. */
closeGracefully(): void;
/** True if the stream is closed. */
get closed(): boolean;
/** @private */
_setClosed(error: Error): void;
}

View File

@@ -0,0 +1,363 @@
import { Request, Headers } from "@libsql/isomorphic-fetch";
import { ClientError, HttpServerError, ProtocolVersionError, ProtoError, ClosedError, InternalError, } from "../errors.js";
import { readJsonObject, writeJsonObject, readProtobufMessage, writeProtobufMessage, } from "../encoding/index.js";
import { IdAlloc } from "../id_alloc.js";
import { Queue } from "../queue.js";
import { queueMicrotask } from "../queue_microtask.js";
import { errorFromProto } from "../result.js";
import { Sql } from "../sql.js";
import { Stream } from "../stream.js";
import { impossible } from "../util.js";
import { HttpCursor } from "./cursor.js";
import { PipelineReqBody as json_PipelineReqBody } from "./json_encode.js";
import { PipelineReqBody as protobuf_PipelineReqBody } from "./protobuf_encode.js";
import { CursorReqBody as json_CursorReqBody } from "./json_encode.js";
import { CursorReqBody as protobuf_CursorReqBody } from "./protobuf_encode.js";
import { PipelineRespBody as json_PipelineRespBody } from "./json_decode.js";
import { PipelineRespBody as protobuf_PipelineRespBody } from "./protobuf_decode.js";
export class HttpStream extends Stream {
#client;
#baseUrl;
#jwt;
#fetch;
#baton;
#queue;
#flushing;
#cursor;
#closing;
#closeQueued;
#closed;
#sqlIdAlloc;
/** @private */
constructor(client, baseUrl, jwt, customFetch) {
super(client.intMode);
this.#client = client;
this.#baseUrl = baseUrl.toString();
this.#jwt = jwt;
this.#fetch = customFetch;
this.#baton = undefined;
this.#queue = new Queue();
this.#flushing = false;
this.#closing = false;
this.#closeQueued = false;
this.#closed = undefined;
this.#sqlIdAlloc = new IdAlloc();
}
/** Get the {@link HttpClient} object that this stream belongs to. */
client() {
return this.#client;
}
/** @private */
_sqlOwner() {
return this;
}
/** Cache a SQL text on the server. */
storeSql(sql) {
const sqlId = this.#sqlIdAlloc.alloc();
this.#sendStreamRequest({ type: "store_sql", sqlId, sql }).then(() => undefined, (error) => this._setClosed(error));
return new Sql(this, sqlId);
}
/** @private */
_closeSql(sqlId) {
if (this.#closed !== undefined) {
return;
}
this.#sendStreamRequest({ type: "close_sql", sqlId }).then(() => this.#sqlIdAlloc.free(sqlId), (error) => this._setClosed(error));
}
/** @private */
_execute(stmt) {
return this.#sendStreamRequest({ type: "execute", stmt }).then((response) => {
return response.result;
});
}
/** @private */
_batch(batch) {
return this.#sendStreamRequest({ type: "batch", batch }).then((response) => {
return response.result;
});
}
/** @private */
_describe(protoSql) {
return this.#sendStreamRequest({
type: "describe",
sql: protoSql.sql,
sqlId: protoSql.sqlId
}).then((response) => {
return response.result;
});
}
/** @private */
_sequence(protoSql) {
return this.#sendStreamRequest({
type: "sequence",
sql: protoSql.sql,
sqlId: protoSql.sqlId,
}).then((_response) => {
return undefined;
});
}
/** Check whether the SQL connection underlying this stream is in autocommit state (i.e., outside of an
* explicit transaction). This requires protocol version 3 or higher.
*/
getAutocommit() {
this.#client._ensureVersion(3, "getAutocommit()");
return this.#sendStreamRequest({
type: "get_autocommit",
}).then((response) => {
return response.isAutocommit;
});
}
#sendStreamRequest(request) {
return new Promise((responseCallback, errorCallback) => {
this.#pushToQueue({ type: "pipeline", request, responseCallback, errorCallback });
});
}
/** @private */
_openCursor(batch) {
return new Promise((cursorCallback, errorCallback) => {
this.#pushToQueue({ type: "cursor", batch, cursorCallback, errorCallback });
});
}
/** @private */
_cursorClosed(cursor) {
if (cursor !== this.#cursor) {
throw new InternalError("Cursor was closed, but it was not associated with the stream");
}
this.#cursor = undefined;
queueMicrotask(() => this.#flushQueue());
}
/** Immediately close the stream. */
close() {
this._setClosed(new ClientError("Stream was manually closed"));
}
/** Gracefully close the stream. */
closeGracefully() {
this.#closing = true;
queueMicrotask(() => this.#flushQueue());
}
/** True if the stream is closed. */
get closed() {
return this.#closed !== undefined || this.#closing;
}
/** @private */
_setClosed(error) {
if (this.#closed !== undefined) {
return;
}
this.#closed = error;
if (this.#cursor !== undefined) {
this.#cursor._setClosed(error);
}
this.#client._streamClosed(this);
for (;;) {
const entry = this.#queue.shift();
if (entry !== undefined) {
entry.errorCallback(error);
}
else {
break;
}
}
if ((this.#baton !== undefined || this.#flushing) && !this.#closeQueued) {
this.#queue.push({
type: "pipeline",
request: { type: "close" },
responseCallback: () => undefined,
errorCallback: () => undefined,
});
this.#closeQueued = true;
queueMicrotask(() => this.#flushQueue());
}
}
#pushToQueue(entry) {
if (this.#closed !== undefined) {
throw new ClosedError("Stream is closed", this.#closed);
}
else if (this.#closing) {
throw new ClosedError("Stream is closing", undefined);
}
else {
this.#queue.push(entry);
queueMicrotask(() => this.#flushQueue());
}
}
#flushQueue() {
if (this.#flushing || this.#cursor !== undefined) {
return;
}
if (this.#closing && this.#queue.length === 0) {
this._setClosed(new ClientError("Stream was gracefully closed"));
return;
}
const endpoint = this.#client._endpoint;
if (endpoint === undefined) {
this.#client._endpointPromise.then(() => this.#flushQueue(), (error) => this._setClosed(error));
return;
}
const firstEntry = this.#queue.shift();
if (firstEntry === undefined) {
return;
}
else if (firstEntry.type === "pipeline") {
const pipeline = [firstEntry];
for (;;) {
const entry = this.#queue.first();
if (entry !== undefined && entry.type === "pipeline") {
pipeline.push(entry);
this.#queue.shift();
}
else if (entry === undefined && this.#closing && !this.#closeQueued) {
pipeline.push({
type: "pipeline",
request: { type: "close" },
responseCallback: () => undefined,
errorCallback: () => undefined,
});
this.#closeQueued = true;
break;
}
else {
break;
}
}
this.#flushPipeline(endpoint, pipeline);
}
else if (firstEntry.type === "cursor") {
this.#flushCursor(endpoint, firstEntry);
}
else {
throw impossible(firstEntry, "Impossible type of QueueEntry");
}
}
#flushPipeline(endpoint, pipeline) {
this.#flush(() => this.#createPipelineRequest(pipeline, endpoint), (resp) => decodePipelineResponse(resp, endpoint.encoding), (respBody) => respBody.baton, (respBody) => respBody.baseUrl, (respBody) => handlePipelineResponse(pipeline, respBody), (error) => pipeline.forEach((entry) => entry.errorCallback(error)));
}
#flushCursor(endpoint, entry) {
const cursor = new HttpCursor(this, endpoint.encoding);
this.#cursor = cursor;
this.#flush(() => this.#createCursorRequest(entry, endpoint), (resp) => cursor.open(resp), (respBody) => respBody.baton, (respBody) => respBody.baseUrl, (_respBody) => entry.cursorCallback(cursor), (error) => entry.errorCallback(error));
}
#flush(createRequest, decodeResponse, getBaton, getBaseUrl, handleResponse, handleError) {
let promise;
try {
const request = createRequest();
const fetch = this.#fetch;
promise = fetch(request);
}
catch (error) {
promise = Promise.reject(error);
}
this.#flushing = true;
promise.then((resp) => {
if (!resp.ok) {
return errorFromResponse(resp).then((error) => {
throw error;
});
}
return decodeResponse(resp);
}).then((r) => {
this.#baton = getBaton(r);
this.#baseUrl = getBaseUrl(r) ?? this.#baseUrl;
handleResponse(r);
}).catch((error) => {
this._setClosed(error);
handleError(error);
}).finally(() => {
this.#flushing = false;
this.#flushQueue();
});
}
#createPipelineRequest(pipeline, endpoint) {
return this.#createRequest(new URL(endpoint.pipelinePath, this.#baseUrl), {
baton: this.#baton,
requests: pipeline.map((entry) => entry.request),
}, endpoint.encoding, json_PipelineReqBody, protobuf_PipelineReqBody);
}
#createCursorRequest(entry, endpoint) {
if (endpoint.cursorPath === undefined) {
throw new ProtocolVersionError("Cursors are supported only on protocol version 3 and higher, " +
`but the HTTP server only supports version ${endpoint.version}.`);
}
return this.#createRequest(new URL(endpoint.cursorPath, this.#baseUrl), {
baton: this.#baton,
batch: entry.batch,
}, endpoint.encoding, json_CursorReqBody, protobuf_CursorReqBody);
}
#createRequest(url, reqBody, encoding, jsonFun, protobufFun) {
let bodyData;
let contentType;
if (encoding === "json") {
bodyData = writeJsonObject(reqBody, jsonFun);
contentType = "application/json";
}
else if (encoding === "protobuf") {
bodyData = writeProtobufMessage(reqBody, protobufFun);
contentType = "application/x-protobuf";
}
else {
throw impossible(encoding, "Impossible encoding");
}
const headers = new Headers();
headers.set("content-type", contentType);
if (this.#jwt !== undefined) {
headers.set("authorization", `Bearer ${this.#jwt}`);
}
return new Request(url.toString(), { method: "POST", headers, body: bodyData });
}
}
function handlePipelineResponse(pipeline, respBody) {
if (respBody.results.length !== pipeline.length) {
throw new ProtoError("Server returned unexpected number of pipeline results");
}
for (let i = 0; i < pipeline.length; ++i) {
const result = respBody.results[i];
const entry = pipeline[i];
if (result.type === "ok") {
if (result.response.type !== entry.request.type) {
throw new ProtoError("Received unexpected type of response");
}
entry.responseCallback(result.response);
}
else if (result.type === "error") {
entry.errorCallback(errorFromProto(result.error));
}
else if (result.type === "none") {
throw new ProtoError("Received unrecognized type of StreamResult");
}
else {
throw impossible(result, "Received impossible type of StreamResult");
}
}
}
async function decodePipelineResponse(resp, encoding) {
if (encoding === "json") {
const respJson = await resp.json();
return readJsonObject(respJson, json_PipelineRespBody);
}
if (encoding === "protobuf") {
const respData = await resp.arrayBuffer();
return readProtobufMessage(new Uint8Array(respData), protobuf_PipelineRespBody);
}
await resp.body?.cancel();
throw impossible(encoding, "Impossible encoding");
}
async function errorFromResponse(resp) {
const respType = resp.headers.get("content-type") ?? "text/plain";
let message = `Server returned HTTP status ${resp.status}`;
if (respType === "application/json") {
const respBody = await resp.json();
if ("message" in respBody) {
return errorFromProto(respBody);
}
return new HttpServerError(message, resp.status);
}
if (respType === "text/plain") {
const respBody = (await resp.text()).trim();
if (respBody !== "") {
message += `: ${respBody}`;
}
return new HttpServerError(message, resp.status);
}
await resp.body?.cancel();
return new HttpServerError(message, resp.status);
}

View File

@@ -0,0 +1,6 @@
export declare class IdAlloc {
#private;
constructor();
alloc(): number;
free(id: number): void;
}

47
node_modules/@libsql/hrana-client/lib-esm/id_alloc.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
import { InternalError } from "./errors.js";
// An allocator of non-negative integer ids.
//
// This clever data structure has these "ideal" properties:
// - It consumes memory proportional to the number of used ids (which is optimal).
// - All operations are O(1) time.
// - The allocated ids are small (with a slight modification, we could always provide the smallest possible
// id).
export class IdAlloc {
// Set of all allocated ids
#usedIds;
// Set of all free ids lower than `#usedIds.size`
#freeIds;
constructor() {
this.#usedIds = new Set();
this.#freeIds = new Set();
}
// Returns an id that was free, and marks it as used.
alloc() {
// this "loop" is just a way to pick an arbitrary element from the `#freeIds` set
for (const freeId of this.#freeIds) {
this.#freeIds.delete(freeId);
this.#usedIds.add(freeId);
// maintain the invariant of `#freeIds`
if (!this.#usedIds.has(this.#usedIds.size - 1)) {
this.#freeIds.add(this.#usedIds.size - 1);
}
return freeId;
}
// the `#freeIds` set is empty, so there are no free ids lower than `#usedIds.size`
// this means that `#usedIds` is a set that contains all numbers from 0 to `#usedIds.size - 1`,
// so `#usedIds.size` is free
const freeId = this.#usedIds.size;
this.#usedIds.add(freeId);
return freeId;
}
free(id) {
if (!this.#usedIds.delete(id)) {
throw new InternalError("Freeing an id that is not allocated");
}
// maintain the invariant of `#freeIds`
this.#freeIds.delete(this.#usedIds.size);
if (id < this.#usedIds.size) {
this.#freeIds.add(id);
}
}
}

34
node_modules/@libsql/hrana-client/lib-esm/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
/// <reference types="node" />
import { HttpClient } from "./http/client.js";
import { WsClient } from "./ws/client.js";
import { ProtocolVersion } from "./client.js";
export { WebSocket } from "@libsql/isomorphic-ws";
export type { RequestInit, Response } from "@libsql/isomorphic-fetch";
export { fetch, Request, Headers } from "@libsql/isomorphic-fetch";
export type { ProtocolVersion, ProtocolEncoding } from "./client.js";
export { Client } from "./client.js";
export type { DescribeResult, DescribeColumn } from "./describe.js";
export * from "./errors.js";
export { Batch, BatchStep, BatchCond } from "./batch.js";
export type { ParsedLibsqlUrl } from "./libsql_url.js";
export { parseLibsqlUrl } from "./libsql_url.js";
export type { StmtResult, RowsResult, RowResult, ValueResult, Row } from "./result.js";
export type { InSql, SqlOwner } from "./sql.js";
export { Sql } from "./sql.js";
export type { InStmt, InStmtArgs } from "./stmt.js";
export { Stmt } from "./stmt.js";
export { Stream } from "./stream.js";
export type { Value, InValue, IntMode } from "./value.js";
export { HttpClient } from "./http/client.js";
export { HttpStream } from "./http/stream.js";
export { WsClient } from "./ws/client.js";
export { WsStream } from "./ws/stream.js";
/** Open a Hrana client over WebSocket connected to the given `url`. */
export declare function openWs(url: string | URL, jwt?: string, protocolVersion?: ProtocolVersion): WsClient;
/** Open a Hrana client over HTTP connected to the given `url`.
*
* If the `customFetch` argument is passed and not `undefined`, it is used in place of the `fetch` function
* from `@libsql/isomorphic-fetch`. This function is always called with a `Request` object from
* `@libsql/isomorphic-fetch`.
*/
export declare function openHttp(url: string | URL, jwt?: string, customFetch?: unknown | undefined, protocolVersion?: ProtocolVersion): HttpClient;

42
node_modules/@libsql/hrana-client/lib-esm/index.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
import { WebSocket } from "@libsql/isomorphic-ws";
import { subprotocolsV2, subprotocolsV3 } from "./ws/client.js";
import { WebSocketUnsupportedError } from "./errors.js";
import { HttpClient } from "./http/client.js";
import { WsClient } from "./ws/client.js";
export { WebSocket } from "@libsql/isomorphic-ws";
export { fetch, Request, Headers } from "@libsql/isomorphic-fetch";
export { Client } from "./client.js";
export * from "./errors.js";
export { Batch, BatchStep, BatchCond } from "./batch.js";
export { parseLibsqlUrl } from "./libsql_url.js";
export { Sql } from "./sql.js";
export { Stmt } from "./stmt.js";
export { Stream } from "./stream.js";
export { HttpClient } from "./http/client.js";
export { HttpStream } from "./http/stream.js";
export { WsClient } from "./ws/client.js";
export { WsStream } from "./ws/stream.js";
/** Open a Hrana client over WebSocket connected to the given `url`. */
export function openWs(url, jwt, protocolVersion = 2) {
if (typeof WebSocket === "undefined") {
throw new WebSocketUnsupportedError("WebSockets are not supported in this environment");
}
var subprotocols = undefined;
if (protocolVersion == 3) {
subprotocols = Array.from(subprotocolsV3.keys());
}
else {
subprotocols = Array.from(subprotocolsV2.keys());
}
const socket = new WebSocket(url, subprotocols);
return new WsClient(socket, jwt);
}
/** Open a Hrana client over HTTP connected to the given `url`.
*
* If the `customFetch` argument is passed and not `undefined`, it is used in place of the `fetch` function
* from `@libsql/isomorphic-fetch`. This function is always called with a `Request` object from
* `@libsql/isomorphic-fetch`.
*/
export function openHttp(url, jwt, customFetch, protocolVersion = 2) {
return new HttpClient(url instanceof URL ? url : new URL(url), jwt, customFetch, protocolVersion);
}

View File

@@ -0,0 +1,15 @@
/** Result of parsing a libsql URL using {@link parseLibsqlUrl}. */
export interface ParsedLibsqlUrl {
/** A WebSocket URL that can be used with {@link openWs} to open a {@link WsClient}. It is `undefined`
* if the parsed URL specified HTTP explicitly. */
hranaWsUrl: string | undefined;
/** A HTTP URL that can be used with {@link openHttp} to open a {@link HttpClient}. It is `undefined`
* if the parsed URL specified WebSockets explicitly. */
hranaHttpUrl: string | undefined;
/** The optional `authToken` query parameter that should be passed as `jwt` to
* {@link openWs}/{@link openHttp}. */
authToken: string | undefined;
}
/** Parses a URL compatible with the libsql client (`@libsql/client`). This URL may have the "libsql:" scheme
* and may contain query parameters. */
export declare function parseLibsqlUrl(urlStr: string): ParsedLibsqlUrl;

View File

@@ -0,0 +1,75 @@
import { LibsqlUrlParseError } from "./errors.js";
;
/** Parses a URL compatible with the libsql client (`@libsql/client`). This URL may have the "libsql:" scheme
* and may contain query parameters. */
export function parseLibsqlUrl(urlStr) {
const url = new URL(urlStr);
let authToken = undefined;
let tls = undefined;
for (const [key, value] of url.searchParams.entries()) {
if (key === "authToken") {
authToken = value;
}
else if (key === "tls") {
if (value === "0") {
tls = false;
}
else if (value === "1") {
tls = true;
}
else {
throw new LibsqlUrlParseError(`Unknown value for the "tls" query argument: ${JSON.stringify(value)}`);
}
}
else {
throw new LibsqlUrlParseError(`Unknown URL query argument ${JSON.stringify(key)}`);
}
}
let hranaWsScheme;
let hranaHttpScheme;
if ((url.protocol === "http:" || url.protocol === "ws:") && (tls === true)) {
throw new LibsqlUrlParseError(`A ${JSON.stringify(url.protocol)} URL cannot opt into TLS using ?tls=1`);
}
else if ((url.protocol === "https:" || url.protocol === "wss:") && (tls === false)) {
throw new LibsqlUrlParseError(`A ${JSON.stringify(url.protocol)} URL cannot opt out of TLS using ?tls=0`);
}
if (url.protocol === "http:" || url.protocol === "https:") {
hranaHttpScheme = url.protocol;
}
else if (url.protocol === "ws:" || url.protocol === "wss:") {
hranaWsScheme = url.protocol;
}
else if (url.protocol === "libsql:") {
if (tls === false) {
if (!url.port) {
throw new LibsqlUrlParseError(`A "libsql:" URL with ?tls=0 must specify an explicit port`);
}
hranaHttpScheme = "http:";
hranaWsScheme = "ws:";
}
else {
hranaHttpScheme = "https:";
hranaWsScheme = "wss:";
}
}
else {
throw new LibsqlUrlParseError(`This client does not support ${JSON.stringify(url.protocol)} URLs. ` +
'Please use a "libsql:", "ws:", "wss:", "http:" or "https:" URL instead.');
}
if (url.username || url.password) {
throw new LibsqlUrlParseError("This client does not support HTTP Basic authentication with a username and password. " +
'You can authenticate using a token passed in the "authToken" URL query parameter.');
}
if (url.hash) {
throw new LibsqlUrlParseError("URL fragments are not supported");
}
let hranaPath = url.pathname;
if (hranaPath === "/") {
hranaPath = "";
}
const hranaWsUrl = hranaWsScheme !== undefined
? `${hranaWsScheme}//${url.host}${hranaPath}` : undefined;
const hranaHttpUrl = hranaHttpScheme !== undefined
? `${hranaHttpScheme}//${url.host}${hranaPath}` : undefined;
return { hranaWsUrl, hranaHttpUrl, authToken };
}

8
node_modules/@libsql/hrana-client/lib-esm/queue.d.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
export declare class Queue<T> {
#private;
constructor();
get length(): number;
push(elem: T): void;
shift(): T | undefined;
first(): T | undefined;
}

26
node_modules/@libsql/hrana-client/lib-esm/queue.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
export class Queue {
#pushStack;
#shiftStack;
constructor() {
this.#pushStack = [];
this.#shiftStack = [];
}
get length() {
return this.#pushStack.length + this.#shiftStack.length;
}
push(elem) {
this.#pushStack.push(elem);
}
shift() {
if (this.#shiftStack.length === 0 && this.#pushStack.length > 0) {
this.#shiftStack = this.#pushStack.reverse();
this.#pushStack = [];
}
return this.#shiftStack.pop();
}
first() {
return this.#shiftStack.length !== 0
? this.#shiftStack[this.#shiftStack.length - 1]
: this.#pushStack[0];
}
}

View File

@@ -0,0 +1,2 @@
declare let _queueMicrotask: (callback: () => void) => void;
export { _queueMicrotask as queueMicrotask };

View File

@@ -0,0 +1,13 @@
// queueMicrotask() ponyfill
// https://github.com/libsql/libsql-client-ts/issues/47
let _queueMicrotask;
if (typeof queueMicrotask !== "undefined") {
_queueMicrotask = queueMicrotask;
}
else {
const resolved = Promise.resolve();
_queueMicrotask = (callback) => {
resolved.then(callback);
};
}
export { _queueMicrotask as queueMicrotask };

43
node_modules/@libsql/hrana-client/lib-esm/result.d.ts generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import { ResponseError } from "./errors.js";
import type * as proto from "./shared/proto.js";
import type { Value, IntMode } from "./value.js";
/** Result of executing a database statement. */
export interface StmtResult {
/** Number of rows that were changed by the statement. This is meaningful only if the statement was an
* INSERT, UPDATE or DELETE, and the value is otherwise undefined. */
affectedRowCount: number;
/** The ROWID of the last successful insert into a rowid table. This is a 64-big signed integer. For other
* statements than INSERTs into a rowid table, the value is not specified. */
lastInsertRowid: bigint | undefined;
/** Names of columns in the result. */
columnNames: Array<string | undefined>;
/** Declared types of columns in the result. */
columnDecltypes: Array<string | undefined>;
}
/** An array of rows returned by a database statement. */
export interface RowsResult extends StmtResult {
/** The returned rows. */
rows: Array<Row>;
}
/** A single row returned by a database statement. */
export interface RowResult extends StmtResult {
/** The returned row. If the query produced zero rows, this is `undefined`. */
row: Row | undefined;
}
/** A single value returned by a database statement. */
export interface ValueResult extends StmtResult {
/** The returned value. If the query produced zero rows or zero columns, this is `undefined`. */
value: Value | undefined;
}
/** Row returned from the database. This is an Array-like object (it has `length` and can be indexed with a
* number), and in addition, it has enumerable properties from the named columns. */
export interface Row {
length: number;
[index: number]: Value;
[name: string]: Value;
}
export declare function stmtResultFromProto(result: proto.StmtResult): StmtResult;
export declare function rowsResultFromProto(result: proto.StmtResult, intMode: IntMode): RowsResult;
export declare function rowResultFromProto(result: proto.StmtResult, intMode: IntMode): RowResult;
export declare function valueResultFromProto(result: proto.StmtResult, intMode: IntMode): ValueResult;
export declare function errorFromProto(error: proto.Error): ResponseError;

48
node_modules/@libsql/hrana-client/lib-esm/result.js generated vendored Normal file
View File

@@ -0,0 +1,48 @@
import { ResponseError } from "./errors.js";
import { valueFromProto } from "./value.js";
export function stmtResultFromProto(result) {
return {
affectedRowCount: result.affectedRowCount,
lastInsertRowid: result.lastInsertRowid,
columnNames: result.cols.map(col => col.name),
columnDecltypes: result.cols.map(col => col.decltype),
};
}
export function rowsResultFromProto(result, intMode) {
const stmtResult = stmtResultFromProto(result);
const rows = result.rows.map(row => rowFromProto(stmtResult.columnNames, row, intMode));
return { ...stmtResult, rows };
}
export function rowResultFromProto(result, intMode) {
const stmtResult = stmtResultFromProto(result);
let row;
if (result.rows.length > 0) {
row = rowFromProto(stmtResult.columnNames, result.rows[0], intMode);
}
return { ...stmtResult, row };
}
export function valueResultFromProto(result, intMode) {
const stmtResult = stmtResultFromProto(result);
let value;
if (result.rows.length > 0 && stmtResult.columnNames.length > 0) {
value = valueFromProto(result.rows[0][0], intMode);
}
return { ...stmtResult, value };
}
function rowFromProto(colNames, values, intMode) {
const row = {};
// make sure that the "length" property is not enumerable
Object.defineProperty(row, "length", { value: values.length });
for (let i = 0; i < values.length; ++i) {
const value = valueFromProto(values[i], intMode);
Object.defineProperty(row, i, { value });
const colName = colNames[i];
if (colName !== undefined && !Object.hasOwn(row, colName)) {
Object.defineProperty(row, colName, { value, enumerable: true, configurable: true, writable: true });
}
}
return row;
}
export function errorFromProto(error) {
return new ResponseError(error.message, error);
}

View File

@@ -0,0 +1,8 @@
import * as d from "../encoding/json/decode.js";
import * as proto from "./proto.js";
export declare function Error(obj: d.Obj): proto.Error;
export declare function StmtResult(obj: d.Obj): proto.StmtResult;
export declare function BatchResult(obj: d.Obj): proto.BatchResult;
export declare function CursorEntry(obj: d.Obj): proto.CursorEntry;
export declare function DescribeResult(obj: d.Obj): proto.DescribeResult;
export declare function Value(obj: d.Obj): proto.Value;

View File

@@ -0,0 +1,106 @@
import { Base64 } from "js-base64";
import { ProtoError } from "../errors.js";
import * as d from "../encoding/json/decode.js";
export function Error(obj) {
const message = d.string(obj["message"]);
const code = d.stringOpt(obj["code"]);
return { message, code };
}
export function StmtResult(obj) {
const cols = d.arrayObjectsMap(obj["cols"], Col);
const rows = d.array(obj["rows"]).map((rowObj) => d.arrayObjectsMap(rowObj, Value));
const affectedRowCount = d.number(obj["affected_row_count"]);
const lastInsertRowidStr = d.stringOpt(obj["last_insert_rowid"]);
const lastInsertRowid = lastInsertRowidStr !== undefined
? BigInt(lastInsertRowidStr) : undefined;
return { cols, rows, affectedRowCount, lastInsertRowid };
}
function Col(obj) {
const name = d.stringOpt(obj["name"]);
const decltype = d.stringOpt(obj["decltype"]);
return { name, decltype };
}
export function BatchResult(obj) {
const stepResults = new Map();
d.array(obj["step_results"]).forEach((value, i) => {
if (value !== null) {
stepResults.set(i, StmtResult(d.object(value)));
}
});
const stepErrors = new Map();
d.array(obj["step_errors"]).forEach((value, i) => {
if (value !== null) {
stepErrors.set(i, Error(d.object(value)));
}
});
return { stepResults, stepErrors };
}
export function CursorEntry(obj) {
const type = d.string(obj["type"]);
if (type === "step_begin") {
const step = d.number(obj["step"]);
const cols = d.arrayObjectsMap(obj["cols"], Col);
return { type: "step_begin", step, cols };
}
else if (type === "step_end") {
const affectedRowCount = d.number(obj["affected_row_count"]);
const lastInsertRowidStr = d.stringOpt(obj["last_insert_rowid"]);
const lastInsertRowid = lastInsertRowidStr !== undefined
? BigInt(lastInsertRowidStr) : undefined;
return { type: "step_end", affectedRowCount, lastInsertRowid };
}
else if (type === "step_error") {
const step = d.number(obj["step"]);
const error = Error(d.object(obj["error"]));
return { type: "step_error", step, error };
}
else if (type === "row") {
const row = d.arrayObjectsMap(obj["row"], Value);
return { type: "row", row };
}
else if (type === "error") {
const error = Error(d.object(obj["error"]));
return { type: "error", error };
}
else {
throw new ProtoError("Unexpected type of CursorEntry");
}
}
export function DescribeResult(obj) {
const params = d.arrayObjectsMap(obj["params"], DescribeParam);
const cols = d.arrayObjectsMap(obj["cols"], DescribeCol);
const isExplain = d.boolean(obj["is_explain"]);
const isReadonly = d.boolean(obj["is_readonly"]);
return { params, cols, isExplain, isReadonly };
}
function DescribeParam(obj) {
const name = d.stringOpt(obj["name"]);
return { name };
}
function DescribeCol(obj) {
const name = d.string(obj["name"]);
const decltype = d.stringOpt(obj["decltype"]);
return { name, decltype };
}
export function Value(obj) {
const type = d.string(obj["type"]);
if (type === "null") {
return null;
}
else if (type === "integer") {
const value = d.string(obj["value"]);
return BigInt(value);
}
else if (type === "float") {
return d.number(obj["value"]);
}
else if (type === "text") {
return d.string(obj["value"]);
}
else if (type === "blob") {
return Base64.toUint8Array(d.string(obj["base64"]));
}
else {
throw new ProtoError("Unexpected type of Value");
}
}

View File

@@ -0,0 +1,4 @@
import * as e from "../encoding/json/encode.js";
import * as proto from "./proto.js";
export declare function Stmt(w: e.ObjectWriter, msg: proto.Stmt): void;
export declare function Batch(w: e.ObjectWriter, msg: proto.Batch): void;

View File

@@ -0,0 +1,71 @@
import { Base64 } from "js-base64";
import { impossible } from "../util.js";
export function Stmt(w, msg) {
if (msg.sql !== undefined) {
w.string("sql", msg.sql);
}
if (msg.sqlId !== undefined) {
w.number("sql_id", msg.sqlId);
}
w.arrayObjects("args", msg.args, Value);
w.arrayObjects("named_args", msg.namedArgs, NamedArg);
w.boolean("want_rows", msg.wantRows);
}
function NamedArg(w, msg) {
w.string("name", msg.name);
w.object("value", msg.value, Value);
}
export function Batch(w, msg) {
w.arrayObjects("steps", msg.steps, BatchStep);
}
function BatchStep(w, msg) {
if (msg.condition !== undefined) {
w.object("condition", msg.condition, BatchCond);
}
w.object("stmt", msg.stmt, Stmt);
}
function BatchCond(w, msg) {
w.stringRaw("type", msg.type);
if (msg.type === "ok" || msg.type === "error") {
w.number("step", msg.step);
}
else if (msg.type === "not") {
w.object("cond", msg.cond, BatchCond);
}
else if (msg.type === "and" || msg.type === "or") {
w.arrayObjects("conds", msg.conds, BatchCond);
}
else if (msg.type === "is_autocommit") {
// do nothing
}
else {
throw impossible(msg, "Impossible type of BatchCond");
}
}
function Value(w, msg) {
if (msg === null) {
w.stringRaw("type", "null");
}
else if (typeof msg === "bigint") {
w.stringRaw("type", "integer");
w.stringRaw("value", "" + msg);
}
else if (typeof msg === "number") {
w.stringRaw("type", "float");
w.number("value", msg);
}
else if (typeof msg === "string") {
w.stringRaw("type", "text");
w.string("value", msg);
}
else if (msg instanceof Uint8Array) {
w.stringRaw("type", "blob");
w.stringRaw("base64", Base64.fromUint8Array(msg));
}
else if (msg === undefined) {
// do nothing
}
else {
throw impossible(msg, "Impossible type of Value");
}
}

View File

@@ -0,0 +1,96 @@
export type int32 = number;
export type uint32 = number;
export type Error = {
message: string;
code: string | undefined;
};
export type Stmt = {
sql: string | undefined;
sqlId: int32 | undefined;
args: Array<Value>;
namedArgs: Array<NamedArg>;
wantRows: boolean;
};
export type NamedArg = {
name: string;
value: Value;
};
export type StmtResult = {
cols: Array<Col>;
rows: Array<Array<Value>>;
affectedRowCount: number;
lastInsertRowid: bigint | undefined;
};
export type Col = {
name: string | undefined;
decltype: string | undefined;
};
export type Batch = {
steps: Array<BatchStep>;
};
export type BatchStep = {
condition: BatchCond | undefined;
stmt: Stmt;
};
export type BatchCond = {
type: "ok";
step: uint32;
} | {
type: "error";
step: uint32;
} | {
type: "not";
cond: BatchCond;
} | {
type: "and";
conds: Array<BatchCond>;
} | {
type: "or";
conds: Array<BatchCond>;
} | {
type: "is_autocommit";
};
export type BatchResult = {
stepResults: Map<uint32, StmtResult>;
stepErrors: Map<uint32, Error>;
};
export type CursorEntry = {
type: "none";
} | StepBeginEntry | StepEndEntry | StepErrorEntry | RowEntry | ErrorEntry;
export type StepBeginEntry = {
type: "step_begin";
step: uint32;
cols: Array<Col>;
};
export type StepEndEntry = {
type: "step_end";
affectedRowCount: number;
lastInsertRowid: bigint | undefined;
};
export type StepErrorEntry = {
type: "step_error";
step: uint32;
error: Error;
};
export type RowEntry = {
type: "row";
row: Array<Value>;
};
export type ErrorEntry = {
type: "error";
error: Error;
};
export type DescribeResult = {
params: Array<DescribeParam>;
cols: Array<DescribeCol>;
isExplain: boolean;
isReadonly: boolean;
};
export type DescribeParam = {
name: string | undefined;
};
export type DescribeCol = {
name: string;
decltype: string | undefined;
};
export type Value = undefined | null | bigint | number | string | Uint8Array;

View File

@@ -0,0 +1,2 @@
// Types for the protocol structures that are shared for WebSocket and HTTP
export {};

View File

@@ -0,0 +1,7 @@
import * as d from "../encoding/protobuf/decode.js";
import * as proto from "./proto.js";
export declare const Error: d.MessageDef<proto.Error>;
export declare const StmtResult: d.MessageDef<proto.StmtResult>;
export declare const BatchResult: d.MessageDef<proto.BatchResult>;
export declare const CursorEntry: d.MessageDef<proto.CursorEntry>;
export declare const DescribeResult: d.MessageDef<proto.DescribeResult>;

View File

@@ -0,0 +1,115 @@
export const Error = {
default() { return { message: "", code: undefined }; },
1(r, msg) { msg.message = r.string(); },
2(r, msg) { msg.code = r.string(); },
};
export const StmtResult = {
default() {
return {
cols: [],
rows: [],
affectedRowCount: 0,
lastInsertRowid: undefined,
};
},
1(r, msg) { msg.cols.push(r.message(Col)); },
2(r, msg) { msg.rows.push(r.message(Row)); },
3(r, msg) { msg.affectedRowCount = Number(r.uint64()); },
4(r, msg) { msg.lastInsertRowid = r.sint64(); },
};
const Col = {
default() { return { name: undefined, decltype: undefined }; },
1(r, msg) { msg.name = r.string(); },
2(r, msg) { msg.decltype = r.string(); },
};
const Row = {
default() { return []; },
1(r, msg) { msg.push(r.message(Value)); },
};
export const BatchResult = {
default() { return { stepResults: new Map(), stepErrors: new Map() }; },
1(r, msg) {
const [key, value] = r.message(BatchResultStepResult);
msg.stepResults.set(key, value);
},
2(r, msg) {
const [key, value] = r.message(BatchResultStepError);
msg.stepErrors.set(key, value);
},
};
const BatchResultStepResult = {
default() { return [0, StmtResult.default()]; },
1(r, msg) { msg[0] = r.uint32(); },
2(r, msg) { msg[1] = r.message(StmtResult); },
};
const BatchResultStepError = {
default() { return [0, Error.default()]; },
1(r, msg) { msg[0] = r.uint32(); },
2(r, msg) { msg[1] = r.message(Error); },
};
export const CursorEntry = {
default() { return { type: "none" }; },
1(r) { return r.message(StepBeginEntry); },
2(r) { return r.message(StepEndEntry); },
3(r) { return r.message(StepErrorEntry); },
4(r) { return { type: "row", row: r.message(Row) }; },
5(r) { return { type: "error", error: r.message(Error) }; },
};
const StepBeginEntry = {
default() { return { type: "step_begin", step: 0, cols: [] }; },
1(r, msg) { msg.step = r.uint32(); },
2(r, msg) { msg.cols.push(r.message(Col)); },
};
const StepEndEntry = {
default() {
return {
type: "step_end",
affectedRowCount: 0,
lastInsertRowid: undefined,
};
},
1(r, msg) { msg.affectedRowCount = r.uint32(); },
2(r, msg) { msg.lastInsertRowid = r.uint64(); },
};
const StepErrorEntry = {
default() {
return {
type: "step_error",
step: 0,
error: Error.default(),
};
},
1(r, msg) { msg.step = r.uint32(); },
2(r, msg) { msg.error = r.message(Error); },
};
export const DescribeResult = {
default() {
return {
params: [],
cols: [],
isExplain: false,
isReadonly: false,
};
},
1(r, msg) { msg.params.push(r.message(DescribeParam)); },
2(r, msg) { msg.cols.push(r.message(DescribeCol)); },
3(r, msg) { msg.isExplain = r.bool(); },
4(r, msg) { msg.isReadonly = r.bool(); },
};
const DescribeParam = {
default() { return { name: undefined }; },
1(r, msg) { msg.name = r.string(); },
};
const DescribeCol = {
default() { return { name: "", decltype: undefined }; },
1(r, msg) { msg.name = r.string(); },
2(r, msg) { msg.decltype = r.string(); },
};
const Value = {
default() { return undefined; },
1(r) { return null; },
2(r) { return r.sint64(); },
3(r) { return r.double(); },
4(r) { return r.string(); },
5(r) { return r.bytes(); },
};

View File

@@ -0,0 +1,4 @@
import * as e from "../encoding/protobuf/encode.js";
import * as proto from "./proto.js";
export declare function Stmt(w: e.MessageWriter, msg: proto.Stmt): void;
export declare function Batch(w: e.MessageWriter, msg: proto.Batch): void;

View File

@@ -0,0 +1,85 @@
import { impossible } from "../util.js";
export function Stmt(w, msg) {
if (msg.sql !== undefined) {
w.string(1, msg.sql);
}
if (msg.sqlId !== undefined) {
w.int32(2, msg.sqlId);
}
for (const arg of msg.args) {
w.message(3, arg, Value);
}
for (const arg of msg.namedArgs) {
w.message(4, arg, NamedArg);
}
w.bool(5, msg.wantRows);
}
function NamedArg(w, msg) {
w.string(1, msg.name);
w.message(2, msg.value, Value);
}
export function Batch(w, msg) {
for (const step of msg.steps) {
w.message(1, step, BatchStep);
}
}
function BatchStep(w, msg) {
if (msg.condition !== undefined) {
w.message(1, msg.condition, BatchCond);
}
w.message(2, msg.stmt, Stmt);
}
function BatchCond(w, msg) {
if (msg.type === "ok") {
w.uint32(1, msg.step);
}
else if (msg.type === "error") {
w.uint32(2, msg.step);
}
else if (msg.type === "not") {
w.message(3, msg.cond, BatchCond);
}
else if (msg.type === "and") {
w.message(4, msg.conds, BatchCondList);
}
else if (msg.type === "or") {
w.message(5, msg.conds, BatchCondList);
}
else if (msg.type === "is_autocommit") {
w.message(6, undefined, Empty);
}
else {
throw impossible(msg, "Impossible type of BatchCond");
}
}
function BatchCondList(w, msg) {
for (const cond of msg) {
w.message(1, cond, BatchCond);
}
}
function Value(w, msg) {
if (msg === null) {
w.message(1, undefined, Empty);
}
else if (typeof msg === "bigint") {
w.sint64(2, msg);
}
else if (typeof msg === "number") {
w.double(3, msg);
}
else if (typeof msg === "string") {
w.string(4, msg);
}
else if (msg instanceof Uint8Array) {
w.bytes(5, msg);
}
else if (msg === undefined) {
// do nothing
}
else {
throw impossible(msg, "Impossible type of Value");
}
}
function Empty(_w, _msg) {
// do nothing
}

28
node_modules/@libsql/hrana-client/lib-esm/sql.d.ts generated vendored Normal file
View File

@@ -0,0 +1,28 @@
/** A SQL text that you can send to the database. Either a string or a reference to SQL text that is cached on
* the server. */
export type InSql = string | Sql;
export interface SqlOwner {
/** Cache a SQL text on the server. This requires protocol version 2 or higher. */
storeSql(sql: string): Sql;
/** @private */
_closeSql(sqlId: number): void;
}
/** Text of an SQL statement cached on the server. */
export declare class Sql {
#private;
/** @private */
constructor(owner: SqlOwner, sqlId: number);
/** @private */
_getSqlId(owner: SqlOwner): number;
/** Remove the SQL text from the server, releasing resouces. */
close(): void;
/** @private */
_setClosed(error: Error): void;
/** True if the SQL text is closed (removed from the server). */
get closed(): boolean;
}
export type ProtoSql = {
sql?: string;
sqlId?: number;
};
export declare function sqlToProto(owner: SqlOwner, sql: InSql): ProtoSql;

46
node_modules/@libsql/hrana-client/lib-esm/sql.js generated vendored Normal file
View File

@@ -0,0 +1,46 @@
import { ClientError, ClosedError, MisuseError } from "./errors.js";
/** Text of an SQL statement cached on the server. */
export class Sql {
#owner;
#sqlId;
#closed;
/** @private */
constructor(owner, sqlId) {
this.#owner = owner;
this.#sqlId = sqlId;
this.#closed = undefined;
}
/** @private */
_getSqlId(owner) {
if (this.#owner !== owner) {
throw new MisuseError("Attempted to use SQL text opened with other object");
}
else if (this.#closed !== undefined) {
throw new ClosedError("SQL text is closed", this.#closed);
}
return this.#sqlId;
}
/** Remove the SQL text from the server, releasing resouces. */
close() {
this._setClosed(new ClientError("SQL text was manually closed"));
}
/** @private */
_setClosed(error) {
if (this.#closed === undefined) {
this.#closed = error;
this.#owner._closeSql(this.#sqlId);
}
}
/** True if the SQL text is closed (removed from the server). */
get closed() {
return this.#closed !== undefined;
}
}
export function sqlToProto(owner, sql) {
if (sql instanceof Sql) {
return { sqlId: sql._getSqlId(owner) };
}
else {
return { sql: "" + sql };
}
}

32
node_modules/@libsql/hrana-client/lib-esm/stmt.d.ts generated vendored Normal file
View File

@@ -0,0 +1,32 @@
import type * as proto from "./shared/proto.js";
import type { InSql, SqlOwner } from "./sql.js";
import type { InValue } from "./value.js";
/** A statement that you can send to the database. Statements are represented by the {@link Stmt} class, but
* as a shorthand, you can specify an SQL text without arguments, or a tuple with the SQL text and positional
* or named arguments.
*/
export type InStmt = Stmt | InSql | [InSql, InStmtArgs];
/** Arguments for a statement. Either an array that is bound to parameters by position, or an object with
* values that are bound to parameters by name. */
export type InStmtArgs = Array<InValue> | Record<string, InValue>;
/** A statement that can be evaluated by the database. Besides the SQL text, it also contains the positional
* and named arguments. */
export declare class Stmt {
/** The SQL statement text. */
sql: InSql;
/** @private */
_args: Array<proto.Value>;
/** @private */
_namedArgs: Map<string, proto.Value>;
/** Initialize the statement with given SQL text. */
constructor(sql: InSql);
/** Binds positional parameters from the given `values`. All previous positional bindings are cleared. */
bindIndexes(values: Iterable<InValue>): this;
/** Binds a parameter by a 1-based index. */
bindIndex(index: number, value: InValue): this;
/** Binds a parameter by name. */
bindName(name: string, value: InValue): this;
/** Clears all bindings. */
unbindAll(): this;
}
export declare function stmtToProto(sqlOwner: SqlOwner, stmt: InStmt, wantRows: boolean): proto.Stmt;

76
node_modules/@libsql/hrana-client/lib-esm/stmt.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
import { sqlToProto } from "./sql.js";
import { valueToProto } from "./value.js";
/** A statement that can be evaluated by the database. Besides the SQL text, it also contains the positional
* and named arguments. */
export class Stmt {
/** The SQL statement text. */
sql;
/** @private */
_args;
/** @private */
_namedArgs;
/** Initialize the statement with given SQL text. */
constructor(sql) {
this.sql = sql;
this._args = [];
this._namedArgs = new Map();
}
/** Binds positional parameters from the given `values`. All previous positional bindings are cleared. */
bindIndexes(values) {
this._args.length = 0;
for (const value of values) {
this._args.push(valueToProto(value));
}
return this;
}
/** Binds a parameter by a 1-based index. */
bindIndex(index, value) {
if (index !== (index | 0) || index <= 0) {
throw new RangeError("Index of a positional argument must be positive integer");
}
while (this._args.length < index) {
this._args.push(null);
}
this._args[index - 1] = valueToProto(value);
return this;
}
/** Binds a parameter by name. */
bindName(name, value) {
this._namedArgs.set(name, valueToProto(value));
return this;
}
/** Clears all bindings. */
unbindAll() {
this._args.length = 0;
this._namedArgs.clear();
return this;
}
}
export function stmtToProto(sqlOwner, stmt, wantRows) {
let inSql;
let args = [];
let namedArgs = [];
if (stmt instanceof Stmt) {
inSql = stmt.sql;
args = stmt._args;
for (const [name, value] of stmt._namedArgs.entries()) {
namedArgs.push({ name, value });
}
}
else if (Array.isArray(stmt)) {
inSql = stmt[0];
if (Array.isArray(stmt[1])) {
args = stmt[1].map((arg) => valueToProto(arg));
}
else {
namedArgs = Object.entries(stmt[1]).map(([name, value]) => {
return { name, value: valueToProto(value) };
});
}
}
else {
inSql = stmt;
}
const { sql, sqlId } = sqlToProto(sqlOwner, inSql);
return { sql, sqlId, args, namedArgs, wantRows };
}

75
node_modules/@libsql/hrana-client/lib-esm/stream.d.ts generated vendored Normal file
View File

@@ -0,0 +1,75 @@
import { Batch } from "./batch.js";
import type { Client } from "./client.js";
import type { Cursor } from "./cursor.js";
import type { DescribeResult } from "./describe.js";
import type { RowsResult, RowResult, ValueResult, StmtResult } from "./result.js";
import type * as proto from "./shared/proto.js";
import type { InSql, SqlOwner, ProtoSql } from "./sql.js";
import type { InStmt } from "./stmt.js";
import type { IntMode } from "./value.js";
/** A stream for executing SQL statements (a "database connection"). */
export declare abstract class Stream {
#private;
/** @private */
constructor(intMode: IntMode);
/** Get the client object that this stream belongs to. */
abstract client(): Client;
/** @private */
abstract _sqlOwner(): SqlOwner;
/** @private */
abstract _execute(stmt: proto.Stmt): Promise<proto.StmtResult>;
/** @private */
abstract _batch(batch: proto.Batch): Promise<proto.BatchResult>;
/** @private */
abstract _describe(protoSql: ProtoSql): Promise<proto.DescribeResult>;
/** @private */
abstract _sequence(protoSql: ProtoSql): Promise<void>;
/** @private */
abstract _openCursor(batch: proto.Batch): Promise<Cursor>;
/** Execute a statement and return rows. */
query(stmt: InStmt): Promise<RowsResult>;
/** Execute a statement and return at most a single row. */
queryRow(stmt: InStmt): Promise<RowResult>;
/** Execute a statement and return at most a single value. */
queryValue(stmt: InStmt): Promise<ValueResult>;
/** Execute a statement without returning rows. */
run(stmt: InStmt): Promise<StmtResult>;
/** Return a builder for creating and executing a batch.
*
* If `useCursor` is true, the batch will be executed using a Hrana cursor, which will stream results from
* the server to the client, which consumes less memory on the server. This requires protocol version 3 or
* higher.
*/
batch(useCursor?: boolean): Batch;
/** Parse and analyze a statement. This requires protocol version 2 or higher. */
describe(inSql: InSql): Promise<DescribeResult>;
/** Execute a sequence of statements separated by semicolons. This requires protocol version 2 or higher.
* */
sequence(inSql: InSql): Promise<void>;
/** Check whether the SQL connection underlying this stream is in autocommit state (i.e., outside of an
* explicit transaction). This requires protocol version 3 or higher.
*/
abstract getAutocommit(): Promise<boolean>;
/** Immediately close the stream.
*
* This closes the stream immediately, aborting any pending operations.
*/
abstract close(): void;
/** Gracefully close the stream.
*
* After calling this method, you will not be able to start new operations, but existing operations will
* complete.
*/
abstract closeGracefully(): void;
/** True if the stream is closed or closing.
*
* If you call {@link closeGracefully}, this will become true immediately, even if the underlying stream
* is not physically closed yet.
*/
abstract get closed(): boolean;
/** Representation of integers returned from the database. See {@link IntMode}.
*
* This value affects the results of all operations on this stream.
*/
intMode: IntMode;
}

57
node_modules/@libsql/hrana-client/lib-esm/stream.js generated vendored Normal file
View File

@@ -0,0 +1,57 @@
import { Batch } from "./batch.js";
import { describeResultFromProto } from "./describe.js";
import { stmtResultFromProto, rowsResultFromProto, rowResultFromProto, valueResultFromProto, } from "./result.js";
import { sqlToProto } from "./sql.js";
import { stmtToProto } from "./stmt.js";
/** A stream for executing SQL statements (a "database connection"). */
export class Stream {
/** @private */
constructor(intMode) {
this.intMode = intMode;
}
/** Execute a statement and return rows. */
query(stmt) {
return this.#execute(stmt, true, rowsResultFromProto);
}
/** Execute a statement and return at most a single row. */
queryRow(stmt) {
return this.#execute(stmt, true, rowResultFromProto);
}
/** Execute a statement and return at most a single value. */
queryValue(stmt) {
return this.#execute(stmt, true, valueResultFromProto);
}
/** Execute a statement without returning rows. */
run(stmt) {
return this.#execute(stmt, false, stmtResultFromProto);
}
#execute(inStmt, wantRows, fromProto) {
const stmt = stmtToProto(this._sqlOwner(), inStmt, wantRows);
return this._execute(stmt).then((r) => fromProto(r, this.intMode));
}
/** Return a builder for creating and executing a batch.
*
* If `useCursor` is true, the batch will be executed using a Hrana cursor, which will stream results from
* the server to the client, which consumes less memory on the server. This requires protocol version 3 or
* higher.
*/
batch(useCursor = false) {
return new Batch(this, useCursor);
}
/** Parse and analyze a statement. This requires protocol version 2 or higher. */
describe(inSql) {
const protoSql = sqlToProto(this._sqlOwner(), inSql);
return this._describe(protoSql).then(describeResultFromProto);
}
/** Execute a sequence of statements separated by semicolons. This requires protocol version 2 or higher.
* */
sequence(inSql) {
const protoSql = sqlToProto(this._sqlOwner(), inSql);
return this._sequence(protoSql);
}
/** Representation of integers returned from the database. See {@link IntMode}.
*
* This value affects the results of all operations on this stream.
*/
intMode;
}

1
node_modules/@libsql/hrana-client/lib-esm/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export declare function impossible(value: never, message: string): Error;

4
node_modules/@libsql/hrana-client/lib-esm/util.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import { InternalError } from "./errors.js";
export function impossible(value, message) {
throw new InternalError(message);
}

17
node_modules/@libsql/hrana-client/lib-esm/value.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import type * as proto from "./shared/proto.js";
/** JavaScript values that you can receive from the database in a statement result. */
export type Value = null | string | number | bigint | ArrayBuffer;
/** JavaScript values that you can send to the database as an argument. */
export type InValue = Value | boolean | Uint8Array | Date | RegExp | object;
/** Possible representations of SQLite integers in JavaScript:
*
* - `"number"` (default): returns SQLite integers as JavaScript `number`-s (double precision floats).
* `number` cannot precisely represent integers larger than 2^53-1 in absolute value, so attempting to read
* larger integers will throw a `RangeError`.
* - `"bigint"`: returns SQLite integers as JavaScript `bigint`-s (arbitrary precision integers). Bigints can
* precisely represent all SQLite integers.
* - `"string"`: returns SQLite integers as strings.
*/
export type IntMode = "number" | "bigint" | "string";
export declare function valueToProto(value: InValue): proto.Value;
export declare function valueFromProto(value: proto.Value, intMode: IntMode): Value;

83
node_modules/@libsql/hrana-client/lib-esm/value.js generated vendored Normal file
View File

@@ -0,0 +1,83 @@
import { ProtoError, MisuseError } from "./errors.js";
import { impossible } from "./util.js";
export function valueToProto(value) {
if (value === null) {
return null;
}
else if (typeof value === "string") {
return value;
}
else 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("This bigint value is too large to be represented as a 64-bit integer and passed as argument");
}
return value;
}
else if (typeof value === "boolean") {
return value ? 1n : 0n;
}
else if (value instanceof ArrayBuffer) {
return new Uint8Array(value);
}
else if (value instanceof Uint8Array) {
return value;
}
else if (value instanceof Date) {
return +value.valueOf();
}
else if (typeof value === "object") {
return "" + value.toString();
}
else {
throw new TypeError("Unsupported type of value");
}
}
const minInteger = -9223372036854775808n;
const maxInteger = 9223372036854775807n;
export function valueFromProto(value, intMode) {
if (value === null) {
return null;
}
else if (typeof value === "number") {
return value;
}
else if (typeof value === "string") {
return value;
}
else if (typeof value === "bigint") {
if (intMode === "number") {
const num = Number(value);
if (!Number.isSafeInteger(num)) {
throw new RangeError("Received integer which is too large to be safely represented as a JavaScript number");
}
return num;
}
else if (intMode === "bigint") {
return value;
}
else if (intMode === "string") {
return "" + value;
}
else {
throw new MisuseError("Invalid value for IntMode");
}
}
else if (value instanceof Uint8Array) {
// TODO: we need to copy data from `Uint8Array` to return an `ArrayBuffer`. Perhaps we should add a
// `blobMode` parameter, similar to `intMode`, which would allow the user to choose between receiving
// `ArrayBuffer` (default, convenient) and `Uint8Array` (zero copy)?
return value.slice().buffer;
}
else if (value === undefined) {
throw new ProtoError("Received unrecognized type of Value");
}
else {
throw impossible(value, "Impossible type of Value");
}
}

View File

@@ -0,0 +1,48 @@
/// <reference types="ws" />
import { WebSocket } from "@libsql/isomorphic-ws";
import type { ProtocolVersion, ProtocolEncoding } from "../client.js";
import { Client } from "../client.js";
import { IdAlloc } from "../id_alloc.js";
import { Sql, SqlOwner } from "../sql.js";
import type * as proto from "./proto.js";
import { WsStream } from "./stream.js";
export type Subprotocol = {
version: ProtocolVersion;
encoding: ProtocolEncoding;
};
export declare const subprotocolsV2: Map<string, Subprotocol>;
export declare const subprotocolsV3: Map<string, Subprotocol>;
/** A client for the Hrana protocol over a WebSocket. */
export declare class WsClient extends Client implements SqlOwner {
#private;
/** @private */
_streamIdAlloc: IdAlloc;
/** @private */
_cursorIdAlloc: IdAlloc;
/** @private */
constructor(socket: WebSocket, jwt: string | undefined);
/** Get the protocol version negotiated with the server, possibly waiting until the socket is open. */
getVersion(): Promise<ProtocolVersion>;
/** @private */
_ensureVersion(minVersion: ProtocolVersion, feature: string): void;
/** @private */
_sendRequest(request: proto.Request, callbacks: ResponseCallbacks): void;
/** Open a {@link WsStream}, a stream for executing SQL statements. */
openStream(): WsStream;
/** Cache a SQL text on the server. This requires protocol version 2 or higher. */
storeSql(sql: string): Sql;
/** @private */
_closeSql(sqlId: number): void;
/** Close the client and the WebSocket. */
close(): void;
/** True if the client is closed. */
get closed(): boolean;
}
export interface OpenCallbacks {
openCallback: () => void;
errorCallback: (_: Error) => void;
}
export interface ResponseCallbacks {
responseCallback: (_: proto.Response) => void;
errorCallback: (_: Error) => void;
}

318
node_modules/@libsql/hrana-client/lib-esm/ws/client.js generated vendored Normal file
View File

@@ -0,0 +1,318 @@
import { Client } from "../client.js";
import { readJsonObject, writeJsonObject, readProtobufMessage, writeProtobufMessage, } from "../encoding/index.js";
import { ClientError, ProtoError, ClosedError, WebSocketError, ProtocolVersionError, InternalError, } from "../errors.js";
import { IdAlloc } from "../id_alloc.js";
import { errorFromProto } from "../result.js";
import { Sql } from "../sql.js";
import { impossible } from "../util.js";
import { WsStream } from "./stream.js";
import { ClientMsg as json_ClientMsg } from "./json_encode.js";
import { ClientMsg as protobuf_ClientMsg } from "./protobuf_encode.js";
import { ServerMsg as json_ServerMsg } from "./json_decode.js";
import { ServerMsg as protobuf_ServerMsg } from "./protobuf_decode.js";
export const subprotocolsV2 = new Map([
["hrana2", { version: 2, encoding: "json" }],
["hrana1", { version: 1, encoding: "json" }],
]);
export const subprotocolsV3 = new Map([
["hrana3-protobuf", { version: 3, encoding: "protobuf" }],
["hrana3", { version: 3, encoding: "json" }],
["hrana2", { version: 2, encoding: "json" }],
["hrana1", { version: 1, encoding: "json" }],
]);
/** A client for the Hrana protocol over a WebSocket. */
export class WsClient extends Client {
#socket;
// List of callbacks that we queue until the socket transitions from the CONNECTING to the OPEN state.
#openCallbacks;
// Have we already transitioned from CONNECTING to OPEN and fired the callbacks in #openCallbacks?
#opened;
// Stores the error that caused us to close the client (and the socket). If we are not closed, this is
// `undefined`.
#closed;
// Have we received a response to our "hello" from the server?
#recvdHello;
// Subprotocol negotiated with the server. It is only available after the socket transitions to the OPEN
// state.
#subprotocol;
// Has the `getVersion()` function been called? This is only used to validate that the API is used
// correctly.
#getVersionCalled;
// A map from request id to the responses that we expect to receive from the server.
#responseMap;
// An allocator of request ids.
#requestIdAlloc;
// An allocator of stream ids.
/** @private */
_streamIdAlloc;
// An allocator of cursor ids.
/** @private */
_cursorIdAlloc;
// An allocator of SQL text ids.
#sqlIdAlloc;
/** @private */
constructor(socket, jwt) {
super();
this.#socket = socket;
this.#openCallbacks = [];
this.#opened = false;
this.#closed = undefined;
this.#recvdHello = false;
this.#subprotocol = undefined;
this.#getVersionCalled = false;
this.#responseMap = new Map();
this.#requestIdAlloc = new IdAlloc();
this._streamIdAlloc = new IdAlloc();
this._cursorIdAlloc = new IdAlloc();
this.#sqlIdAlloc = new IdAlloc();
this.#socket.binaryType = "arraybuffer";
this.#socket.addEventListener("open", () => this.#onSocketOpen());
this.#socket.addEventListener("close", (event) => this.#onSocketClose(event));
this.#socket.addEventListener("error", (event) => this.#onSocketError(event));
this.#socket.addEventListener("message", (event) => this.#onSocketMessage(event));
this.#send({ type: "hello", jwt });
}
// Send (or enqueue to send) a message to the server.
#send(msg) {
if (this.#closed !== undefined) {
throw new InternalError("Trying to send a message on a closed client");
}
if (this.#opened) {
this.#sendToSocket(msg);
}
else {
const openCallback = () => this.#sendToSocket(msg);
const errorCallback = () => undefined;
this.#openCallbacks.push({ openCallback, errorCallback });
}
}
// The socket transitioned from CONNECTING to OPEN
#onSocketOpen() {
const protocol = this.#socket.protocol;
if (protocol === undefined) {
this.#setClosed(new ClientError("The `WebSocket.protocol` property is undefined. This most likely means that the WebSocket " +
"implementation provided by the environment is broken. If you are using Miniflare 2, " +
"please update to Miniflare 3, which fixes this problem."));
return;
}
else if (protocol === "") {
this.#subprotocol = { version: 1, encoding: "json" };
}
else {
this.#subprotocol = subprotocolsV3.get(protocol);
if (this.#subprotocol === undefined) {
this.#setClosed(new ProtoError(`Unrecognized WebSocket subprotocol: ${JSON.stringify(protocol)}`));
return;
}
}
for (const callbacks of this.#openCallbacks) {
callbacks.openCallback();
}
this.#openCallbacks.length = 0;
this.#opened = true;
}
#sendToSocket(msg) {
const encoding = this.#subprotocol.encoding;
if (encoding === "json") {
const jsonMsg = writeJsonObject(msg, json_ClientMsg);
this.#socket.send(jsonMsg);
}
else if (encoding === "protobuf") {
const protobufMsg = writeProtobufMessage(msg, protobuf_ClientMsg);
this.#socket.send(protobufMsg);
}
else {
throw impossible(encoding, "Impossible encoding");
}
}
/** Get the protocol version negotiated with the server, possibly waiting until the socket is open. */
getVersion() {
return new Promise((versionCallback, errorCallback) => {
this.#getVersionCalled = true;
if (this.#closed !== undefined) {
errorCallback(this.#closed);
}
else if (!this.#opened) {
const openCallback = () => versionCallback(this.#subprotocol.version);
this.#openCallbacks.push({ openCallback, errorCallback });
}
else {
versionCallback(this.#subprotocol.version);
}
});
}
// Make sure that the negotiated version is at least `minVersion`.
/** @private */
_ensureVersion(minVersion, feature) {
if (this.#subprotocol === undefined || !this.#getVersionCalled) {
throw new ProtocolVersionError(`${feature} is supported only on protocol version ${minVersion} and higher, ` +
"but the version supported by the WebSocket server is not yet known. " +
"Use Client.getVersion() to wait until the version is available.");
}
else if (this.#subprotocol.version < minVersion) {
throw new ProtocolVersionError(`${feature} is supported on protocol version ${minVersion} and higher, ` +
`but the WebSocket server only supports version ${this.#subprotocol.version}`);
}
}
// Send a request to the server and invoke a callback when we get the response.
/** @private */
_sendRequest(request, callbacks) {
if (this.#closed !== undefined) {
callbacks.errorCallback(new ClosedError("Client is closed", this.#closed));
return;
}
const requestId = this.#requestIdAlloc.alloc();
this.#responseMap.set(requestId, { ...callbacks, type: request.type });
this.#send({ type: "request", requestId, request });
}
// The socket encountered an error.
#onSocketError(event) {
const eventMessage = event.message;
const message = eventMessage ?? "WebSocket was closed due to an error";
this.#setClosed(new WebSocketError(message));
}
// The socket was closed.
#onSocketClose(event) {
let message = `WebSocket was closed with code ${event.code}`;
if (event.reason) {
message += `: ${event.reason}`;
}
this.#setClosed(new WebSocketError(message));
}
// Close the client with the given error.
#setClosed(error) {
if (this.#closed !== undefined) {
return;
}
this.#closed = error;
for (const callbacks of this.#openCallbacks) {
callbacks.errorCallback(error);
}
this.#openCallbacks.length = 0;
for (const [requestId, responseState] of this.#responseMap.entries()) {
responseState.errorCallback(error);
this.#requestIdAlloc.free(requestId);
}
this.#responseMap.clear();
this.#socket.close();
}
// We received a message from the socket.
#onSocketMessage(event) {
if (this.#closed !== undefined) {
return;
}
try {
let msg;
const encoding = this.#subprotocol.encoding;
if (encoding === "json") {
if (typeof event.data !== "string") {
this.#socket.close(3003, "Only text messages are accepted with JSON encoding");
this.#setClosed(new ProtoError("Received non-text message from server with JSON encoding"));
return;
}
msg = readJsonObject(JSON.parse(event.data), json_ServerMsg);
}
else if (encoding === "protobuf") {
if (!(event.data instanceof ArrayBuffer)) {
this.#socket.close(3003, "Only binary messages are accepted with Protobuf encoding");
this.#setClosed(new ProtoError("Received non-binary message from server with Protobuf encoding"));
return;
}
msg = readProtobufMessage(new Uint8Array(event.data), protobuf_ServerMsg);
}
else {
throw impossible(encoding, "Impossible encoding");
}
this.#handleMsg(msg);
}
catch (e) {
this.#socket.close(3007, "Could not handle message");
this.#setClosed(e);
}
}
// Handle a message from the server.
#handleMsg(msg) {
if (msg.type === "none") {
throw new ProtoError("Received an unrecognized ServerMsg");
}
else if (msg.type === "hello_ok" || msg.type === "hello_error") {
if (this.#recvdHello) {
throw new ProtoError("Received a duplicated hello response");
}
this.#recvdHello = true;
if (msg.type === "hello_error") {
throw errorFromProto(msg.error);
}
return;
}
else if (!this.#recvdHello) {
throw new ProtoError("Received a non-hello message before a hello response");
}
if (msg.type === "response_ok") {
const requestId = msg.requestId;
const responseState = this.#responseMap.get(requestId);
this.#responseMap.delete(requestId);
if (responseState === undefined) {
throw new ProtoError("Received unexpected OK response");
}
this.#requestIdAlloc.free(requestId);
try {
if (responseState.type !== msg.response.type) {
console.dir({ responseState, msg });
throw new ProtoError("Received unexpected type of response");
}
responseState.responseCallback(msg.response);
}
catch (e) {
responseState.errorCallback(e);
throw e;
}
}
else if (msg.type === "response_error") {
const requestId = msg.requestId;
const responseState = this.#responseMap.get(requestId);
this.#responseMap.delete(requestId);
if (responseState === undefined) {
throw new ProtoError("Received unexpected error response");
}
this.#requestIdAlloc.free(requestId);
responseState.errorCallback(errorFromProto(msg.error));
}
else {
throw impossible(msg, "Impossible ServerMsg type");
}
}
/** Open a {@link WsStream}, a stream for executing SQL statements. */
openStream() {
return WsStream.open(this);
}
/** Cache a SQL text on the server. This requires protocol version 2 or higher. */
storeSql(sql) {
this._ensureVersion(2, "storeSql()");
const sqlId = this.#sqlIdAlloc.alloc();
const sqlObj = new Sql(this, sqlId);
const responseCallback = () => undefined;
const errorCallback = (e) => sqlObj._setClosed(e);
const request = { type: "store_sql", sqlId, sql };
this._sendRequest(request, { responseCallback, errorCallback });
return sqlObj;
}
/** @private */
_closeSql(sqlId) {
if (this.#closed !== undefined) {
return;
}
const responseCallback = () => this.#sqlIdAlloc.free(sqlId);
const errorCallback = (e) => this.#setClosed(e);
const request = { type: "close_sql", sqlId };
this._sendRequest(request, { responseCallback, errorCallback });
}
/** Close the client and the WebSocket. */
close() {
this.#setClosed(new ClientError("Client was manually closed"));
}
/** True if the client is closed. */
get closed() {
return this.#closed !== undefined;
}
}

View File

@@ -0,0 +1,17 @@
import { Cursor } from "../cursor.js";
import type { WsClient } from "./client.js";
import type * as proto from "./proto.js";
import type { WsStream } from "./stream.js";
export declare class WsCursor extends Cursor {
#private;
/** @private */
constructor(client: WsClient, stream: WsStream, cursorId: number);
/** Fetch the next entry from the cursor. */
next(): Promise<proto.CursorEntry | undefined>;
/** @private */
_setClosed(error: Error): void;
/** Close the cursor. */
close(): void;
/** True if the cursor is closed. */
get closed(): boolean;
}

80
node_modules/@libsql/hrana-client/lib-esm/ws/cursor.js generated vendored Normal file
View File

@@ -0,0 +1,80 @@
import { ClientError, ClosedError } from "../errors.js";
import { Cursor } from "../cursor.js";
import { Queue } from "../queue.js";
const fetchChunkSize = 1000;
const fetchQueueSize = 10;
export class WsCursor extends Cursor {
#client;
#stream;
#cursorId;
#entryQueue;
#fetchQueue;
#closed;
#done;
/** @private */
constructor(client, stream, cursorId) {
super();
this.#client = client;
this.#stream = stream;
this.#cursorId = cursorId;
this.#entryQueue = new Queue();
this.#fetchQueue = new Queue();
this.#closed = undefined;
this.#done = false;
}
/** Fetch the next entry from the cursor. */
async next() {
for (;;) {
if (this.#closed !== undefined) {
throw new ClosedError("Cursor is closed", this.#closed);
}
while (!this.#done && this.#fetchQueue.length < fetchQueueSize) {
this.#fetchQueue.push(this.#fetch());
}
const entry = this.#entryQueue.shift();
if (this.#done || entry !== undefined) {
return entry;
}
// we assume that `Cursor.next()` is never called concurrently
await this.#fetchQueue.shift().then((response) => {
if (response === undefined) {
return;
}
for (const entry of response.entries) {
this.#entryQueue.push(entry);
}
this.#done ||= response.done;
});
}
}
#fetch() {
return this.#stream._sendCursorRequest(this, {
type: "fetch_cursor",
cursorId: this.#cursorId,
maxCount: fetchChunkSize,
}).then((resp) => resp, (error) => {
this._setClosed(error);
return undefined;
});
}
/** @private */
_setClosed(error) {
if (this.#closed !== undefined) {
return;
}
this.#closed = error;
this.#stream._sendCursorRequest(this, {
type: "close_cursor",
cursorId: this.#cursorId,
}).catch(() => undefined);
this.#stream._cursorClosed(this);
}
/** Close the cursor. */
close() {
this._setClosed(new ClientError("Cursor was manually closed"));
}
/** True if the cursor is closed. */
get closed() {
return this.#closed !== undefined;
}
}

View File

@@ -0,0 +1,3 @@
import * as d from "../encoding/json/decode.js";
import * as proto from "./proto.js";
export declare function ServerMsg(obj: d.Obj): proto.ServerMsg;

View File

@@ -0,0 +1,74 @@
import { ProtoError } from "../errors.js";
import * as d from "../encoding/json/decode.js";
import { Error, StmtResult, BatchResult, CursorEntry, DescribeResult } from "../shared/json_decode.js";
export function ServerMsg(obj) {
const type = d.string(obj["type"]);
if (type === "hello_ok") {
return { type: "hello_ok" };
}
else if (type === "hello_error") {
const error = Error(d.object(obj["error"]));
return { type: "hello_error", error };
}
else if (type === "response_ok") {
const requestId = d.number(obj["request_id"]);
const response = Response(d.object(obj["response"]));
return { type: "response_ok", requestId, response };
}
else if (type === "response_error") {
const requestId = d.number(obj["request_id"]);
const error = Error(d.object(obj["error"]));
return { type: "response_error", requestId, error };
}
else {
throw new ProtoError("Unexpected type of ServerMsg");
}
}
function Response(obj) {
const type = d.string(obj["type"]);
if (type === "open_stream") {
return { type: "open_stream" };
}
else if (type === "close_stream") {
return { type: "close_stream" };
}
else if (type === "execute") {
const result = StmtResult(d.object(obj["result"]));
return { type: "execute", result };
}
else if (type === "batch") {
const result = BatchResult(d.object(obj["result"]));
return { type: "batch", result };
}
else if (type === "open_cursor") {
return { type: "open_cursor" };
}
else if (type === "close_cursor") {
return { type: "close_cursor" };
}
else if (type === "fetch_cursor") {
const entries = d.arrayObjectsMap(obj["entries"], CursorEntry);
const done = d.boolean(obj["done"]);
return { type: "fetch_cursor", entries, done };
}
else if (type === "sequence") {
return { type: "sequence" };
}
else if (type === "describe") {
const result = DescribeResult(d.object(obj["result"]));
return { type: "describe", result };
}
else if (type === "store_sql") {
return { type: "store_sql" };
}
else if (type === "close_sql") {
return { type: "close_sql" };
}
else if (type === "get_autocommit") {
const isAutocommit = d.boolean(obj["is_autocommit"]);
return { type: "get_autocommit", isAutocommit };
}
else {
throw new ProtoError("Unexpected type of Response");
}
}

View File

@@ -0,0 +1,3 @@
import * as e from "../encoding/json/encode.js";
import * as proto from "./proto.js";
export declare function ClientMsg(w: e.ObjectWriter, msg: proto.ClientMsg): void;

View File

@@ -0,0 +1,77 @@
import { Stmt, Batch } from "../shared/json_encode.js";
import { impossible } from "../util.js";
export function ClientMsg(w, msg) {
w.stringRaw("type", msg.type);
if (msg.type === "hello") {
if (msg.jwt !== undefined) {
w.string("jwt", msg.jwt);
}
}
else if (msg.type === "request") {
w.number("request_id", msg.requestId);
w.object("request", msg.request, Request);
}
else {
throw impossible(msg, "Impossible type of ClientMsg");
}
}
function Request(w, msg) {
w.stringRaw("type", msg.type);
if (msg.type === "open_stream") {
w.number("stream_id", msg.streamId);
}
else if (msg.type === "close_stream") {
w.number("stream_id", msg.streamId);
}
else if (msg.type === "execute") {
w.number("stream_id", msg.streamId);
w.object("stmt", msg.stmt, Stmt);
}
else if (msg.type === "batch") {
w.number("stream_id", msg.streamId);
w.object("batch", msg.batch, Batch);
}
else if (msg.type === "open_cursor") {
w.number("stream_id", msg.streamId);
w.number("cursor_id", msg.cursorId);
w.object("batch", msg.batch, Batch);
}
else if (msg.type === "close_cursor") {
w.number("cursor_id", msg.cursorId);
}
else if (msg.type === "fetch_cursor") {
w.number("cursor_id", msg.cursorId);
w.number("max_count", msg.maxCount);
}
else if (msg.type === "sequence") {
w.number("stream_id", msg.streamId);
if (msg.sql !== undefined) {
w.string("sql", msg.sql);
}
if (msg.sqlId !== undefined) {
w.number("sql_id", msg.sqlId);
}
}
else if (msg.type === "describe") {
w.number("stream_id", msg.streamId);
if (msg.sql !== undefined) {
w.string("sql", msg.sql);
}
if (msg.sqlId !== undefined) {
w.number("sql_id", msg.sqlId);
}
}
else if (msg.type === "store_sql") {
w.number("sql_id", msg.sqlId);
w.string("sql", msg.sql);
}
else if (msg.type === "close_sql") {
w.number("sql_id", msg.sqlId);
}
else if (msg.type === "get_autocommit") {
w.number("stream_id", msg.streamId);
}
else {
throw impossible(msg, "Impossible type of Request");
}
}

136
node_modules/@libsql/hrana-client/lib-esm/ws/proto.d.ts generated vendored Normal file
View File

@@ -0,0 +1,136 @@
export * from "../shared/proto.js";
import { int32, uint32, Error, Stmt, StmtResult, Batch, BatchResult, CursorEntry, DescribeResult } from "../shared/proto.js";
export type ClientMsg = HelloMsg | RequestMsg;
export type ServerMsg = {
type: "none";
} | HelloOkMsg | HelloErrorMsg | ResponseOkMsg | ResponseErrorMsg;
export type HelloMsg = {
type: "hello";
jwt: string | undefined;
};
export type HelloOkMsg = {
type: "hello_ok";
};
export type HelloErrorMsg = {
type: "hello_error";
error: Error;
};
export type RequestMsg = {
type: "request";
requestId: int32;
request: Request;
};
export type ResponseOkMsg = {
type: "response_ok";
requestId: int32;
response: Response;
};
export type ResponseErrorMsg = {
type: "response_error";
requestId: int32;
error: Error;
};
export type Request = OpenStreamReq | CloseStreamReq | ExecuteReq | BatchReq | OpenCursorReq | CloseCursorReq | FetchCursorReq | SequenceReq | DescribeReq | StoreSqlReq | CloseSqlReq | GetAutocommitReq;
export type Response = {
type: "none";
} | OpenStreamResp | CloseStreamResp | ExecuteResp | BatchResp | OpenCursorResp | CloseCursorResp | FetchCursorResp | SequenceResp | DescribeResp | StoreSqlResp | CloseSqlResp | GetAutocommitResp;
export type OpenStreamReq = {
type: "open_stream";
streamId: int32;
};
export type OpenStreamResp = {
type: "open_stream";
};
export type CloseStreamReq = {
type: "close_stream";
streamId: int32;
};
export type CloseStreamResp = {
type: "close_stream";
};
export type ExecuteReq = {
type: "execute";
streamId: int32;
stmt: Stmt;
};
export type ExecuteResp = {
type: "execute";
result: StmtResult;
};
export type BatchReq = {
type: "batch";
streamId: int32;
batch: Batch;
};
export type BatchResp = {
type: "batch";
result: BatchResult;
};
export type OpenCursorReq = {
type: "open_cursor";
streamId: int32;
cursorId: int32;
batch: Batch;
};
export type OpenCursorResp = {
type: "open_cursor";
};
export type CloseCursorReq = {
type: "close_cursor";
cursorId: int32;
};
export type CloseCursorResp = {
type: "close_cursor";
};
export type FetchCursorReq = {
type: "fetch_cursor";
cursorId: int32;
maxCount: uint32;
};
export type FetchCursorResp = {
type: "fetch_cursor";
entries: Array<CursorEntry>;
done: boolean;
};
export type DescribeReq = {
type: "describe";
streamId: int32;
sql: string | undefined;
sqlId: int32 | undefined;
};
export type DescribeResp = {
type: "describe";
result: DescribeResult;
};
export type SequenceReq = {
type: "sequence";
streamId: int32;
sql: string | undefined;
sqlId: int32 | undefined;
};
export type SequenceResp = {
type: "sequence";
};
export type StoreSqlReq = {
type: "store_sql";
sqlId: int32;
sql: string;
};
export type StoreSqlResp = {
type: "store_sql";
};
export type CloseSqlReq = {
type: "close_sql";
sqlId: int32;
};
export type CloseSqlResp = {
type: "close_sql";
};
export type GetAutocommitReq = {
type: "get_autocommit";
streamId: int32;
};
export type GetAutocommitResp = {
type: "get_autocommit";
isAutocommit: boolean;
};

View File

@@ -0,0 +1,2 @@
// Types for the structures specific to Hrana over WebSockets.
export * from "../shared/proto.js";

View File

@@ -0,0 +1,3 @@
import * as d from "../encoding/protobuf/decode.js";
import * as proto from "./proto.js";
export declare const ServerMsg: d.MessageDef<proto.ServerMsg>;

View File

@@ -0,0 +1,60 @@
import { Error, StmtResult, BatchResult, CursorEntry, DescribeResult } from "../shared/protobuf_decode.js";
export const ServerMsg = {
default() { return { type: "none" }; },
1(r) { return { type: "hello_ok" }; },
2(r) { return r.message(HelloErrorMsg); },
3(r) { return r.message(ResponseOkMsg); },
4(r) { return r.message(ResponseErrorMsg); },
};
const HelloErrorMsg = {
default() { return { type: "hello_error", error: Error.default() }; },
1(r, msg) { msg.error = r.message(Error); },
};
const ResponseErrorMsg = {
default() { return { type: "response_error", requestId: 0, error: Error.default() }; },
1(r, msg) { msg.requestId = r.int32(); },
2(r, msg) { msg.error = r.message(Error); },
};
const ResponseOkMsg = {
default() {
return {
type: "response_ok",
requestId: 0,
response: { type: "none" },
};
},
1(r, msg) { msg.requestId = r.int32(); },
2(r, msg) { msg.response = { type: "open_stream" }; },
3(r, msg) { msg.response = { type: "close_stream" }; },
4(r, msg) { msg.response = r.message(ExecuteResp); },
5(r, msg) { msg.response = r.message(BatchResp); },
6(r, msg) { msg.response = { type: "open_cursor" }; },
7(r, msg) { msg.response = { type: "close_cursor" }; },
8(r, msg) { msg.response = r.message(FetchCursorResp); },
9(r, msg) { msg.response = { type: "sequence" }; },
10(r, msg) { msg.response = r.message(DescribeResp); },
11(r, msg) { msg.response = { type: "store_sql" }; },
12(r, msg) { msg.response = { type: "close_sql" }; },
13(r, msg) { msg.response = r.message(GetAutocommitResp); },
};
const ExecuteResp = {
default() { return { type: "execute", result: StmtResult.default() }; },
1(r, msg) { msg.result = r.message(StmtResult); },
};
const BatchResp = {
default() { return { type: "batch", result: BatchResult.default() }; },
1(r, msg) { msg.result = r.message(BatchResult); },
};
const FetchCursorResp = {
default() { return { type: "fetch_cursor", entries: [], done: false }; },
1(r, msg) { msg.entries.push(r.message(CursorEntry)); },
2(r, msg) { msg.done = r.bool(); },
};
const DescribeResp = {
default() { return { type: "describe", result: DescribeResult.default() }; },
1(r, msg) { msg.result = r.message(DescribeResult); },
};
const GetAutocommitResp = {
default() { return { type: "get_autocommit", isAutocommit: false }; },
1(r, msg) { msg.isAutocommit = r.bool(); },
};

View File

@@ -0,0 +1,3 @@
import * as e from "../encoding/protobuf/encode.js";
import * as proto from "./proto.js";
export declare function ClientMsg(w: e.MessageWriter, msg: proto.ClientMsg): void;

View File

@@ -0,0 +1,115 @@
import { Stmt, Batch } from "../shared/protobuf_encode.js";
import { impossible } from "../util.js";
export function ClientMsg(w, msg) {
if (msg.type === "hello") {
w.message(1, msg, HelloMsg);
}
else if (msg.type === "request") {
w.message(2, msg, RequestMsg);
}
else {
throw impossible(msg, "Impossible type of ClientMsg");
}
}
function HelloMsg(w, msg) {
if (msg.jwt !== undefined) {
w.string(1, msg.jwt);
}
}
function RequestMsg(w, msg) {
w.int32(1, msg.requestId);
const request = msg.request;
if (request.type === "open_stream") {
w.message(2, request, OpenStreamReq);
}
else if (request.type === "close_stream") {
w.message(3, request, CloseStreamReq);
}
else if (request.type === "execute") {
w.message(4, request, ExecuteReq);
}
else if (request.type === "batch") {
w.message(5, request, BatchReq);
}
else if (request.type === "open_cursor") {
w.message(6, request, OpenCursorReq);
}
else if (request.type === "close_cursor") {
w.message(7, request, CloseCursorReq);
}
else if (request.type === "fetch_cursor") {
w.message(8, request, FetchCursorReq);
}
else if (request.type === "sequence") {
w.message(9, request, SequenceReq);
}
else if (request.type === "describe") {
w.message(10, request, DescribeReq);
}
else if (request.type === "store_sql") {
w.message(11, request, StoreSqlReq);
}
else if (request.type === "close_sql") {
w.message(12, request, CloseSqlReq);
}
else if (request.type === "get_autocommit") {
w.message(13, request, GetAutocommitReq);
}
else {
throw impossible(request, "Impossible type of Request");
}
}
function OpenStreamReq(w, msg) {
w.int32(1, msg.streamId);
}
function CloseStreamReq(w, msg) {
w.int32(1, msg.streamId);
}
function ExecuteReq(w, msg) {
w.int32(1, msg.streamId);
w.message(2, msg.stmt, Stmt);
}
function BatchReq(w, msg) {
w.int32(1, msg.streamId);
w.message(2, msg.batch, Batch);
}
function OpenCursorReq(w, msg) {
w.int32(1, msg.streamId);
w.int32(2, msg.cursorId);
w.message(3, msg.batch, Batch);
}
function CloseCursorReq(w, msg) {
w.int32(1, msg.cursorId);
}
function FetchCursorReq(w, msg) {
w.int32(1, msg.cursorId);
w.uint32(2, msg.maxCount);
}
function SequenceReq(w, msg) {
w.int32(1, msg.streamId);
if (msg.sql !== undefined) {
w.string(2, msg.sql);
}
if (msg.sqlId !== undefined) {
w.int32(3, msg.sqlId);
}
}
function DescribeReq(w, msg) {
w.int32(1, msg.streamId);
if (msg.sql !== undefined) {
w.string(2, msg.sql);
}
if (msg.sqlId !== undefined) {
w.int32(3, msg.sqlId);
}
}
function StoreSqlReq(w, msg) {
w.int32(1, msg.sqlId);
w.string(2, msg.sql);
}
function CloseSqlReq(w, msg) {
w.int32(1, msg.sqlId);
}
function GetAutocommitReq(w, msg) {
w.int32(1, msg.streamId);
}

View File

@@ -0,0 +1,40 @@
import type { SqlOwner, ProtoSql } from "../sql.js";
import { Stream } from "../stream.js";
import type { WsClient } from "./client.js";
import { WsCursor } from "./cursor.js";
import type * as proto from "./proto.js";
export declare class WsStream extends Stream {
#private;
/** @private */
static open(client: WsClient): WsStream;
/** @private */
constructor(client: WsClient, streamId: number);
/** Get the {@link WsClient} object that this stream belongs to. */
client(): WsClient;
/** @private */
_sqlOwner(): SqlOwner;
/** @private */
_execute(stmt: proto.Stmt): Promise<proto.StmtResult>;
/** @private */
_batch(batch: proto.Batch): Promise<proto.BatchResult>;
/** @private */
_describe(protoSql: ProtoSql): Promise<proto.DescribeResult>;
/** @private */
_sequence(protoSql: ProtoSql): Promise<void>;
/** Check whether the SQL connection underlying this stream is in autocommit state (i.e., outside of an
* explicit transaction). This requires protocol version 3 or higher.
*/
getAutocommit(): Promise<boolean>;
/** @private */
_openCursor(batch: proto.Batch): Promise<WsCursor>;
/** @private */
_sendCursorRequest(cursor: WsCursor, request: proto.Request): Promise<proto.Response>;
/** @private */
_cursorClosed(cursor: WsCursor): void;
/** Immediately close the stream. */
close(): void;
/** Gracefully close the stream. */
closeGracefully(): void;
/** True if the stream is closed or closing. */
get closed(): boolean;
}

211
node_modules/@libsql/hrana-client/lib-esm/ws/stream.js generated vendored Normal file
View File

@@ -0,0 +1,211 @@
import { ClientError, ClosedError, InternalError } from "../errors.js";
import { Queue } from "../queue.js";
import { Stream } from "../stream.js";
import { WsCursor } from "./cursor.js";
export class WsStream extends Stream {
#client;
#streamId;
#queue;
#cursor;
#closing;
#closed;
/** @private */
static open(client) {
const streamId = client._streamIdAlloc.alloc();
const stream = new WsStream(client, streamId);
const responseCallback = () => undefined;
const errorCallback = (e) => stream.#setClosed(e);
const request = { type: "open_stream", streamId };
client._sendRequest(request, { responseCallback, errorCallback });
return stream;
}
/** @private */
constructor(client, streamId) {
super(client.intMode);
this.#client = client;
this.#streamId = streamId;
this.#queue = new Queue();
this.#cursor = undefined;
this.#closing = false;
this.#closed = undefined;
}
/** Get the {@link WsClient} object that this stream belongs to. */
client() {
return this.#client;
}
/** @private */
_sqlOwner() {
return this.#client;
}
/** @private */
_execute(stmt) {
return this.#sendStreamRequest({
type: "execute",
streamId: this.#streamId,
stmt,
}).then((response) => {
return response.result;
});
}
/** @private */
_batch(batch) {
return this.#sendStreamRequest({
type: "batch",
streamId: this.#streamId,
batch,
}).then((response) => {
return response.result;
});
}
/** @private */
_describe(protoSql) {
this.#client._ensureVersion(2, "describe()");
return this.#sendStreamRequest({
type: "describe",
streamId: this.#streamId,
sql: protoSql.sql,
sqlId: protoSql.sqlId,
}).then((response) => {
return response.result;
});
}
/** @private */
_sequence(protoSql) {
this.#client._ensureVersion(2, "sequence()");
return this.#sendStreamRequest({
type: "sequence",
streamId: this.#streamId,
sql: protoSql.sql,
sqlId: protoSql.sqlId,
}).then((_response) => {
return undefined;
});
}
/** Check whether the SQL connection underlying this stream is in autocommit state (i.e., outside of an
* explicit transaction). This requires protocol version 3 or higher.
*/
getAutocommit() {
this.#client._ensureVersion(3, "getAutocommit()");
return this.#sendStreamRequest({
type: "get_autocommit",
streamId: this.#streamId,
}).then((response) => {
return response.isAutocommit;
});
}
#sendStreamRequest(request) {
return new Promise((responseCallback, errorCallback) => {
this.#pushToQueue({ type: "request", request, responseCallback, errorCallback });
});
}
/** @private */
_openCursor(batch) {
this.#client._ensureVersion(3, "cursor");
return new Promise((cursorCallback, errorCallback) => {
this.#pushToQueue({ type: "cursor", batch, cursorCallback, errorCallback });
});
}
/** @private */
_sendCursorRequest(cursor, request) {
if (cursor !== this.#cursor) {
throw new InternalError("Cursor not associated with the stream attempted to execute a request");
}
return new Promise((responseCallback, errorCallback) => {
if (this.#closed !== undefined) {
errorCallback(new ClosedError("Stream is closed", this.#closed));
}
else {
this.#client._sendRequest(request, { responseCallback, errorCallback });
}
});
}
/** @private */
_cursorClosed(cursor) {
if (cursor !== this.#cursor) {
throw new InternalError("Cursor was closed, but it was not associated with the stream");
}
this.#cursor = undefined;
this.#flushQueue();
}
#pushToQueue(entry) {
if (this.#closed !== undefined) {
entry.errorCallback(new ClosedError("Stream is closed", this.#closed));
}
else if (this.#closing) {
entry.errorCallback(new ClosedError("Stream is closing", undefined));
}
else {
this.#queue.push(entry);
this.#flushQueue();
}
}
#flushQueue() {
for (;;) {
const entry = this.#queue.first();
if (entry === undefined && this.#cursor === undefined && this.#closing) {
this.#setClosed(new ClientError("Stream was gracefully closed"));
break;
}
else if (entry?.type === "request" && this.#cursor === undefined) {
const { request, responseCallback, errorCallback } = entry;
this.#queue.shift();
this.#client._sendRequest(request, { responseCallback, errorCallback });
}
else if (entry?.type === "cursor" && this.#cursor === undefined) {
const { batch, cursorCallback } = entry;
this.#queue.shift();
const cursorId = this.#client._cursorIdAlloc.alloc();
const cursor = new WsCursor(this.#client, this, cursorId);
const request = {
type: "open_cursor",
streamId: this.#streamId,
cursorId,
batch,
};
const responseCallback = () => undefined;
const errorCallback = (e) => cursor._setClosed(e);
this.#client._sendRequest(request, { responseCallback, errorCallback });
this.#cursor = cursor;
cursorCallback(cursor);
}
else {
break;
}
}
}
#setClosed(error) {
if (this.#closed !== undefined) {
return;
}
this.#closed = error;
if (this.#cursor !== undefined) {
this.#cursor._setClosed(error);
}
for (;;) {
const entry = this.#queue.shift();
if (entry !== undefined) {
entry.errorCallback(error);
}
else {
break;
}
}
const request = { type: "close_stream", streamId: this.#streamId };
const responseCallback = () => this.#client._streamIdAlloc.free(this.#streamId);
const errorCallback = () => undefined;
this.#client._sendRequest(request, { responseCallback, errorCallback });
}
/** Immediately close the stream. */
close() {
this.#setClosed(new ClientError("Stream was manually closed"));
}
/** Gracefully close the stream. */
closeGracefully() {
this.#closing = true;
this.#flushQueue();
}
/** True if the stream is closed or closing. */
get closed() {
return this.#closed !== undefined || this.#closing;
}
}