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

@gjallarhorn-hq/sdk

v1.0.1

Published

Official TypeScript/Node.js SDK for the Gjallarhorn prompt-injection detection API

Readme

@gjallarhorn-hq/sdk

Official TypeScript/JavaScript SDK for the Gjallarhorn prompt-injection detection API.

npm version License: MIT

Installation

npm install @gjallarhorn-hq/sdk
# or
pnpm add @gjallarhorn-hq/sdk
# or
yarn add @gjallarhorn-hq/sdk

Requirements: Node.js 18+, or any environment with the global fetch API.

Quickstart

import { GjallarhornClient } from '@gjallarhorn-hq/sdk';

const client = new GjallarhornClient({ apiKey: process.env.GJALLARHORN_API_KEY });

// Scan user input before sending to your LLM
const result = await client.scan(userInput);

if (result.risk_level === 'critical' || result.risk_level === 'high') {
  // block or flag the request
}
// safe to pass to LLM

Methods

scan(content, opts?)

Scan a text string for prompt injection.

const result = await client.scan('Some user input', {
  useClassifier: true,  // force LLM classifier (default: auto)
});

console.log(result.risk_level);       // 'safe' | 'low' | 'medium' | 'high' | 'critical'
console.log(result.recommendation);   // 'allow' | 'flag' | 'block'
console.log(result.detection_layers); // string[], e.g. ["l1"] or ["l1", "l3"]
console.log(result.risk_score);       // 0.0–1.0

scanMultimodal(file, mimeType, filename?)

Scan a PDF, image, or QR code for embedded injection payloads.

import { readFileSync } from 'fs';

const pdf = readFileSync('user-upload.pdf');
const result = await client.scanMultimodal(pdf, 'application/pdf', 'upload.pdf');

console.log(result.risk_level);         // same as scan()
console.log(result.billed_pages);       // non-blank pages counted for billing
console.log(result.extraction_source);  // 'pdf-parse' | 'mistral-ocr' | 'jsqr'

Supported MIME types: application/pdf, image/png, image/jpeg, image/gif, image/webp.

getQuota()

Check your API key's current usage and quota.

const usage = await client.getQuota();

console.log(usage.tier);             // 'starter' | 'growth' | 'scale' | 'enterprise'
console.log(usage.scans_this_month); // credits consumed
console.log(usage.quota_remaining);  // null = unlimited
console.log(usage.quota_reset_at);   // ISO 8601 timestamp

checkCanary(llmResponse) — L2 Agentic Integrity

Check whether your LLM's response still contains the Gjallarhorn canary token. Absence indicates a possible system-prompt override. L2 is opt-in — it only covers agents explicitly registered with Gjallarhorn; LLM calls made outside the integration are not monitored.

const check = await client.checkCanary(llmOutput);

if (check.alert_code === 'RAGNARÖK') {
  // Canary absent — system prompt may have been overridden.
  // Treat this session as potentially compromised.
  throw new Error('Prompt injection detected in agent output');
}

Privacy: L2 canary checks are stateless and content-free. Gjallarhorn receives the LLM output, performs a token presence check, and returns a boolean result. No output content, user data, or conversation text is retained server-side.

Full L2 integration example

import { GjallarhornClient } from '@gjallarhorn-hq/sdk';
import {
  AuthError,
  ServiceUnavailableError,
  type CanaryCheckResult,
} from '@gjallarhorn-hq/sdk';

const client = new GjallarhornClient({ apiKey: process.env.GJALLARHORN_API_KEY! });

// Step 1: Register agent once at startup — store canaryToken in your config/secrets.
// (Registration is a one-time REST call to POST /v1/agents/register — not in SDK yet.)
const CANARY_TOKEN = process.env.AGENT_CANARY_TOKEN!;

// Step 2: Inject canary into every system prompt.
function buildSystemPrompt(basePrompt: string): string {
  return `${basePrompt}\n${CANARY_TOKEN}`;
}

// Step 3: After every LLM call, check output integrity.
async function checkAgentOutput(llmOutput: string): Promise<void> {
  let check: CanaryCheckResult;

  try {
    check = await client.checkCanary(llmOutput);
  } catch (err) {
    if (err instanceof AuthError) throw new Error('Canary check: invalid API key');
    if (err instanceof ServiceUnavailableError) {
      // Canary service down — decide whether to fail-open or fail-closed
      console.warn('Canary check unavailable — proceeding with caution');
      return;
    }
    throw err;
  }

  if (check.alert_code === 'RAGNARÖK') {
    // Canary absent: model did not echo the token it should always produce.
    // Possible causes: system prompt was overridden by an injection attack.
    throw new Error(
      `[RAGNARÖK] Agent output integrity check failed for agent ${check.agent_id} at ${check.checked_at}`
    );
  }
}

// Usage in your agent loop:
const systemPrompt = buildSystemPrompt('You are a helpful customer support agent.');
const llmOutput = await callYourLLM(systemPrompt, userMessage);
await checkAgentOutput(llmOutput);
// Safe to proceed

health()

Check server and database health. No authentication required. The endpoint is /health (not /v1/health — note the absence of the /v1 prefix).

const status = await client.health();
console.log(status.status); // 'ok' | 'error'
console.log(status.db);     // 'ok' | 'unreachable'

Returns 503 if the database is unreachable.

Error Handling

All methods throw typed errors:

import {
  AuthError,
  QuotaExceededError,
  RateLimitError,
  ExtractionFailedError,
  ServiceUnavailableError,
} from '@gjallarhorn-hq/sdk';

try {
  const result = await client.scan(input);
} catch (err) {
  if (err instanceof AuthError)          console.error('Invalid API key');
  if (err instanceof QuotaExceededError) console.error('Monthly quota hit — upgrade plan');
  if (err instanceof RateLimitError)     console.error(`Rate limited — retry after ${err.retryAfter}s`);
  if (err instanceof ServiceUnavailableError) console.error('Service down');
}

The SDK automatically retries on RateLimitError (respecting retry_after) and 503 Service Unavailable (exponential backoff), up to maxRetries times (default: 3).

Configuration

const client = new GjallarhornClient({
  apiKey: 'gjh_...',
  baseUrl: 'https://gjallarhorn.watch', // default
  maxRetries: 3,                         // default
});

TypeScript Types

All response types are exported:

import type {
  ScanResult,
  MultimodalScanResult,
  QuotaResult,
  CanaryCheckResult,
  HealthResult,
  PatternMatch,
} from '@gjallarhorn-hq/sdk';

CanaryCheckResult includes alert_code?: 'RAGNARÖK' — present only when canary_present is false.

License

MIT — see LICENSE.

Links