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

@trajs/olap

v0.0.0-alpha.4

Published

Trajectories read as the rows an OLAP store aggregates them in, and the ClickHouse they are asked of.

Readme

@trajs/olap

A trajectory read as the rows an OLAP store aggregates it in, and the ClickHouse those rows are asked of: a server reached over HTTP, or the engine chdb runs in the same process.

  • Clickhouse — the client rows are written and queries are asked through (Clickhouse.Client, the ClickhouseClient of @effect/sql-clickhouse), stated for a server (Clickhouse.layer) or for the engine chdb embeds (Clickhouse.layerEmbedded).
  • Parts — the parts table: one row per part, the columns a query groups by, and the part itself as the JSON payload the rest is read off. Parts.create states the table, Parts.ingest writes a trajectory under the id it carries, and Parts.Row is a row.

Importing what a program kept

A trajectory is imported through the exchange that read it, so what is written is the parts the .trajs file carries rather than anything derived of them:

import { Exchange } from "@trajs/core/Exchange";
import { Clickhouse, Parts } from "@trajs/olap";
import { Effect } from "effect";

const importSession = (id: string) =>
  Effect.gen(function* () {
    const exchange = yield* Exchange;
    const loaded = yield* exchange.load(id);

    return yield* Parts.ingest(loaded.read(config));
  });

Effect.gen(function* () {
  yield* Parts.create();
  yield* importSession("sessions/01890a5d.trajs");
}).pipe(Effect.provide(Clickhouse.layerEmbedded()), Effect.runPromise);

config is what the trajectory is read with: the kits its events, metrics and response tools are read under. A trajectory read with no event kit holds no event parts, so none of them are written.

The rows of every trajectory are written under the id that trajectory carries, so the parts of one are the rows of one trajectory_id — and a trajectory read off a file is named by the uuid its load generated, since the bytes state no id of their own.

What the table is read for

Every column but the payload is a fact the part states of itself, so a query groups and filters without reaching into a document; the payload is the part as JSON states it, with the paths a query reads most stated as subcolumns of their own — a JSON column infers the type of every other path it holds, so a part of a kit this package has no schema for is still one a query can read.

The payload is the canonical JSON of the part rather than the bytes the exchange writes: the bytes of a media part are the base64 string JSON states them as rather than an object of a key per byte, a moment is an ISO 8601 string, and a field the part does not state is null.

SELECT
  session_id,
  countIf(tag = 'Prompt') AS prompts,
  sum(part.`response.usage.inputTokens.total`) AS input
FROM parts
GROUP BY session_id

A row's part names the response part it was produced as — text, tool-call, finish — beside the kind of part in tag, so the two are read together: tools by part.response.name, tokens by the response.usage totals of a finish part.