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

sct-langchain

v0.1.0

Published

LangChain/LangGraph integration for SCT (Secure Compact Tokenization) — reversible, keyed PII pseudonymization (DSGVO/BaFin-grade) plus deterministic tool-output compression and a metered OpenAI-compatible chat model.

Readme

sct-langchain

Reversible, keyed PII pseudonymization for LangChain / LangGraph (v1) — DSGVO/BaFin-grade. PII is tokenized before the model sees it and the real values are restored in the answer via SCT (Secure Compact Tokenization).

Warum SCT statt der eingebauten PIIMiddleware?

LangChains eigene PIIMiddleware kennt nur redact / mask / hash — alle einwegig. Die Antwort des Agenten enthält [REDACTED_email] statt des echten Namens oder der IBAN. SCT ist ein echtes Round-Trip:

| | eingebaute PIIMiddleware | sct-langchain | | --- | --- | --- | | Vor dem Modell | redigiert / maskiert | tokenisiert (reversibel) | | Nach dem Modell | keine Wiederherstellung | re-identifiziert die echten Werte | | Schlüssel-Verwahrung | — | AES-256-GCM / FF3-1, tenant-isoliert | | Erkennung | 5 US-Regex-Typen | DE/EU NER + Regex (Name, IBAN, Steuer-ID …) |

Installation

npm install sct-langchain
# peer deps
npm install langchain @langchain/core zod
# nur für ChatSCT (sct-langchain/chat) — optionaler Peer-Dep:
npm install @langchain/openai

Middleware (Flagship)

import { createAgent } from 'langchain';
import { sctPseudonymizationMiddleware } from 'sct-langchain';

const agent = createAgent({
  model: 'openai:gpt-4o',
  middleware: [
    sctPseudonymizationMiddleware({ apiKey: process.env.SCT_API_KEY! }),
  ],
});

// PII in the prompt never reaches the LLM; the answer comes back re-identified.
const res = await agent.invoke({
  messages: [{ role: 'user', content: 'Mail an Max Mustermann: [email protected]' }],
});

Optionen: applyToInput (default true), applyToOutput (default true), applyToToolResults (default false), autoDetectPii (default true). Ein vorgefertigter Client geht via client, sonst apiKey / baseUrl / timeoutMs.

Design-Hinweis (verifiziert gegen [email protected])

Die Re-Identifikation läuft als node-style afterModel-Hook, nicht als wrapModelCall. Grund: LangChain.js-Bug #9418 bricht responseFormat / Structured-Output mit jedem wrapModelCall-Middleware, und wrapModelCall kann keine State-Updates zurückgeben. beforeModel + afterModel sind die stabile, structured-output-sichere Naht. Der Verschlüsselungs-Schlüssel wird pro Lauf einmal erzeugt und über das Middleware-State (stateSchema) von beforeModel zu afterModel getragen.

Kompression: sctCompressionMiddleware

Der zweite Differenzierer — Token-Kosten. Werkzeug-Ausgaben (Log-Dumps, Test-Reports, Such-Treffer) fließen oft ungefiltert zurück in den Kontext und treiben die Kosten. sctCompressionMiddleware komprimiert sie im wrapToolCall-Seam über SCTs /tokenizer/compressbevor sie das Modell wieder erreichen:

import { createAgent } from 'langchain';
import { sctCompressionMiddleware, sctPseudonymizationMiddleware } from 'sct-langchain';

const agent = createAgent({
  model: 'openai:gpt-4o',
  tools: [searchDocs],
  middleware: [
    // Erst pseudonymisieren, dann komprimieren — PII wird tokenisiert,
    // bevor sie in die Kompression läuft.
    sctPseudonymizationMiddleware({ apiKey: process.env.SCT_API_KEY! }),
    sctCompressionMiddleware({ apiKey: process.env.SCT_API_KEY! }),
  ],
});

Was LangChain sonst bietet — und warum SCT besser passt:

| | eingebaute Optionen | sctCompressionMiddleware | | --- | --- | --- | | Kürzen | blindes Truncation (schneidet Datensätze mitten durch) | format-bewusst (pytest, jest, eslint, git-diff …) | | Zusammenfassen | Summarizer-LLM (extra Call, nicht-deterministisch) | deterministisch, kein extra LLM-Call | | Garantie | keine | tiktoken-geprüft neverWorse — nie mehr Tokens als das Original | | Finance/Legal/Health | riskant (LLM halluziniert Zusammenfassung) | reproduzierbar, auditierbar |

Optionen: format (Parser-Hinweis), model, verbosity (compact | verbose | ultra), minChars (default 200 — überspringt winzige Ausgaben), toolNames (Whitelist), onCompressed(result, toolName) (z. B. um savings_pct als Billing-Envelope zu loggen). Non-ToolMessage- und Nicht-Text-Ergebnisse laufen unverändert durch.

ChatSCT: gemetertes OpenAI-kompatibles Chat-Modell

ChatSCT ist ein dünner ChatOpenAI-Subclass, der auf SCTs OpenAI-kompatibles api-gateway gepinnt ist — Tenant-/API-Key-Header und Token-Metering inklusive. Import über den chat-Subpath (der optionale Peer-Dep @langchain/openai wird nur hier benötigt):

import { ChatSCT } from 'sct-langchain/chat';

const model = new ChatSCT({
  model: 'gpt-4o',
  apiKey: process.env.SCT_API_KEY!, // sct_… Bearer-Token
  tenantId: 'acme-gmbh',            // -> X-Tenant-Id Header
});
const res = await model.invoke('Hallo!');

Ein-Zeilen-Alternative ohne diesen Subpath: new ChatOpenAI({ apiKey, configuration: { baseURL: 'https://sct.simosphereai.com/v1' } }). ChatSCT bündelt Base-URL, Header und die SCTUsageCallback-Meterung, damit das nicht pro Call-Site wiederholt wird.

Streaming-Hinweis: Eine eigene base_url deaktiviert OpenAIs gestreamte Token-Nutzung. Die angehängte SCTUsageCallback liest das normalisierte usage_metadata aus der Antwort, sodass die Meterung in beiden Fällen korrekt bleibt. metering: false schaltet sie ab.

Runnables (jede LCEL-Kette, nicht nur Agenten)

import { withSctPseudonymization } from 'sct-langchain';

// Beliebige string-in/string-out Runnable schützen:
const safe = withSctPseudonymization(prompt.pipe(llm), {
  apiKey: process.env.SCT_API_KEY!,
});
const answer = await safe.invoke('Fasse zusammen: Max Mustermann schuldet 500 EUR');

Für manuelle Komposition (Fork des Schlüssels um den Modell-Aufruf herum):

import { sctPseudonymize, sctReidentify } from 'sct-langchain';

const pseud = sctPseudonymize({ apiKey: KEY });
const reident = sctReidentify({ apiKey: KEY });

const { text, encryptionKey } = await pseud.invoke('Max Mustermann, [email protected]');
const modelOut = await llm.invoke(text); // sieht nur Tokens
const restored = await reident.invoke({ text: String(modelOut.content), encryptionKey });

DSGVO-Nuance

Beide Middleware adressieren getrennte DSGVO-Hebel. sctPseudonymizationMiddleware setzt Datenminimierung / Pseudonymisierung (Art. 5, Art. 32 DSGVO) durch: der LLM-Prozessor sieht nie Klartext-PII, die Schlüsselverwahrung bleibt tenant-isoliert und auditierbar server-seitig — anders als redigierende Guards verliert der Nutzer aber keine Antwortqualität, weil re-identifiziert wird. sctCompressionMiddleware reduziert die an den Prozessor übermittelte Datenmenge zusätzlich, ohne Inhalte an ein zweites LLM (Summarizer) weiterzugeben — relevant für die Vermeidung zusätzlicher Auftragsverarbeiter.

Exports

Root (sct-langchain):

  • sctPseudonymizationMiddleware(options) / Alias SCTPseudonymizationMiddleware
  • sctCompressionMiddleware(options) / Alias SCTCompressionMiddleware
  • withSctPseudonymization(inner, options)
  • sctPseudonymize(options) · sctReidentify(options)
  • SCTUsageCallback (Token-Metering-Callback)
  • SCTClient · resolveSctClient(source)

Subpath (sct-langchain/chat, benötigt @langchain/openai):

  • ChatSCT (gemetertes, gateway-gepinntes ChatOpenAI)

Entwicklung

npm install
npm run build      # tsup -> dist/ (ESM + d.ts)
npm test           # vitest (gemockter SCT-Client, Golden-Round-Trip)
npm run typecheck

MIT © SIMO GmbH