npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@helix-db/helix-db

v3.0.4

Published

TypeScript library for working with HelixDB

Readme

@helix-db/helix-db

TypeScript query DSL and client for HelixDB. The SDK emits the same query JSON AST as the Rust, Go, and Python SDKs and can execute it over HTTP or against an embedded database.

Quick Start

import { Client, Predicate, defineParams, g, param, readBatch } from "@helix-db/helix-db";

const params = defineParams({
  tenantId: param.string(),
  limit: param.i64(),
});

function findUsers(p = params) {
  return readBatch()
    .varAs("users", g().nWithLabel("User").where(Predicate.eq("tenantId", p.tenantId)).limit(p.limit).valueMap(["$id", "name"]))
    .returning(["users"]);
}

const request = findUsers().toQueryRequest(params, {
  tenantId: "acme",
  limit: 25n,
});
const rows = await new Client("http://localhost:6969").query(request).send();

Query builders are normal functions returning ReadBatch or WriteBatch. The request helpers are:

findUsers().toQueryRequest(params, { tenantId: "acme", limit: 25n });
findUsers().toQueryJson(params, { tenantId: "acme", limit: 25n });
findUsers().toQueryBytes(params, { tenantId: "acme", limit: 25n });

All requests execute through POST /v2/query. The SDK does not expose stored routes, registration, or query-bundle APIs.

Clients

Server mode uses the built-in global fetch:

const client = Client.server("https://cluster.helix-db.com").withApiKey("hx_secret");
const result = await client.query<MyResponse>(request).send();

Advanced server-only headers are available from requestBuilder<R>():

await client.requestBuilder<MyResponse>().writerOnly().query(request).send();
await client.requestBuilder<void>().warmOnly().query(request).send();
await client.requestBuilder<MyResponse>().shouldAwaitDurability(false).query(request).send();

warmOnly() is read-only. It sends the ordinary read with X-Helix-Warm: true; Helix Cloud fans it out to every eligible backend and returns 204 No Content with no query payload after at least one target succeeds. Chain writerOnly() before warmOnly() to warm only the authoritative writer. Warm writes return 400 Bad Request before execution. A standalone local warm read can return its normal query payload instead.

Embedded mode uses @helix-db/helix-db-embedded:

npm install @helix-db/helix-db @helix-db/helix-db-embedded
const client = await Client.embedded({ kind: "inMemory", database: "app" });
try {
  const result = await client.query<MyResponse>(request).send();
} finally {
  await client.close();
}

Pass a cache profile as the second argument when the default memory cache is not appropriate. Vector-memory-only mode disables SlateDB and object-store caches; it does not disable canonical persistence.

const client = await Client.embedded(
  { kind: "disk", root: "/data/helix", database: "app" },
  { vectorMemoryBytes: 256 * 1024 * 1024, mode: { kind: "vectorMemoryOnly" } },
);

Client.embeddedReader(...) opens an existing disk or object-storage database read-only. Server request options are rejected in embedded mode.

Set HELIXDB_EMBEDDED_NODE_PACKAGE to load a compatible native package from a different module specifier. The former HELIXDB_UNIFFI_NODE_PACKAGE name remains supported as a deprecated compatibility alias.

HelixError.kind distinguishes Network, Remote, Serialization, InvalidUrl, InvalidRequest, EmbeddedUnavailable, and Embedded failures.

Parameter Schemas

Supported schemas are param.bool(), param.i64(), param.f64(), param.f32(), param.string(), param.dateTime(), param.bytes(), param.value(), param.object(), param.object(inner), and param.array(inner).

Parameter values and types are inserted into the request together. Unknown parameters and invalid values are rejected before execution. JSON requests cannot represent bytes parameters, so param.bytes() conversion returns QueryError.UnsupportedBytesParameter.

Unnamed requests serialize query_name: null. Pass an optional name for logs and diagnostics:

findUsers().toQueryJson(params, { tenantId: "acme", limit: 25n }, { queryName: "find_users" });

Predicates

Predicate.eq, neq, gt, gte, lt, lte, and between accept literal values or expressions. Use parameter helpers for request-specific values and Predicate.compare(...) for arbitrary expression comparisons.

g().nWithLabel("User").where(Predicate.eqParam("email", "email"));
g()
  .nWithLabel("User")
  .where(Predicate.eq("email", Expr.param("email")));

Traversal-scoped text search

Use textSearch(...) after a node or edge traversal to rank only the IDs in that current stream. This is an exact BM25 prefilter, not a post-search limit: the result is the same as searching the selected tenant partition exhaustively, intersecting with the unique input IDs, and taking the deterministic top k.

BM25 statistics still come from the full tenant partition.

import { Expr, Predicate, PropertyInput, PropertyProjection, defineParams, g, param, readBatch } from "@helix-db/helix-db";

const searchParams = defineParams({
  tenantId: param.string(),
  query: param.string(),
  limit: param.i64(),
});

function searchVisibleDocuments(p = searchParams) {
  return readBatch()
    .varAs(
      "documents",
      g()
        .nWithLabel("Document")
        .where(Predicate.eq("tenantId", p.tenantId))
        .textSearchWith("Document", "body", PropertyInput.param("query"), Expr.param("limit"), PropertyInput.param("tenantId"))
        .project([PropertyProjection.renamed("$id", "id"), PropertyProjection.renamed("$score", "score"), PropertyProjection.new("title")]),
    )
    .returning(["documents"]);
}

Use the literal form as .textSearch("Document", "body", "graph databases", 10, "acme"). The same textSearch and textSearchWith methods work on edge streams and emit TextSearchEdgesWithin. Source-level textSearchNodes[With] and textSearchEdges[With] remain whole-partition searches.

Restricted results contain unique input IDs, return at most k, and order by $score descending then entity ID ascending. The selected input row keeps its bindings, path, and sack. An empty input returns without opening the text index. More than 1,000,000 unique candidates is a query error. For a tenant-scoped index, pass the same tenant partition used to build the candidate stream.

Row Bindings

Bindings retain correlated values across multi-hop traversals:

const query = readBatch()
  .varAs(
    "dependencies",
    g()
      .nWithLabel("Service")
      .bind("service")
      .out("ROUTES_TO")
      .bind("pod")
      .optional(sub().in("CREATES").bind("deployment"))
      .projectDistinctBindings([
        BindingProjection.binding("service", "$id", "service_id"),
        BindingProjection.coalesce(
          [BindingProjection.bindingRef("deployment", "$id"), BindingProjection.bindingRef("pod", "$id")],
          "workload_id",
        ),
      ]),
  )
  .returning(["dependencies"]);

Binding projections support stored properties and virtual fields such as $id, $label, $from, $to, $distance, and $score.

Numbers and Datetimes

Use bigint or i64(...) for integers outside JavaScript's safe range. Query responses preserve those integers as bigint.

g().n(9223372036854775807n);
PropertyValue.i64(9223372036854775807n);

Use stringifyJson or request toJsonString() when values may contain bigint. DateTime stores epoch milliseconds and renders parameters as UTC RFC3339 strings with millisecond precision.

DateTime.fromMillis(-1).toRfc3339(); // 1969-12-31T23:59:59.999Z

Native graph algorithms

const selection = new GraphSelection({
  nodeTraversal: g().nWhere(SourcePredicate.hasKey("$id")),
  edgeTraversal: g().eWhere(SourcePredicate.hasKey("$id")),
  direction: "directed",
  allowFullScan: true,
});
const graph = await client.graph(selection);
const scores = await graph.betweennessCentrality({ mode: "auto", exactThrough: 1000, sampleCount: 100, seed: 42 });

The load is one normal query. The returned immutable native object runs all accessors, algorithms, subgraphs, and transforms in Rust without additional reads. CPU-heavy work therefore runs outside the JavaScript event loop.

API Reference

The public entry point exports scalar helpers, AST types, traversal builders, batch builders, query request helpers, graph helpers, and the server/embedded client. The wire contract follows Rust serde names while TypeScript builders use camel case.