UNPKG

surrealdb

Version:

The official SurrealDB SDK for JavaScript.

1,742 lines (1,729 loc) 225 kB
//#region src/internal/normalize-path.ts function normalizePath(prefix, path) { return `/${[...prefix.split("/"), ...path.split("/")].filter(Boolean).join("/")}`; } //#endregion //#region src/errors.ts var SurrealError = class extends Error {}; /** * Thrown when a call has been terminated because the connection was closed */ var CallTerminatedError = class extends SurrealError { name = "CallTerminatedError"; message = "The call has been terminated because the connection was closed"; }; /** * Thrown when reconnect attempts have been exhausted */ var ReconnectExhaustionError = class extends SurrealError { name = "ReconnectExhaustionError"; message = "The reconnect attempts have been exhausted"; }; /** * Thrown when a reconnect iterator fails to iterate */ var ReconnectIterationError = class extends SurrealError { name = "ReconnectIterationError"; message = "The reconnect iterator failed to iterate"; }; /** * Thrown when an unexpected server response is received */ var UnexpectedServerResponseError = class extends SurrealError { name = "UnexpectedServerResponseError"; response; constructor(response) { super(`The server returned an unexpected response: ${JSON.stringify(response)}`); this.response = response; } }; /** * Thrown when an unexpected connection error occurs */ var UnexpectedConnectionError = class extends SurrealError { name = "UnexpectedConnectionError"; message = "An unexpected connection error occurred"; constructor(cause) { super(); this.cause = cause; } }; /** * Thrown when an engine is not supported */ var UnsupportedEngineError = class extends SurrealError { name = "UnsupportedEngineError"; engine; constructor(engine) { super(`The engine "${engine}" is not supported or configured`); this.engine = engine; } }; /** * Thrown when there is no connection available */ var ConnectionUnavailableError = class extends SurrealError { name = "ConnectionUnavailableError"; message = "You must be connected to a SurrealDB instance before performing this operation"; }; /** * Thrown when there is no namespace and/or database selected */ var MissingNamespaceDatabaseError = class extends SurrealError { name = "MissingNamespaceDatabaseError"; message = "There is no namespace and/or database selected"; }; /** * Thrown when a connection to the server fails */ var HttpConnectionError = class extends SurrealError { name = "HttpConnectionError"; status; statusText; buffer; constructor(message, status, statusText, buffer) { super(`HTTP connection failed: ${message}`); this.status = status; this.statusText = statusText; this.buffer = buffer; } }; /** * Known error kinds returned by the SurrealDB server. * Use these constants for matching against `ServerError.kind`. */ const ErrorKind = { Validation: "Validation", Configuration: "Configuration", Thrown: "Thrown", Query: "Query", Serialization: "Serialization", NotAllowed: "NotAllowed", NotFound: "NotFound", AlreadyExists: "AlreadyExists", Connection: "Connection", Internal: "Internal" }; /** * Base class for all errors originating from the SurrealDB server. * Replaces the former `ResponseError` class. * * Server errors carry structured information: * - `kind` — the error category (e.g. `"NotAllowed"`, `"NotFound"`) * - `code` — legacy JSON-RPC numeric error code (0 when unavailable) * - `details` — kind-specific structured details from the server (`{ kind, details? }` format) * - `cause` — optional inner `ServerError` forming a recursive error chain * * The `cause` field mirrors Rust's `Option<Box<Error>>` — each error can * optionally wrap an inner error, creating a stack of structured errors. * It is set as the native `Error.cause` so that standard JS tooling * (Node.js, Chrome DevTools, debuggers) displays the full chain * automatically using the `[cause]:` format. * * Use `instanceof` on subclasses (e.g. `NotFoundError`, `NotAllowedError`) * for type-safe matching, or check the `kind` property directly. */ var ServerError = class extends SurrealError { get name() { return `ServerError [${this.kind}]`; } /** The structured error kind (e.g. "NotAllowed", "NotFound", "Internal") */ kind; /** Legacy JSON-RPC error code. 0 when not available (e.g. query result errors). */ code; /** * Kind-specific structured details using the `{ kind, details? }` wire format. * `undefined` when not provided by the server. Subclasses narrow this type * to their specific detail union (e.g. `NotAllowedErrorDetail`). */ details; constructor(options) { const innerCause = options.cause ?? void 0; super(options.message, innerCause ? { cause: innerCause } : void 0); this.kind = options.kind; this.code = options.code ?? 0; this.details = options.details ?? void 0; } }; /** * Server error: validation failure (parse error, invalid request/params, bad input). */ var ValidationError = class extends ServerError { kind = "Validation"; get name() { return "ValidationError"; } /** True if this is a SurrealQL parse error. */ get isParseError() { return this.details?.kind === "Parse"; } /** The name of the invalid parameter, if applicable. */ get parameterName() { if (this.details?.kind !== "InvalidParameter") return void 0; return this.details.details?.name; } }; /** * Server error: feature or configuration not supported (live queries, GraphQL). */ var ConfigurationError = class extends ServerError { kind = "Configuration"; get name() { return "ConfigurationError"; } /** True if live queries are not supported by the server configuration. */ get isLiveQueryNotSupported() { return this.details?.kind === "LiveQueryNotSupported"; } }; /** * Server error: user-thrown error via THROW in SurrealQL. */ var ThrownError = class extends ServerError { kind = "Thrown"; get name() { return "ThrownError"; } }; /** * Server error: query execution failure (timeout, cancelled, not executed). */ var QueryError = class extends ServerError { kind = "Query"; get name() { return "QueryError"; } /** True if the query was not executed (e.g. due to a prior error in the batch). */ get isNotExecuted() { return this.details?.kind === "NotExecuted"; } /** True if the query timed out. */ get isTimedOut() { return this.details?.kind === "TimedOut"; } /** True if the query was cancelled. */ get isCancelled() { return this.details?.kind === "Cancelled"; } /** The timeout duration, if this is a timeout error. Returns `{ secs, nanos }` or undefined. */ get timeout() { if (this.details?.kind !== "TimedOut") return void 0; return this.details.details?.duration; } }; /** * Server error: serialization or deserialization failure. */ var SerializationError = class extends ServerError { kind = "Serialization"; get name() { return "SerializationError"; } /** True if this is a deserialization error (as opposed to serialization). */ get isDeserialization() { return this.details?.kind === "Deserialization"; } }; /** * Server error: permission denied, method not allowed, function/scripting blocked. */ var NotAllowedError = class extends ServerError { kind = "NotAllowed"; get name() { return "NotAllowedError"; } /** True if the auth token has expired. */ get isTokenExpired() { return this.details?.kind === "Auth" && this.details.details?.kind === "TokenExpired"; } /** True if authentication credentials are invalid. */ get isInvalidAuth() { return this.details?.kind === "Auth" && this.details.details?.kind === "InvalidAuth"; } /** True if scripting is blocked. */ get isScriptingBlocked() { return this.details?.kind === "Scripting"; } /** The method name that is not allowed, if applicable. */ get methodName() { if (this.details?.kind !== "Method") return void 0; return this.details.details?.name; } /** The function name that is not allowed, if applicable. */ get functionName() { if (this.details?.kind !== "Function") return void 0; return this.details.details?.name; } }; /** * Server error: resource not found (table, record, namespace, method, etc.). */ var NotFoundError = class extends ServerError { kind = "NotFound"; get name() { return "NotFoundError"; } /** The table name that was not found, if applicable. */ get tableName() { if (this.details?.kind !== "Table") return void 0; return this.details.details?.name; } /** The record ID that was not found, if applicable. */ get recordId() { if (this.details?.kind !== "Record") return void 0; return this.details.details?.id; } /** The RPC method name that was not found, if applicable. */ get methodName() { if (this.details?.kind !== "Method") return void 0; return this.details.details?.name; } /** The namespace name that was not found, if applicable. */ get namespaceName() { if (this.details?.kind !== "Namespace") return void 0; return this.details.details?.name; } /** The database name that was not found, if applicable. */ get databaseName() { if (this.details?.kind !== "Database") return void 0; return this.details.details?.name; } }; /** * Server error: duplicate resource (record, table, namespace, etc.). */ var AlreadyExistsError = class extends ServerError { kind = "AlreadyExists"; get name() { return "AlreadyExistsError"; } /** The record ID that already exists, if applicable. */ get recordId() { if (this.details?.kind !== "Record") return void 0; return this.details.details?.id; } /** The table name that already exists, if applicable. */ get tableName() { if (this.details?.kind !== "Table") return void 0; return this.details.details?.name; } }; /** * Server error: unexpected or unknown internal error. * Also used as the fallback for unrecognized `kind` strings from newer servers. */ var InternalError = class extends ServerError { kind = "Internal"; get name() { return "InternalError"; } }; /** * @deprecated Use `ServerError` instead. This alias exists for backward compatibility. */ const ResponseError = ServerError; /** * Thrown when authentication fails */ var AuthenticationError = class extends SurrealError { name = "AuthenticationError"; message = "Authentication did not succeed"; constructor(cause) { super(); this.cause = cause; } }; /** * Thrown when a live subscription fails to listen */ var LiveSubscriptionError = class extends SurrealError { name = "LiveSubscriptionError"; constructor(messageOrCause) { if (typeof messageOrCause === "string") super(messageOrCause); else { super("Live subscription failed to listen"); this.cause = messageOrCause; } } }; /** * Thrown when the version of the remote datastore is not supported */ var UnsupportedVersionError = class extends SurrealError { name = "UnsupportedVersionError"; version; minimum; maximum; constructor(version, minimum, maximum) { super(`The version "${version}" reported by the engine is not supported by this library, expected a version that satisfies >= ${minimum} < ${maximum}`); this.version = version; this.minimum = minimum; this.maximum = maximum; } }; /** * Thrown when a SurrealQL expression fails to compute */ var ExpressionError = class extends SurrealError { name = "ExpressionError"; constructor(messageOrCause) { if (typeof messageOrCause === "string") super(messageOrCause); else { super("Failed to parse invalid expression"); this.cause = messageOrCause; } } }; /** * Thrown when one or more subscribers throw an error */ var PublishError = class PublishError extends SurrealError { name = "PublishError"; message = "One or more subscribers threw an error:"; causes; constructor(causes) { super(); this.causes = causes; this.message += PublishError.#appendCauses(causes, ""); } static #appendCauses(causes, msg) { let message = msg; for (const cause of causes) if (cause instanceof PublishError) message = PublishError.#appendCauses(cause.causes, msg); else message += `\n - ${cause instanceof Error ? cause.message : cause}`; return message; } }; /** * Thrown when a parsed date or datetime is invalid */ var InvalidDateError = class extends SurrealError { name = "InvalidDateError"; constructor(dateOrMessage) { if (typeof dateOrMessage === "string") super(dateOrMessage); else super(`The provided date is invalid: ${dateOrMessage}`); } }; /** * Thrown when a feature is not supported by the current engine */ var UnsupportedFeatureError = class extends SurrealError { name = "UnsupportedFeatureError"; feature; constructor(feature) { super(`The configured engine does not support the feature: ${feature.name}`); this.feature = feature; } }; /** * Thrown when a feature is not available in the used version of SurrealDB */ var UnavailableFeatureError = class extends SurrealError { name = "UnavailableFeatureError"; feature; version; constructor(feature, version) { super(`The version of SurrealDB (${version}) does not support the feature: ${feature.name} (>= ${feature.sinceVersion} < ${feature.untilVersion})`); this.feature = feature; this.version = version; } }; /** * Thrown when a session is invalid */ var InvalidSessionError = class extends SurrealError { name = "InvalidSessionError"; message = "The provided session is invalid"; session; constructor(session) { super(`Invalid session: ${session}`); this.session = session; } }; /** * Thrown when an API request was unsuccessful */ var UnsuccessfulApiError = class extends SurrealError { name = "UnsuccessfulApiError"; path; method; response; constructor(path, method, response) { super(`The ${method.toUpperCase()} ${path} request failed with status ${response.status}`); this.path = path; this.method = method; this.response = response; } }; /** * Thrown when a RecordId or RecordIdRange is constructed with invalid parts */ var InvalidRecordIdError = class extends SurrealError { name = "InvalidRecordIdError"; }; /** * Thrown when a Duration string cannot be parsed or a duration operation is invalid */ var InvalidDurationError = class extends SurrealError { name = "InvalidDurationError"; }; /** * Thrown when a Decimal operation fails (division by zero, invalid input, etc.) */ var InvalidDecimalError = class extends SurrealError { name = "InvalidDecimalError"; }; /** * Thrown when a Table or StringRecordId is constructed with an invalid value */ var InvalidTableError = class extends SurrealError { name = "InvalidTableError"; }; //#endregion //#region src/internal/dispatched-promise.ts var DispatchedPromise = class extends Promise { #resolve; #reject; #dispatched = false; constructor() { let _resolve; let _reject; super((resolve, reject) => { _resolve = resolve; _reject = reject; }); if (!_resolve || !_reject) throw new Error("resolve and reject required"); this.#resolve = _resolve; this.#reject = _reject; } #ensureDispatched() { if (!this.#dispatched) { this.#dispatched = true; this.dispatch().then(this.#resolve, this.#reject); } return this; } then(onfulfilled, onrejected) { this.#ensureDispatched(); return super.then(onfulfilled, onrejected); } catch(onrejected) { this.#ensureDispatched(); return super.catch(onrejected); } finally(onfinally) { this.#ensureDispatched(); return super.finally(onfinally); } static get [Symbol.species]() { return Promise; } get [Symbol.toStringTag]() { return "DispatchedPromise"; } }; //#endregion //#region src/internal/get-incremental-id.ts let id = 0; function getIncrementalID() { id = (id + 1) % Number.MAX_SAFE_INTEGER; return id.toString(); } //#endregion //#region src/utils/range.ts /** * Represents a range bound which includes the value within the range */ var BoundIncluded = class { constructor(value) { this.value = value; } }; /** * Represents a range bound which excludes the value from the range */ var BoundExcluded = class { constructor(value) { this.value = value; } }; //#endregion //#region src/internal/escape-regex.ts function escapeRegex(str) { return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); } //#endregion //#region src/value/value.ts /** * A complex SurrealQL value type */ var Value = class {}; //#endregion //#region src/value/duration.ts const NANOSECOND$1 = 1n; const MICROSECOND$1 = 1000n * NANOSECOND$1; const MILLISECOND$1 = 1000n * MICROSECOND$1; const SECOND$1 = 1000n * MILLISECOND$1; const MINUTE = 60n * SECOND$1; const HOUR = 60n * MINUTE; const DAY = 24n * HOUR; const WEEK = 7n * DAY; const YEAR = 365n * DAY; const UNITS = new Map([ ["ns", NANOSECOND$1], ["µs", MICROSECOND$1], ["μs", MICROSECOND$1], ["us", MICROSECOND$1], ["ms", MILLISECOND$1], ["s", SECOND$1], ["m", MINUTE], ["h", HOUR], ["d", DAY], ["w", WEEK], ["y", YEAR] ]); const UNITS_REVERSED = Array.from(UNITS).reduce((map, [unit, size]) => { map.set(size, unit); return map; }, /* @__PURE__ */ new Map()); const DURATION_PART_REGEX = /* @__PURE__ */ new RegExp(`^(\\d+)\\.?\\d*(${Array.from(UNITS.keys()).map(escapeRegex).join("|")})`); const FLOAT_DURATION_REGEX = /* @__PURE__ */ new RegExp(`^(\\d+(?:\\.\\d+)?)(${Array.from(UNITS.keys()).map(escapeRegex).join("|")})$`); /** * A SurrealQL duration value with support for parsing, formatting, arithmetic, and nanosecond precision. */ var Duration = class Duration extends Value { #seconds; #nanoseconds; constructor(input) { super(); if (input instanceof Duration) { this.#seconds = input.#seconds; this.#nanoseconds = input.#nanoseconds; } else if (typeof input === "string") { const [s$1, ns] = Duration.parseString(input); this.#seconds = s$1; this.#nanoseconds = ns; } else { const s$1 = typeof input[0] === "bigint" ? input[0] : BigInt(Math.floor(input[0] ?? 0)); const ns = typeof input[1] === "bigint" ? input[1] : BigInt(Math.floor(input[1] ?? 0)); const total = s$1 * SECOND$1 + ns; this.#seconds = total / SECOND$1; this.#nanoseconds = total % SECOND$1; } } equals(other) { if (!(other instanceof Duration)) return false; return this.#seconds === other.#seconds && this.#nanoseconds === other.#nanoseconds; } toJSON() { return this.toString(); } /** * @returns Human readable duration string */ toString() { let remainingSeconds = this.#seconds; let result = ""; for (const [size, unit] of Array.from(UNITS_REVERSED).reverse()) if (size >= SECOND$1) { const amount = remainingSeconds / (size / SECOND$1); if (amount > 0n) { remainingSeconds %= size / SECOND$1; result += `${amount}${unit}`; } } let remainingNanoseconds = remainingSeconds * SECOND$1 + this.#nanoseconds; for (const [size, unit] of Array.from(UNITS_REVERSED).reverse()) if (size < SECOND$1) { const amount = remainingNanoseconds / size; if (amount > 0n) { remainingNanoseconds %= size; result += `${amount}${unit}`; } } return result; } /** * Converts the duration to a tuple */ toCompact() { return this.#nanoseconds > 0n ? [this.#seconds, this.#nanoseconds] : this.#seconds > 0n ? [this.#seconds] : []; } /** * Parses a duration string like "1h30m" * * @param input Input string * @returns [seconds, nanoseconds] */ static parseString(input) { let seconds = 0n; let nanoseconds = 0n; let left = input; while (left !== "") { const match = left.match(DURATION_PART_REGEX); if (match) { const amount = BigInt(match[1]); const unit = match[2]; const factor = UNITS.get(unit); if (!factor) throw new InvalidDurationError(`Invalid duration unit: ${unit}`); if (factor >= SECOND$1) seconds += amount * (factor / SECOND$1); else nanoseconds += amount * factor; left = left.slice(match[0].length); } else throw new InvalidDurationError("Could not match a next duration part"); } seconds += nanoseconds / SECOND$1; nanoseconds %= SECOND$1; return [seconds, nanoseconds]; } /** * Adds two durations together * * @param other The duration to add * @returns The resulting duration */ add(other) { let sec = this.#seconds + other.#seconds; let ns = this.#nanoseconds + other.#nanoseconds; if (ns >= SECOND$1) { sec += 1n; ns -= SECOND$1; } return new Duration([sec, ns]); } /** * Subtracts another duration from this one * * @param other The duration to subtract * @returns The resulting duration */ sub(other) { let sec = this.#seconds - other.#seconds; let ns = this.#nanoseconds - other.#nanoseconds; if (ns < 0n) { sec -= 1n; ns += SECOND$1; } return new Duration([sec, ns]); } /** * Multiplies the duration by a scalar * * @param factor The factor to multiply by * @returns The resulting duration */ mul(factor) { const factorBig = typeof factor === "bigint" ? factor : BigInt(Math.floor(factor)); const totalNs = this.#seconds * SECOND$1 + this.#nanoseconds; const resultNs = totalNs * factorBig; return new Duration([resultNs / SECOND$1, resultNs % SECOND$1]); } div(divisor) { if (typeof divisor === "object" && divisor instanceof Duration) { const a = this.#seconds * SECOND$1 + this.#nanoseconds; const b = divisor.#seconds * SECOND$1 + divisor.#nanoseconds; if (b === 0n) throw new InvalidDurationError("Division by zero duration"); return a / b; } const divisorBig = typeof divisor === "bigint" ? divisor : BigInt(Math.floor(divisor)); if (divisorBig === 0n) throw new InvalidDurationError("Division by zero"); const totalNs = this.#seconds * SECOND$1 + this.#nanoseconds; const resultNs = totalNs / divisorBig; return new Duration([resultNs / SECOND$1, resultNs % SECOND$1]); } /** * Computes the remainder after division * * @param mod The divisor * @returns The remainder duration */ mod(mod) { const a = this.#seconds * SECOND$1 + this.#nanoseconds; const b = mod.#seconds * SECOND$1 + mod.#nanoseconds; if (b === 0n) throw new InvalidDurationError("Modulo by zero duration"); const resultNs = a % b; return new Duration([resultNs / SECOND$1, resultNs % SECOND$1]); } /** * Total nanoseconds in this duration */ get nanoseconds() { return this.#seconds * SECOND$1 + this.#nanoseconds; } /** * Total microseconds */ get microseconds() { return this.nanoseconds / MICROSECOND$1; } /** * Total milliseconds */ get milliseconds() { return this.nanoseconds / MILLISECOND$1; } /** * Whole seconds in the duration */ get seconds() { return this.#seconds; } /** * Total whole minutes in the duration */ get minutes() { return this.#seconds / (MINUTE / SECOND$1); } /** * Total whole hours in the duration */ get hours() { return this.#seconds / (HOUR / SECOND$1); } /** * Total whole days in the duration */ get days() { return this.#seconds / (DAY / SECOND$1); } /** * Total whole weeks in the duration */ get weeks() { return this.#seconds / (WEEK / SECOND$1); } /** * Total whole years in the duration */ get years() { return this.#seconds / (YEAR / SECOND$1); } /** * Creates a Duration from nanoseconds * * @param ns Nanoseconds value * @returns The resulting duration */ static nanoseconds(ns) { const n = typeof ns === "bigint" ? ns : BigInt(Math.floor(ns)); return new Duration([n / SECOND$1, n % SECOND$1]); } /** * Creates a Duration from microseconds * * @param µs Microseconds value * @returns The resulting duration */ static microseconds(µs) { const n = typeof µs === "bigint" ? µs : BigInt(Math.floor(µs)); return Duration.nanoseconds(n * MICROSECOND$1); } /** * Creates a Duration from milliseconds * * @param ms Milliseconds value * @returns The resulting duration */ static milliseconds(ms) { const n = typeof ms === "bigint" ? ms : BigInt(Math.floor(ms)); return Duration.nanoseconds(n * MILLISECOND$1); } /** * Creates a Duration from seconds * * @param s Seconds value * @returns The resulting duration */ static seconds(s$1) { const n = typeof s$1 === "bigint" ? s$1 : BigInt(Math.floor(s$1)); return new Duration([n, 0n]); } /** * Creates a Duration from minutes * * @param m Minutes value * @returns The resulting duration */ static minutes(m) { const n = typeof m === "bigint" ? m : BigInt(Math.floor(m)); return new Duration([n * (MINUTE / SECOND$1), 0n]); } /** * Creates a Duration from hours * * @param h Hours value * @returns The resulting duration */ static hours(h) { const n = typeof h === "bigint" ? h : BigInt(Math.floor(h)); return new Duration([n * (HOUR / SECOND$1), 0n]); } /** * Creates a Duration from days * * @param d Days value * @returns The resulting duration */ static days(d$1) { const n = typeof d$1 === "bigint" ? d$1 : BigInt(Math.floor(d$1)); return new Duration([n * (DAY / SECOND$1), 0n]); } /** * Creates a Duration from weeks * * @param w Weeks value * @returns The resulting duration */ static weeks(w) { const n = typeof w === "bigint" ? w : BigInt(Math.floor(w)); return new Duration([n * (WEEK / SECOND$1), 0n]); } /** * Creates a Duration from years * * @param y Years value * @returns The resulting duration */ static years(y) { const n = typeof y === "bigint" ? y : BigInt(Math.floor(y)); return new Duration([n * (YEAR / SECOND$1), 0n]); } /** * Parses a duration from a float string with a single time unit, e.g. "1.998487792s", "1.5m", "500.0ms" * * @param input Float duration string * @returns The resulting duration */ static parseFloat(input) { const match = input.match(FLOAT_DURATION_REGEX); if (!match) throw new InvalidDurationError(`Invalid float duration string: ${input}`); const numStr = match[1]; const unit = match[2]; const factor = UNITS.get(unit); if (!factor) throw new InvalidDurationError(`Invalid duration unit: ${unit}`); const [intPart, fracPart = ""] = numStr.split("."); const scale = 10n ** BigInt(fracPart.length); const scaledValue = BigInt(intPart) * scale + BigInt(fracPart || "0"); const totalNs = scaledValue * factor / scale; return new Duration([totalNs / SECOND$1, totalNs % SECOND$1]); } /** * Measures the elapsed time since the function was called * If the Performance API is available, it uses it to measure the elapsed time in nanoseconds * * @returns A function that returns the elapsed time as a Duration */ static measure() { if (typeof performance !== "undefined" && performance.now) { const start$1 = performance.now(); return () => { const end = performance.now(); return Duration.nanoseconds((end - start$1) * 1e6); }; } const start = Date.now(); return () => { const end = Date.now(); return Duration.milliseconds(end - start); }; } }; //#endregion //#region src/value/datetime.ts const NANOSECOND = 1n; const MICROSECOND = 1000n * NANOSECOND; const MILLISECOND = 1000n * MICROSECOND; const SECOND = 1000n * MILLISECOND; /** * A SurrealQL datetime value with support for parsing, formatting, arithmetic, and nanosecond precision. */ var DateTime = class DateTime extends Value { #seconds; #nanoseconds; static loadHr = typeof process !== "undefined" && process.hrtime ? { ns: process.hrtime.bigint(), ms: BigInt(Date.now()) } : void 0; constructor(input) { super(); if (input === void 0) { const now = DateTime.now(); this.#seconds = now.#seconds; this.#nanoseconds = now.#nanoseconds; } else if (input instanceof DateTime) { this.#seconds = input.#seconds; this.#nanoseconds = input.#nanoseconds; } else if (input instanceof Date) { const time = input.getTime(); if (Number.isNaN(time)) throw new InvalidDateError(input); const s$1 = BigInt(Math.floor(time / 1e3)); const ns = BigInt(time % 1e3 * 1e6); this.#seconds = s$1; this.#nanoseconds = ns; } else if (typeof input === "string") { const [s$1, ns] = DateTime.parseString(input); this.#seconds = s$1; this.#nanoseconds = ns; } else if (typeof input === "number") { this.#seconds = BigInt(Math.floor(input)); this.#nanoseconds = 0n; } else if (typeof input === "bigint") { this.#seconds = input; this.#nanoseconds = 0n; } else { const s$1 = typeof input[0] === "bigint" ? input[0] : BigInt(Math.floor(input[0] ?? 0)); const ns = typeof input[1] === "bigint" ? input[1] : BigInt(Math.floor(input[1] ?? 0)); const totalSeconds = s$1 + ns / SECOND; this.#seconds = totalSeconds; this.#nanoseconds = ns % SECOND; } } equals(other) { if (!(other instanceof DateTime)) return false; return this.#seconds === other.#seconds && this.#nanoseconds === other.#nanoseconds; } toJSON() { return this.toISOString(); } /** * @returns The ISO 8601 string representation of the datetime */ toString() { return this.toISOString(); } /** * Converts the datetime to a tuple */ toCompact() { return [this.#seconds, this.#nanoseconds]; } /** * Formats the datetime as an ISO 8601 string */ toISOString() { const totalMilliseconds = Number(this.#seconds) * 1e3 + Number(this.#nanoseconds) / 1e6; const date = new Date(totalMilliseconds); const isoString = date.toISOString(); if (this.#nanoseconds === 0n) return isoString; const nanoseconds = this.#nanoseconds.toString().padStart(9, "0"); const trimmed = nanoseconds.replace(/0+$/, ""); return isoString.replace(/\.\d{3}Z$/, `.${trimmed}Z`); } /** * Converts to JavaScript Date object */ toDate() { const milliseconds = Number(this.#seconds) * 1e3 + Math.floor(Number(this.#nanoseconds) / 1e6); return new Date(milliseconds); } /** * Parses a datetime string * * @param input Input string (ISO 8601 format) * @returns [seconds, nanoseconds] tuple */ static parseString(input) { const isoRegex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?Z?$/; const match = input.match(isoRegex); if (match) { const [, year, month, day, hour, minute, second, fraction] = match; const baseIsoString = `${year}-${month}-${day}T${hour}:${minute}:${second}Z`; const baseDate = new Date(baseIsoString); const baseTimestamp = baseDate.getTime(); if (Number.isNaN(baseTimestamp)) throw new InvalidDateError(baseDate); const seconds = BigInt(Math.floor(baseTimestamp / 1e3)); let nanoseconds = 0n; if (fraction) { const fractionLength = fraction.length; if (fractionLength <= 3) nanoseconds = BigInt(fraction.padEnd(3, "0")) * 1000000n; else if (fractionLength <= 6) nanoseconds = BigInt(fraction.padEnd(6, "0")) * 1000n; else nanoseconds = BigInt(fraction.padEnd(9, "0")); } return [seconds, nanoseconds]; } const timestamp = Date.parse(input); if (!Number.isNaN(timestamp)) { const seconds = BigInt(Math.floor(timestamp / 1e3)); const nanoseconds = BigInt(timestamp % 1e3 * 1e6); return [seconds, nanoseconds]; } throw new InvalidDateError(`Invalid datetime format: ${input}`); } /** * Adds a duration to this datetime * * @param duration The duration to add * @returns The new datetime instance */ add(duration) { const [durSeconds, durNanoseconds] = duration.toCompact(); let newSeconds = this.#seconds + (durSeconds || 0n); let newNanoseconds = this.#nanoseconds + (durNanoseconds || 0n); if (newNanoseconds >= SECOND) { newSeconds += 1n; newNanoseconds -= SECOND; } return new DateTime([newSeconds, newNanoseconds]); } /** * Subtracts a duration from this datetime * * @param duration The duration to subtract * @returns The new datetime instance */ sub(duration) { const [durSeconds, durNanoseconds] = duration.toCompact(); let newSeconds = this.#seconds - (durSeconds || 0n); let newNanoseconds = this.#nanoseconds - (durNanoseconds || 0n); if (newNanoseconds < 0n) { newSeconds -= 1n; newNanoseconds += SECOND; } return new DateTime([newSeconds, newNanoseconds]); } /** * Calculates the duration between two datetimes * * @param other The other datetime */ diff(other) { const totalThis = this.#seconds * SECOND + this.#nanoseconds; const totalOther = other.#seconds * SECOND + other.#nanoseconds; const diff = totalThis > totalOther ? totalThis - totalOther : totalOther - totalThis; return Duration.nanoseconds(diff); } /** * Compares this DateTime with another * * @param other The DateTime to compare with * @returns -1 if other is before, 0 if equal, 1 if other is after */ compare(other) { const a = this.nanoseconds; const b = other.nanoseconds; if (a < b) return -1; if (a > b) return 1; return 0; } /** * Total nanoseconds since Unix epoch */ get nanoseconds() { return this.#seconds * SECOND + this.#nanoseconds; } /** * Total microseconds since Unix epoch */ get microseconds() { return this.nanoseconds / MICROSECOND; } /** * Total milliseconds since Unix epoch */ get milliseconds() { return Number(this.nanoseconds / MILLISECOND); } /** * Seconds since Unix epoch */ get seconds() { return Number(this.#seconds); } /** * Creates a DateTime from nanoseconds since Unix epoch * * @param ns Nanoseconds value */ static fromEpochNanoseconds(ns) { const n = typeof ns === "bigint" ? ns : BigInt(Math.floor(ns)); return new DateTime([n / SECOND, n % SECOND]); } /** * Creates a DateTime from microseconds since Unix epoch * * @param µs Microseconds value */ static fromEpochMicroseconds(µs) { const n = typeof µs === "bigint" ? µs : BigInt(Math.floor(µs)); return DateTime.fromEpochNanoseconds(n * MICROSECOND); } /** * Creates a DateTime from milliseconds since Unix epoch * * @param ms Milliseconds value */ static fromEpochMilliseconds(ms) { const n = typeof ms === "bigint" ? ms : BigInt(Math.floor(ms)); return DateTime.fromEpochNanoseconds(n * MILLISECOND); } /** * Creates a DateTime from seconds since Unix epoch * * @param s Seconds value */ static fromEpochSeconds(s$1) { const n = typeof s$1 === "bigint" ? s$1 : BigInt(Math.floor(s$1)); return new DateTime([n, 0n]); } /** * Returns a new DateTime representing the current time */ static now() { if (DateTime.loadHr) { const diffNs = process.hrtime.bigint() - DateTime.loadHr.ns; const totalNanoseconds = DateTime.loadHr.ms * 1000000n + diffNs; const seconds$1 = totalNanoseconds / 1000000000n; const nanoseconds$1 = totalNanoseconds % 1000000000n; return new DateTime([seconds$1, nanoseconds$1]); } if (typeof performance !== "undefined" && performance.now && performance.timeOrigin) { const totalMilliseconds = performance.timeOrigin + performance.now(); const seconds$1 = BigInt(Math.floor(totalMilliseconds / 1e3)); const nanoseconds$1 = BigInt(Math.floor(totalMilliseconds % 1e3 * 1e6)); return new DateTime([seconds$1, nanoseconds$1]); } const now = Date.now(); const seconds = BigInt(Math.floor(now / 1e3)); const nanoseconds = BigInt(now % 1e3 * 1e6); return new DateTime([seconds, nanoseconds]); } /** * Returns a new DateTime representing the Unix epoch (1970-01-01T00:00:00Z) */ static epoch() { return new DateTime([0n, 0n]); } }; //#endregion //#region src/value/decimal.ts /** * A SurrealQL decimal number value with support for parsing, formatting, arithmetic, and high precision. */ var Decimal = class Decimal extends Value { #int; #frac; #scale; constructor(input) { super(); if (input instanceof Decimal) { this.#int = input.#int; this.#frac = input.#frac; this.#scale = input.#scale; } else if (typeof input === "bigint") { this.#int = input; this.#frac = 0n; this.#scale = 0; } else if (Array.isArray(input)) { let [int, frac, scale] = input; const maxFrac = 10n ** BigInt(scale); if (frac >= maxFrac) { int += frac / maxFrac; frac %= maxFrac; } this.#int = int; this.#frac = frac; this.#scale = scale; } else if (typeof input === "string" && /e/i.test(input)) { const dec = Decimal.fromScientificNotation(input); this.#int = dec.#int; this.#frac = dec.#frac; this.#scale = dec.#scale; } else { const str = input.toString().trim(); const isNegative = str.startsWith("-"); const clean = isNegative ? str.slice(1) : str; const [intStrRaw, fracStrRaw = ""] = clean.split("."); const safeInt = /^\d+$/.test(intStrRaw) ? intStrRaw : "0"; const safeFrac = /^\d+$/.test(fracStrRaw) ? fracStrRaw : "0"; const intStr = safeInt || "0"; const fracStr = safeFrac.padEnd(safeFrac.length || 1, "0"); const absInt = BigInt(intStr); const absFrac = BigInt(fracStr); this.#int = isNegative ? -absInt : absInt; this.#frac = isNegative ? -absFrac : absFrac; this.#scale = safeFrac.length; } } equals(other) { if (!(other instanceof Decimal)) return false; const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); const scale = Math.max(a.scale, b.scale); const aVal = a.value * 10n ** BigInt(scale - a.scale); const bVal = b.value * 10n ** BigInt(scale - b.scale); return aVal === bVal; } toJSON() { return this.toString(); } /** * @returns The canonical string representation of the decimal with * trailing zeros in fractional part trimmed */ toString() { const sign = this.#int < 0n || this.#frac < 0n ? "-" : ""; const absInt = this.#int < 0n ? -this.#int : this.#int; const absFrac = this.#frac < 0n ? -this.#frac : this.#frac; if (this.#scale === 0) return `${sign}${absInt}`; let fracStr = absFrac.toString().padStart(this.#scale, "0"); let end = fracStr.length; while (end > 0 && fracStr.charCodeAt(end - 1) === 48) end--; fracStr = fracStr.slice(0, end); return fracStr === "" ? `${sign}${absInt}` : `${sign}${absInt}.${fracStr}`; } /** Returns the integer part of the number */ get int() { return this.#int; } /** Returns the fractional part of the number */ get frac() { return this.#frac; } /** Returns the scale (number of decimal places) */ get scale() { return this.#scale; } /** * Adds another Decimal to this one * * @param other The Decimal to add * @returns A new Decimal representing the sum */ add(other) { const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); const scale = Math.max(a.scale, b.scale); const scaleDiffA = BigInt(scale - a.scale); const scaleDiffB = BigInt(scale - b.scale); const valA = a.value * 10n ** scaleDiffA; const valB = b.value * 10n ** scaleDiffB; const sum = valA + valB; const intPart = sum / 10n ** BigInt(scale); const fracPart = sum % 10n ** BigInt(scale); return new Decimal([ intPart, fracPart, scale ]); } /** * Subtracts another Decimal from this one * * @param other The Decimal to subtract * @returns A new Decimal representing the difference */ sub(other) { const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); const scale = Math.max(a.scale, b.scale); const factorA = 10n ** BigInt(scale - a.scale); const factorB = 10n ** BigInt(scale - b.scale); const valA = a.value * factorA; const valB = b.value * factorB; const result = valA - valB; const intPart = result / 10n ** BigInt(scale); const fracPart = result % 10n ** BigInt(scale); return new Decimal([ intPart, fracPart, scale ]); } /** * Multiplies this Decimal by another * * @param other The Decimal to multiply by * @returns A new Decimal representing the product */ mul(other) { const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); const result = a.value * b.value; const scale = a.scale + b.scale; const intPart = result / 10n ** BigInt(scale); const fracPart = result % 10n ** BigInt(scale); return new Decimal([ intPart, fracPart, scale ]); } /** * Divides this Decimal by another, with fixed precision * * @param other The Decimal to divide by * @returns A new Decimal representing the quotient */ div(other) { const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); if (b.value === 0n) throw new InvalidDecimalError("Division by zero"); const targetScale = 38; const scaleDiff = BigInt(targetScale + b.scale - a.scale); const scaledA = a.value * 10n ** scaleDiff; const result = scaledA / b.value; const intPart = result / 10n ** BigInt(targetScale); const fracPart = result % 10n ** BigInt(targetScale); return new Decimal([ intPart, fracPart, targetScale ]); } /** * Computes the remainder of this Decimal divided by another * * @param other The divisor Decimal * @returns A new Decimal representing the remainder */ mod(other) { const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); if (b.value === 0n) throw new InvalidDecimalError("Modulo by zero"); const scale = Math.max(a.scale, b.scale); const scaleDiffA = BigInt(scale - a.scale); const scaleDiffB = BigInt(scale - b.scale); const valA = a.value * 10n ** scaleDiffA; const valB = b.value * 10n ** scaleDiffB; const result = valA % valB; const intPart = result / 10n ** BigInt(scale); const fracPart = result % 10n ** BigInt(scale); return new Decimal([ intPart, fracPart, scale ]); } /** * Returns the absolute value of this Decimal * @returns A new Decimal with non-negative components */ abs() { return this.#int < 0n || this.#frac < 0n ? new Decimal([ this.#int < 0n ? -this.#int : this.#int, this.#frac < 0n ? -this.#frac : this.#frac, this.#scale ]) : this; } /** * Returns the negated value of this Decimal * @returns A new Decimal with inverted sign */ neg() { return new Decimal([ -this.#int, -this.#frac, this.#scale ]); } /** * Checks if the value is exactly zero * @returns True if both int and frac parts are zero */ isZero() { return this.#int === 0n && this.#frac === 0n; } /** * Checks if the value is negative * @returns True if negative */ isNegative() { return this.#int < 0n || this.#int === 0n && this.#frac < 0n; } /** * Compares this Decimal with another * * @param other The Decimal to compare with * @returns -1 if less, 0 if equal, 1 if greater */ compare(other) { const a = this.toBigIntWithScale(); const b = other.toBigIntWithScale(); const scale = Math.max(a.scale, b.scale); const aVal = a.value * 10n ** BigInt(scale - a.scale); const bVal = b.value * 10n ** BigInt(scale - b.scale); if (aVal < bVal) return -1; if (aVal > bVal) return 1; return 0; } /** * Rounds the Decimal to a fixed number of decimal places * * @param precision Number of digits to keep after the decimal point * @returns The new decimal instance */ round(precision) { if (precision < 0) throw new InvalidDecimalError("Precision must be >= 0"); const full = this.toBigIntWithScale(); if (this.#scale <= precision) { const factor$1 = 10n ** BigInt(precision - this.#scale); const newValue = full.value * factor$1; const intPart$1 = newValue / 10n ** BigInt(precision); const fracPart$1 = newValue % 10n ** BigInt(precision); return new Decimal([ intPart$1, fracPart$1, precision ]); } const factor = 10n ** BigInt(this.#scale - precision); const half = factor / 2n; const rounded = full.value >= 0n ? (full.value + half) / factor : (full.value - half) / factor; const intPart = rounded / 10n ** BigInt(precision); const fracPart = rounded % 10n ** BigInt(precision); return new Decimal([ intPart, fracPart, precision ]); } /** * Converts the number to fixed-point notation string * * @param precision Number of digits after the decimal point */ toFixed(precision) { const rounded = this.round(precision); const sign = rounded.int < 0n || rounded.frac < 0n ? "-" : ""; const absInt = rounded.int < 0n ? -rounded.int : rounded.int; if (precision === 0) return `${sign}${absInt}`; const absFrac = rounded.frac < 0n ? -rounded.frac : rounded.frac; const fracStr = absFrac.toString().padStart(precision, "0"); return `${sign}${absInt}.${fracStr}`; } /** * Converts the Decimal to a native JavaScript number * @returns A number approximation (may lose precision) */ toFloat() { return Number(this.toString()); } /** * Converts to bigint by truncating the fractional part * @returns An bigint approximation (may lose precision) */ toBigInt() { if (this.#int >= 0n) return this.#int; if (this.#frac !== 0n) return this.#int - 1n; return this.#int; } /** * Returns the raw parts of the Decimal * @returns An object with int, frac, and scale */ toParts() { return { int: this.#int, frac: this.#frac, scale: this.#scale }; } /** * Converts to scientific notation string (e.g., "1.23e4") */ toScientific() { if (this.isZero()) return "0e0"; const negative = this.isNegative(); const abs = negative ? this.neg() : this; const str = abs.toString(); const [intPart, fracPart = ""] = str.split("."); const raw$1 = (intPart + fracPart).replace(/^0+/, ""); const firstSig = raw$1.search(/[1-9]/); if (firstSig === -1) return "0e0"; let exponent; if (intPart !== "0") exponent = intPart.length - 1; else { let leading = 0; while (leading < fracPart.length && fracPart.charCodeAt(leading) === 48) leading++; exponent = -leading - 1; } let end = raw$1.length; while (end > 0 && raw$1.charCodeAt(end - 1) === 48) end--; const digits = raw$1.slice(0, end); const mantissa = digits.length > 1 ? `${digits[0]}.${digits.slice(1)}` : digits[0]; return `${negative ? "-" : ""}${mantissa}e${exponent}`; } /** * Parses a number in scientific notation into a Decimal * * @param input The scientific notation string */ static fromScientificNotation(input) { const trimmed = input.trim(); if (!/^[+-]?\d+(\.\d+)?[eE][+-]?\d+$/.test(trimmed)) throw new InvalidDecimalError(`Invalid scientific notation: ${input}`); const [baseStr, expStr] = trimmed.split(/[eE]/); const exp = Number.parseInt(expStr, 10); const negative = baseStr.startsWith("-"); const [intPart, fracPart = ""] = baseStr.replace(/^[-+]/, "").split("."); const raw$1 = intPart + fracPart; let start = 0; while (start < raw$1.length && raw$1.charCodeAt(start) === 48) start++; const digits = raw$1.slice(start) || "0"; const pointIndex = intPart.length; const newPointIndex = pointIndex + exp; let result; if (newPointIndex <= 0) result = `0.${"0".repeat(-newPointIndex)}${digits}`; else if (newPointIndex >= digits.length) result = digits + "0".repeat(newPointIndex - digits.length); else result = `${digits.slice(0, newPointIndex)}.${digits.slice(newPointIndex)}`; return new Decimal(negative ? `-${result}` : result); } toBigIntWithScale() { return { value: this.#int * 10n ** BigInt(this.#scale) + this.#frac, scale: this.#scale }; } }; //#endregion //#region src/value/file.ts /** * A SurrealQL file reference value. */ var FileRef = class FileRef extends Value { #bucket; #key; constructor(bucket, key) { super(); this.#bucket = bucket; this.#key = key.startsWith("/") ? key : `/${key}`; } get bucket() { return this.#bucket; } get key() { return this.#key; } equals(other) { if (!(other instanceof FileRef)) return false; return this.#bucket === other.#bucket && this.#key === other.#key; } toJSON() { return this.toString(); } toString() { return `${fmtInner(this.#bucket, true)}:${fmtInner(this.#key, false)}`; } }; function fmtInner(str, escapeSlash) { let result = ""; for (let i = 0; i < str.length; i++) { const char = str[i]; const code = str.charCodeAt(i); if (code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95 || code === 45 || code === 46 || !escapeSlash && code === 47) result += char; else result += `\\${char}`; } return result; } //#endregion //#region src/value/future.ts /** * An uncomputed SurrealQL future value. * * @deprecated Futures were removed in SurrealDB 3.0 */ var Future = class Future extends Value { #body; constructor(body) { super(); this.#body = body; } equals(other) { if (!(other instanceof Future)) return false; return this.#body === other.#body; } toJSON() { return this.toString(); } /** * @returns The uncomputed future notation */ toString() { return `<future> ${this.#body}`; } /** * The body of the future */ get body() { return this.#body; } }; //#endregion //#region src/value/geometry.ts /** * A SurrealQL geometry value. */ var Geometry = class Geometry extends Value { equals(other) { if (!(other instanceof Geometry)) return false; return this.is(other); } toString() { return JSON.stringify(this.toJSON()); } }; function f(num) { if (num instanceof Decimal) return num.toFloat(); return num; } /** * A SurrealQL point geometry value. */ var GeometryPoint = class GeometryPoint extends Geometry { point; constructor(point) { super(); if (point instanceof GeometryPoint) this.point = point.clone().point; else this.point = [f(point[0]), f(point[1])]; } toJSON() { return { type: "Point", coordinates: this.coordinates }; } get coordinates() { return this.point; } is(geometry) { if (!(geometry instanceof GeometryPoint)) return false; return this.point[0] === geometry.point[0] && this.point[1] === geometry.point[1]; } clone() { return new GeometryPoint([...this.point]); } }; /** * A SurrealQL line geometry value. */ var GeometryLine = class GeometryLine extends Geometry { line; constructor(line) { super(); this.line = line instanceof GeometryLine ? line.clone().line : line; } toJSON() { return { type: "LineString", coordinates: this.coordinates }; } get coordinates() { return this.line.map((g) => g.coordinates); } close() { if (!this.line[0].is(this.line.at(-1))) this.line.push(this.line[0]); } is(geometry) { if (!(geometry instanceof GeometryLine)) return false; if (this.line.length !== geometry.line.length) return false; for (let i = 0; i < this.line.length; i++) if (!this.line[i].is(geometry.line[i])) return false; return true; } clone() { return new GeometryLine(this.line.map((p) => p.clone())); } }; /** * A SurrealQL polygon geometry value. */ var GeometryPolygon = class GeometryPolygon extends Geometry { polygon; constructor(polygon) { super(); this.polygon = polygon instanceof GeometryPolygon ? polygon.clone().polygon : pol