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

@datar-platform/knowledge-kit

v0.1.0-alpha.3

Published

Drop-in Documents, Knowledge Base and Ask surfaces for the Datar platform — upload, indexing, cited answers, React hooks and Next.js route handlers on top of @datar-platform/sdk.

Readme

@datar-platform/knowledge-kit

Documents, Knowledge Base and Ask, on top of @datar-platform/sdk.

Upload a file, watch it index, and answer questions from it with citations that point at the exact indexed passage. The SDK gives you the calls; this gives you the parts every front end would otherwise rewrite: upload-and-wait, status that tells the truth, answer rendering with clickable citations, source cards, a reasoning trace, React hooks and Next.js route handlers.

Ships behaviour, not design. There is no CSS here and no component library.

pnpm add @datar-platform/knowledge-kit

Setup

Two environment variables, server-side only:

DATAR_URL=https://develop-af.datar.co.za   # gateway origin
DATAR_TOKEN=dt_...                         # org-scoped API token

DATAR_DEV_SESSION_TOKEN is accepted as a fallback name.

The credential

Use an organisation-scoped API token, not a personal session — a session expires in hours, a token does not. Mint one with v2.auth.apiToken.create, passing the organisation and the three scopes this kit needs:

{
  "name": "my-app service token",
  "organizationId": "<your org id>",
  "expiresInDays": 90,
  "scopes": ["api.ai.kb.read", "api.ai.kb.ingest", "api.ai.invoke"]
}

Scopes are enforced: a token without api.ai.kb.ingest can read and ask but cannot upload or re-index, which is the honest way to give a front end read-only access. A token with no scopes is refused everywhere.

Next.js in five files

// lib/knowledge.ts
import { createKnowledgeClientFromEnv } from "@datar-platform/knowledge-kit";
export const knowledge = createKnowledgeClientFromEnv();
// app/api/documents/route.ts
import { createDocumentsRoute } from "@datar-platform/knowledge-kit/next";
import { knowledge } from "~/lib/knowledge";
export const { GET, POST, dynamic } = createDocumentsRoute(knowledge);
// app/api/documents/[fileId]/index/route.ts   → createDocumentIndexRoute
// app/api/documents/[fileId]/chunks/route.ts  → createDocumentChunksRoute
// app/api/ask/route.ts                        → createAskRoute      (also export maxDuration)
// app/api/threads/route.ts                    → createThreadsRoute
// app/api/threads/[sessionId]/route.ts        → createThreadRoute

Then in a client component:

"use client";
import { useAsk, useDocuments } from "@datar-platform/knowledge-kit/react";

export function Hub() {
  const { documents, upload, uploading } = useDocuments();
  const { messages, ask, busy } = useAsk();
  // documents[n].kbStatus is "complete" once it is citable;
  // messages carry rendered html, named sources and the trace.
}

Every route answers { ok: true, data } or { ok: false, error: { message, code } }, and the hooks throw KnowledgeFetchError carrying that message and code — so an expired credential is distinguishable from a failed upload without parsing strings.

Without a framework

import { createKnowledgeClient } from "@datar-platform/knowledge-kit";

const knowledge = createKnowledgeClient({ token, baseUrl });

const { fileId } = await knowledge.uploadDocument({ fileName, mimeType, body });
await knowledge.waitForIndexed(fileId);

const answer = await knowledge.ask({ question: "What is the tenant concentration?" });
answer.html;       // escaped HTML, [n] rendered as <sup class="cite" data-cite="n">
answer.sources;    // one card per citation, named after its document
answer.reasoning;  // trace built only from values the platform returned

Render citations by listening for clicks on [data-cite] and showing answer.sources[n - 1].

Entry points

| Import | Contents | Runs | | --- | --- | --- | | @datar-platform/knowledge-kit | createKnowledgeClient, documents, ask, threads | Server only — holds the credential | | .../format | answerToHtml, citationsToSources, buildTrace, labels | Anywhere; pure, no network | | .../react | useDocuments, useAsk, useThreads, kitFetch | Browser | | .../next | The six route-handler factories | Server |

Safety

Model output is escaped before it is turned into HTML, and a [n] marker becomes a citation badge only when citation n exists. An answer cannot inject markup or fabricate a source number.

Platform notes

No workarounds: every call goes through a real SDK method, and the behaviours that used to need patching around are fixed at their source.

  • Index status completes server-side — the gateway reconciles a pending job before it answers a listing (#274). listDocuments({ reconcile: true }) additionally asks for reconciliation, and the polling paths use it so the kit stays correct against an older gateway.
  • Citations carry their own file name and type (#278). If a citation arrives unnamed — an older gateway — ask fetches the document list once to label it, and otherwise never makes that call.
  • syncStatus and getFileChunks are SDK methods as of 0.3.0-alpha.9 (#277).

Still open, and worth knowing before you design around them:

| Gap | Issue | Effect | | --- | --- | --- | | ~100-token chunks split structured records | #283 | An attribute can be attributed to a neighbouring record in a long table or register. The most important one to follow. | | query takes no answer instructions | #280 | Every product inherits the same generic answer voice. | | No streaming here | — | queryStream needs AppSync. Expect 15 to 30 seconds per answer and design the waiting state for it. |

Converting an existing front end

RUNBOOK.md walks through it: mint a credential, mount the routes, swap mock arrays for the hooks, and the end-to-end checks worth doing by hand the first time.

Tests

pnpm -F @datar-platform/knowledge-kit test        # unit + contract, no network
DATAR_E2E=1 pnpm -F @datar-platform/knowledge-kit test:e2e

The contract tests pin every call to its exact tRPC path and verb, so drift between this kit and the router fails here rather than in a running app. The live suite uploads a fixture, waits for indexing, asks a question and asserts that each citation quotes text actually stored in the document — then asks something the document cannot answer and checks it refuses.

Follow-up: wiring these into .github/workflows/ci.yml (alongside the existing pnpm -F @datar-platform/sdk test step) needs a token with the workflow scope, so it has not been done here.