Skip to content

Releases: surrealdb/surrealdb.js

Release v2.0.8

Choose a tag to compare

@macjuul macjuul released this 21 Jul 16:17
64b8f10

What's Changed

  • fix(live): deliver KILLED notifications and end the subscription by @tobiemh in #650
  • Bump SDK version to 2.0.8 by @kearfy in #651

Full Changelog: v2.0.7...v2.0.8

Release v2.0.7

Choose a tag to compare

@itsezc itsezc released this 21 Jul 09:53
e037c28

What's Changed

  • fix(auth): omit undefined namespace/database for bearer signin by @tobiemh in #648
  • Bump version to v2.0.7 by @itsezc in #649

Full Changelog: v2.0.6...v2.0.7

Release v2.0.6

Choose a tag to compare

@tobiemh tobiemh released this 19 Jul 17:54
651d6c1

What's Changed

  • fix(live): sync isAlive with session/connection teardown (2.0.6) by @tobiemh in #646

Full Changelog: v2.0.5...v2.0.6

Release v2.0.5

Choose a tag to compare

@tobiemh tobiemh released this 19 Jul 09:54
83f27b6

What's Changed

  • Update readme and bump sqon version by @macjuul in #635
  • chore: route feature requests to the suggestions hub by @macjuul in #638
  • Disable request timeout for multipart requests by @macjuul in #639
  • chore(spectron): bump version to 1.0.0-alpha.5 by @macjuul in #640
  • fix(sqon): repair encode/decode visitor hooks in JsonCodec by @kearfy in #642
  • Bump @surrealdb/sqon version to 0.1.2 by @kearfy in #643
  • fix(live): await LIVE registration and buffer notifications to stop dropped events by @tobiemh in #644
  • chore(sdk): bump surrealdb to 2.0.5 by @tobiemh in #645

Full Changelog: v2.0.4...v2.0.5

Release v2.0.4

Choose a tag to compare

@macjuul macjuul released this 24 Jun 19:29

What's Changed

New Contributors

Full Changelog: v2.0.3...v2.0.4

Release v2.0.3

Choose a tag to compare

@macjuul macjuul released this 18 Mar 09:58
  • Added support for new export options
  • Added support for interpolating BoundQuery into the surql template tag literal
  • Fixed signature of patch functions (#580)

Release v2.0.2

Choose a tag to compare

@macjuul macjuul released this 09 Mar 11:19
d44b4e0
  • Support Blob to be passed to import()
  • Fixed support for older glibc versions
  • Fixed missing duplex property during import streaming
  • Fixed StringRecordId resulting in a wrong return type

Release v2.0.1

Choose a tag to compare

@macjuul macjuul released this 06 Mar 16:46
762cf2a
  • Added the ability to stream imports and exports
    • The .import() method now accepts a ReadableStream
    • The .export() method now provides a chainable .raw() method which returns a Response. This is useful when you require access to the underlying export stream.
  • Added an .exportModel() method for exporting SurrealML models
  • Fixed query duration stats not parsing correctly

Release v2.0.0

Choose a tag to compare

@macjuul macjuul released this 25 Feb 10:49

What's Changed

The SurrealDB JavaScript SDK v2 is the most significant update to the SDK to date, rebuilding core internals with a focus on ergonomics, flexibility, and developer experience. Key highlights include full support for SurrealDB 3.0, multi-session support, automatic token refreshing, client side transactions, a redesigned live query API, and a new query builder pattern that makes working with your data more intuitive than ever.

πŸ“¦ Welcome @surrealdb/wasm and @surrealdb/node!

The existing WebAssembly and Node.js SDK's have been rewritten, updated to support the 2.0 JavaScript SDK, and have been moved into the JavaScript SDK repository.

Going forward, the JS SDK, WASM SDK, and Node.js SDK will be published together, meaning embedded versions of SurrealDB will be kept up-to-date. Both the WASM and Node.js SDK versions will sync their major and minor components with SurrealDB, while the patch is still kept separate. This means a version such as 2.3.5 will use at least SurrealDB 2.3.0.

As an additional bonus, the WASM SDK now also supports running within a Web Worker. This allows you to offload computationally intensive database operations away from the main thread, while keeping your interface responsive.

Wasm

import { Surreal, createRemoteEngines } from "surrealdb";
import { createWasmEngines } from "@surrealdb/wasm";
import WorkerAgent from "@surrealdb/wasm/worker?worker";

const db = new Surreal({
    engines: {
        ...createRemoteEngines(),
        ...createWasmEngines(),
        // or for Web Worker based engines
        ...createWasmWorkerEngines({
            createWorker: () => new WorkerAgent()
        })
    },
});

Node.js (+ Bun.js & Deno)

import { Surreal, createRemoteEngines } from "surrealdb";
import { createNodeEngines } from "@surrealdb/node";

const db = new Surreal({
    engines: {
        ...createRemoteEngines(),
        ...createNodeEngines(),
    },
});

βœ‰οΈ Official event listeners

The original SDK allowed for the listening of events through the leaked internal surreal.emitter field. Instead, the updated SDK provides a type-safe surreal.subscribe() function allowing you to listen to events. Invoking .subscribe() now also returns a cleanup function, which unsubscribes the listener when called.

Example

// Subscribe to events
const unsub = surreal.subscribe("connected", () => {
    ...
});

// Unsubscribe
unsub();

🏹 Access internal state

Additional getters have been added to retrieve internal state from the Surreal instance, such as

  • surreal.namespace and surreal.database to obtain the selected NS and DB
  • surreal.params to obtain defined connection params
  • surreal.accesToken and surreal.refreshToken to obtain authentication tokens

Example

await surreal.use({ namespace: surreal.namespace, database: "other-db" });

πŸ”„ Automatic token refreshing

The SDK will now automatically restore or renew authentication when your access token expires or the connection reconnects. When refresh tokens are available, these will be used and exchanged for a fresh token pair, otherwise the SDK falls back to re-using the provided authentication details, or firing an auth event for custom handling. (read more)

In situations where authentication may be provided asynchronously you can now pass a callable function to the authentication property.

Example

const surreal = new Surreal();

await surreal.connect("http://example.com", {
    namespace: "test",
    database: "test",
    renewAccess: true, // default true
    authentication: () => ({
        username: "foo",
        password: "bar",
    })
});

πŸ”‘ Multi-session support

You can now create multiple isolated sessions within a single connection, each with their own namespace, database, variables, and authentication state. The SDK allows you to construct entirely new sessions at any time, or fork an existing session and reuse its state.

Simple example

// Create a new session
const session = await surreal.newSession();

// Use the session
session.signin(...);

// Dispose the session
await session.closeSession();

Forking sessions

const freshSession = await surreal.newSession();

// Clone a session including namespace, database, variables, and auth state
const forkedSession = await freshSession.forkSession();

Await using

await using session = await surreal.newSession();

// JavaScript will automatically close the session at the end of the current scope

πŸ“£ Redesigned live query API

The live query functions provided by the Surreal class have been redesigned to feel more intuitive and natural to use. Additionally, live select queries can now be automatically restarted once the driver reconnects.

The record ID will now also be provided as third argument to your handlers, allowing you to determine the record when listening to patch updates.

Example

// Construct a new live subscription
const live = await surreal.live(new Table("users"));

// Listen to changes
live.subscribe((action, result, record) => {
     ...
});

// Alternatively, iterate messages
for await (const { action, value } of live) {
    ...
}

// Kill the query and stop listening
live.kill();

// Create an unmanaged query from an existing id
const [id] = await surreal.query("LIVE SELECT * FROM users");
const live = await surreal.liveOf(id);

❗ Improved parameter explicitness

Query functions now no longer accept strings as table names. Instead, you must explicitly use the Table class to represent tables. This avoids situations where record ids may be accidentally passed as table names, resulting in confusing results.

Example

// tables.ts
const usersTable = new Table("users");
const productsTable = new Table("products");
...

// main.ts
await surreal.select(usersTable);

πŸ”§ Query builder pattern

In order to provide a more transparent and ergonomic way to configure individual RPC calls, a new builder pattern has been introduced allowing the optional chaining of functions on RPC calls. All existing query functions have received chainable functions to accomplish common tasks such as filtering, limiting, and fetching.

As a side affect, both update and upsert no longer take contents as second argument, instead, you can choose whether you want to .content(), .merge(), .replace(), or .patch() your record(s).

Example

// Select
const record = await db.select(id)
    .fields("age", "firstname", "lastname")
    .fetch("foo");

// Update
await db.update(record).merge({
    hello: "world"
});

πŸ—Ό Query method overhaul

The .query() function has been overhauled to support a wider set of functionality, including the ability to pick response indexes, automatically jsonify results, and stream responses.

Example

// Execute a query and return results
const [user] = await db.query<[User]>("SELECT * FROM user:foo");

// Collect specific results
const [foo, bar] = await db.query("LET $foo = ...; LET $bar = ...; SELECT * FROM $foo; SELECT * FROM $bar")
    .collect<[User, Product]>(2, 3);

// Jsonify responses
const [products] = await db.query<[Product[]]>("SELECT * FROM product").json();

// Response objects
const responses = await db.query<[Product[]]>("SELECT * FROM product").responses(); 

// Stream responses
const stream = surreal.query(`SELECT * FROM foo`).stream();

for await (const frame of stream) {
    if (frame.isValue<Foo>()) {
        //  Process a single value with frame.value typed Foo
    } else if (frame.isDone()) {
        // Handle completion and access stats with frame.stats
    } else if (frame.isError()) {
        // Handle error frame.error
    }
}

Note

SurrealDB currently does not yet support the streaming of individual records, however this API will provide the base for streamed responses in a future update. It is fully backwards compatible with the existing versions of SurrealDB and is now the only way to obtain query stats.

🎨 Expressions API

In order to facilitate working with the .where() function found on multiple query methods, we introduced a new Expressions API to ease the process of composing dynamic expressions. This new API integrates seamlessly with the surql template tag, allowing you to insert param-safe expressions anywhere.

Example

const checkActive = true;

// Query method
await db.select(userTable).where(eq("active", checkActive));

// Custom query
await db.query(surql`SELECT * FROM user WHERE ${eq("active", checkActive)}`);

// Expressions even allow raw insertion
await db.query(surql`SELECT * FROM user ${raw("WHERE active = true")}`);

You can also parse expressions into a string manually using the expr() function

const result: BoundQuery = expr(
    or(
        eq("foo", "bar"),
        false && eq("hello", "world"),
        eq("alpha", "beta"),
        and(
            inside("hello", ["hello"]),
            between("number", 1, 10)
        )
    )
);

πŸ”­ Value encode/decode visitor API

To support advanced use cases and situations where additional processing must be done on SurrealDB value classes, you can now specify a value encode or decode visitor callback in the Surreal constructor. These functions will be invoked for each value received or sent to the engine, and allow you to modify or wrap values before they are collected in responses.

Example

const surreal = new Surreal({
	codecOptions: {
		valueDecodeVisitor(value) {
			if (value instanceof Record...
Read more

Release v2.0.0-beta.2

Release v2.0.0-beta.2 Pre-release
Pre-release

Choose a tag to compare

@macjuul macjuul released this 20 Feb 22:51

Changes since the previous version

  • Fix WebWorker Vite compatibility (#507)
  • Bump the minimum version to 2.1.0
  • Update package exports configuration

Full changelog

πŸ“¦ Welcome @surrealdb/wasm and @surrealdb/node!

The existing WebAssembly and Node.js SDK's have been rewritten, updated to support the 2.0 JavaScript SDK, and have been moved into the JavaScript SDK repository.

Going forward, the JS SDK, WASM SDK, and Node.js SDK will be published together, meaning embedded versions of SurrealDB will be kept up-to-date. Both the WASM and Node.js SDK versions will sync their major and minor components with SurrealDB, while the patch is still kept separate. This means a version such as 2.3.5 will use at least SurrealDB 2.3.0.

As an additional bonus, the WASM SDK now also supports running within a Web Worker. This allows you to offload computationally intensive database operations away from the main thread, while keeping your interface responsive.

Wasm

import { Surreal, createRemoteEngines } from "surrealdb";
import { createWasmEngines } from "@surrealdb/wasm";
import WorkerAgent from "@surrealdb/wasm/worker?worker";

const db = new Surreal({
    engines: {
        ...createRemoteEngines(),
        ...createWasmEngines(),
        // or for Web Worker based engines
        ...createWasmWorkerEngines({
            createWorker: () => new WorkerAgent()
        })
    },
});

Node.js (+ Bun.js & Deno)

import { Surreal, createRemoteEngines } from "surrealdb";
import { createNodeEngines } from "@surrealdb/node";

const db = new Surreal({
    engines: {
        ...createRemoteEngines(),
        ...createNodeEngines(),
    },
});

βœ‰οΈ Official event listeners

The original SDK allowed for the listening of events through the leaked internal surreal.emitter field. Instead, the updated SDK provides a type-safe surreal.subscribe() function allowing you to listen to events. Invoking .subscribe() now also returns a cleanup function, which unsubscribes the listener when called.

Example

// Subscribe to events
const unsub = surreal.subscribe("connected", () => {
    ...
});

// Unsubscribe
unsub();

🏹 Access internal state

Additional getters have been added to retrieve internal state from the Surreal instance, such as

  • surreal.namespace and surreal.database to obtain the selected NS and DB
  • surreal.params to obtain defined connection params
  • surreal.accesToken and surreal.refreshToken to obtain authentication tokens

Example

await surreal.use({ namespace: surreal.namespace, database: "other-db" });

πŸ”„ Automatic token refreshing

The SDK will now automatically restore or renew authentication when your access token expires or the connection reconnects. When refresh tokens are available, these will be used and exchanged for a fresh token pair, otherwise the SDK falls back to re-using the provided authentication details, or firing an auth event for custom handling. (read more)

In situations where authentication may be provided asynchronously you can now pass a callable function to the authentication property.

Example

const surreal = new Surreal();

await surreal.connect("http://example.com", {
    namespace: "test",
    database: "test",
    renewAccess: true, // default true
    authentication: () => ({
        username: "foo",
        password: "bar",
    })
});

πŸ”‘ Multi-session support

You can now create multiple isolated sessions within a single connection, each with their own namespace, database, variables, and authentication state. The SDK allows you to construct entirely new sessions at any time, or fork an existing session and reuse its state.

Simple example

// Create a new session
const session = await surreal.newSession();

// Use the session
session.signin(...);

// Dispose the session
await session.closeSession();

Forking sessions

const freshSession = await surreal.newSession();

// Clone a session including namespace, database, variables, and auth state
const forkedSession = await freshSession.forkSession();

Await using

await using session = await surreal.newSession();

// JavaScript will automatically close the session at the end of the current scope

πŸ“£ Redesigned live query API

The live query functions provided by the Surreal class have been redesigned to feel more intuitive and natural to use. Additionally, live select queries can now be automatically restarted once the driver reconnects.

The record ID will now also be provided as third argument to your handlers, allowing you to determine the record when listening to patch updates.

Example

// Construct a new live subscription
const live = await surreal.live(new Table("users"));

// Listen to changes
live.subscribe((action, result, record) => {
     ...
});

// Alternatively, iterate messages
for await (const { action, value } of live) {
    ...
}

// Kill the query and stop listening
live.kill();

// Create an unmanaged query from an existing id
const [id] = await surreal.query("LIVE SELECT * FROM users");
const live = await surreal.liveOf(id);

❗ Improved parameter explicitness

Query functions now no longer accept strings as table names. Instead, you must explicitly use the Table class to represent tables. This avoids situations where record ids may be accidentally passed as table names, resulting in confusing results.

Example

// tables.ts
const usersTable = new Table("users");
const productsTable = new Table("products");
...

// main.ts
await surreal.select(usersTable);

πŸ”§ Query builder pattern

In order to provide a more transparent and ergonomic way to configure individual RPC calls, a new builder pattern has been introduced allowing the optional chaining of functions on RPC calls. All existing query functions have received chainable functions to accomplish common tasks such as filtering, limiting, and fetching.

As a side affect, both update and upsert no longer take contents as second argument, instead, you can choose whether you want to .content(), .merge(), .replace(), or .patch() your record(s).

Example

// Select
const record = await db.select(id)
    .fields("age", "firstname", "lastname")
    .fetch("foo");

// Update
await db.update(record).merge({
    hello: "world"
});

πŸ—Ό Query method overhaul

The .query() function has been overhauled to support a wider set of functionality, including the ability to pick response indexes, automatically jsonify results, and stream responses.

Example

// Execute a query and return results
const [user] = await db.query<[User]>("SELECT * FROM user:foo");

// Collect specific results
const [foo, bar] = await db.query("LET $foo = ...; LET $bar = ...; SELECT * FROM $foo; SELECT * FROM $bar")
    .collect<[User, Product]>(2, 3);

// Jsonify responses
const [products] = await db.query<[Product[]]>("SELECT * FROM product").json();

// Response objects
const responses = await db.query<[Product[]]>("SELECT * FROM product").responses(); 

// Stream responses
const stream = surreal.query(`SELECT * FROM foo`).stream();

for await (const frame of stream) {
    if (frame.isValue<Foo>()) {
        //  Process a single value with frame.value typed Foo
    } else if (frame.isDone()) {
        // Handle completion and access stats with frame.stats
    } else if (frame.isError()) {
        // Handle error frame.error
    }
}

Note

SurrealDB currently does not yet support the streaming of individual records, however this API will provide the base for streamed responses in a future update. It is fully backwards compatible with the existing versions of SurrealDB and is now the only way to obtain query stats.

🎨 Expressions API

In order to facilitate working with the .where() function found on multiple query methods, we introduced a new Expressions API to ease the process of composing dynamic expressions. This new API integrates seamlessly with the surql template tag, allowing you to insert param-safe expressions anywhere.

Example

const checkActive = true;

// Query method
await db.select(userTable).where(eq("active", checkActive));

// Custom query
await db.query(surql`SELECT * FROM user WHERE ${eq("active", checkActive)}`);

// Expressions even allow raw insertion
await db.query(surql`SELECT * FROM user ${raw("WHERE active = true")}`);

You can also parse expressions into a string manually using the expr() function

const result: BoundQuery = expr(
    or(
        eq("foo", "bar"),
        false && eq("hello", "world"),
        eq("alpha", "beta"),
        and(
            inside("hello", ["hello"]),
            between("number", 1, 10)
        )
    )
);

πŸ”­ Value encode/decode visitor API

To support advanced use cases and situations where additional processing must be done on SurrealDB value classes, you can now specify a value encode or decode visitor callback in the Surreal constructor. These functions will be invoked for each value received or sent to the engine, and allow you to modify or wrap values before they are collected in responses.

Example

const surreal = new Surreal({
	codecOptions: {
		valueDecodeVisitor(value) {
			if (value instanceof RecordId) {
				return new RecordId("foo", "bar");
			}

			return value;
		},
	},
});

...

const [result] = await surreal.query(`RETURN hello:world`).collect<[RecordId]>();

console.log(result); // foo:bar

πŸ‘€ Diagnostics API

The Diagnostics API a...

Read more