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

@splyntra/sdk

v2.3.0

Published

Splyntra TypeScript SDK - Agent observability & security, built on OpenTelemetry

Readme


Compatible with Node.js ≥ 18, TypeScript or plain JavaScript, ESM or CommonJS.

Installation

npm install @splyntra/sdk
pnpm add @splyntra/sdk
# or
yarn add @splyntra/sdk

Getting Started

Initialize once at process start. The instrument array enables automatic tracing for supported frameworks — no per-call changes required.

import { Splyntra } from "@splyntra/sdk";

new Splyntra({
  apiKey: process.env.SPLYNTRA_API_KEY ?? "splyntra_dev_key",
  project: "my-app",
  endpoint: process.env.SPLYNTRA_ENDPOINT ?? "https://ingest.splyntra.com", // or http://localhost:4318 locally
  framework: "langgraph",
  instrument: ["openai", "langgraph"],
});

// Use the OpenAI SDK / LangGraph.js as usual — spans are captured automatically.

CommonJS:

const { Splyntra } = require("@splyntra/sdk");

new Splyntra({
  apiKey: "splyntra_dev_key",
  project: "my-app",
  instrument: ["openai"],
});

Manual Instrumentation

For custom functions beyond auto-instrumented frameworks, two approaches are available.

Function Wrappers (TypeScript & JavaScript)

import { wrapAgent, wrapTool, wrapLLM } from "@splyntra/sdk";

const readCustomer = wrapTool(
  async (id: string) => db.get(id),
  "crm.read",
);

const callLLM = wrapLLM(
  async (prompt: string) =>
    openai.chat.completions.create({ model: "gpt-4o", messages: [{ role: "user", content: prompt }] }),
  "gpt-4o",
  "openai",
);

const runAgent = wrapAgent(
  async (query: string) => {
    const customer = await readCustomer("42");
    return callLLM(query);
  },
  "support_agent",
  "refund",
);

await runAgent("refund my order");

wrapLLM reads token usage from a returned object with a usage field ({ prompt_tokens, completion_tokens }) for cost analytics.

Decorators (TypeScript only)

Requires "experimentalDecorators": true in tsconfig.json:

import { traceAgent, traceTool, traceLLM } from "@splyntra/sdk";

class SupportAgent {
  @traceAgent("support_agent", "refund")
  async run(query: string) { /* ... */ }

  @traceTool("crm.read")
  async readCustomer(id: string) { /* ... */ }

  @traceLLM("gpt-4o", "openai")
  async complete(prompt: string) { /* ... */ }
}

Configuration

| Option | Default | Description | |-------------------|-------------------------|------------------------------------------------| | apiKey | required | Splyntra API key (sent as Bearer token) | | project | required | Project slug | | endpoint | http://localhost:4318 | Collector base URL | | environment | development | Deployment environment label | | serviceName | value of project | OpenTelemetry service.name resource | | framework | — | Framework label shown on the Agents page | | redactByDefault | true | Strip secrets from spans before export | | instrument | [] | Frameworks to auto-instrument | | guard | "off" | Inline guardrail: "off", "monitor", "block" | | guardFailOpen | true | On a guard-service error, proceed vs block |

Client-Side Redaction

High-confidence secrets (AWS keys, JWTs, bearer tokens, API keys) are stripped from span attributes before they leave your process. The collector applies a second pass on ingest as defence-in-depth.

Disable with redactByDefault: false (not recommended for production).

Inline Guard

Run a fast, high-confidence check before a model/tool call completes so you can block or redact rather than only detect after the fact. Enable it at init with guard: "monitor" (log only) or guard: "block" (throws on a high-confidence prompt-injection match); auto-instrumented frameworks call it in a pre-flight hook.

import { Splyntra, SplyntraBlocked } from "@splyntra/sdk";

new Splyntra({ apiKey: "...", project: "my-app", guard: "block", instrument: ["openai"] });

try {
  await runAgent(userInput);
} catch (e) {
  if (e instanceof SplyntraBlocked) handleBlocked(e); // high-precision injection pre-flight
  else throw e;
}

Secrets are redacted in place; only high-precision injection signatures block, so benign role-play prompts pass through (deep analysis stays on the async detector path). guardFailOpen: true (default) proceeds if the guard service is unreachable — set false to fail closed.

Graceful Shutdown

Spans are batched and flushed asynchronously. For short-lived scripts, flush before exit:

const splyntra = new Splyntra({ apiKey: "...", project: "my-app" });

// ...work...

await splyntra.shutdown();

The SDK also registers handlers on SIGTERM and SIGINT for automatic flush.

Supported Frameworks

| Framework | instrument name | Span mapping | |----------------|-------------------|--------------------------------------------------| | OpenAI SDK | openai | Chat completions → llm_call spans | | Anthropic SDK | anthropic | Messages → llm_call spans | | Ollama | ollama | Generate/chat → llm_call spans | | LangGraph.js | langgraph | Graph invoke → agent span | | CrewAI.js | crewai | Crew/Task/Tool → agent/step/tool_call | | OpenAI Agents | openai-agents | Agent runs → agent/tool_call | | MCP | mcp | tools/call → tool_call (server, tool, args) | | LlamaIndex.TS | llamaindex | Query engine → agent; retriever → retrieval | | Chroma | chroma | Collection query/get → vector_search |

Each instrumentor is a safe no-op when its target package is not installed.

Structured Logs

Emit trace-correlated logs to the same collector (auto-attached to the active span, redacted like spans):

import { log } from "@splyntra/sdk";

log.info("charged card", { amount: 42 });
log.warn("rate limited", { server: "stripe" });
log.error("payment failed", { code: "card_declined" });

Governance

Ask the control plane whether an agent may act, and record consequential actions to the tamper-evident ledger (served by Splyntra Cloud):

import { authorize, logAction } from "@splyntra/sdk";

const d = await authorize("payments.refund", { agentId: "support", context: { amount: 80 } });
if (d.decision === "allow") { /* proceed */ }
else if (d.decision === "needs_approval") { /* wait for a human */ }

await logAction("payments.refund", { actor: "support", resource: "order_123", metadata: { amount: 80 } });

Evaluation

Push datasets and gate CI on regressions — programmatically or via the splyntra CLI (installed with this package):

import { pushDataset, runEval } from "@splyntra/sdk";

await pushDataset("support-qa", [{ input: "capital of France?", expected_output: "Paris" }]);
const res = await runEval(datasetId, [{ input: "capital of France?", actual: "Paris" }], { gate: true });
if (!res.passed) process.exit(1); // regression
# In CI (SPLYNTRA_API_KEY + SPLYNTRA_EVAL_ENDPOINT set):
splyntra eval push --name support-qa --file dataset.jsonl
splyntra eval run  --dataset <id> --file results.jsonl --scorers exact_match,groundedness --gate

License

Apache-2.0 — see LICENSE.