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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@kilwar/sentinel-client-sdk

v0.2.0

Published

Official TypeScript SDK for Sentinel Platform - AI-powered operator orchestration

Readme

Sentinel Client SDK

Official TypeScript SDK for the Sentinel Platform - AI-powered operator orchestration.

Getting Access

The Sentinel Platform is an enterprise solution with controlled access. To obtain your API endpoint URL and credentials:

Installation

npm install @kilwar/sentinel-client-sdk
# or
yarn add @kilwar/sentinel-client-sdk
# or
pnpm add @kilwar/sentinel-client-sdk

Quick Start

import { SentinelClient } from '@kilwar/sentinel-client-sdk';

// API URL is provided during onboarding
const client = new SentinelClient({
  apiUrl: process.env.SENTINEL_API_URL,  // From your .env file
});

// Login with your credentials
await client.auth.login(
  process.env.SENTINEL_EMAIL,
  process.env.SENTINEL_PASSWORD
);

// List tenants
const { data: tenants } = await client.tenants.list();
console.log(`Found ${tenants.length} tenants`);

// List projects in a tenant
const { data: projects } = await client.projects.list('your-tenant-slug');
console.log(`Found ${projects.length} projects`);

// Start a batch
const batch = await client.batches.start('tenant-slug', 'project-slug', {
  trigger: 'manual',
  context: { source: 'sdk' }
});
console.log('Batch started:', batch.id);

Environment Variables

Create a .env file:

SENTINEL_API_URL=<your-api-url>
SENTINEL_EMAIL=<your-email>
SENTINEL_PASSWORD=<your-password>

Authentication

Basic Login

const client = new SentinelClient({
  apiUrl: process.env.SENTINEL_API_URL
});

// Login with credentials
await client.auth.login('[email protected]', 'your-password');

// Check if authenticated
if (client.auth.isAuthenticated()) {
  console.log('Logged in!');
}

// Logout
await client.auth.logout();

Token Persistence

Browser (localStorage)

import { SentinelClient, BrowserTokenStorage } from '@kilwar/sentinel-client-sdk';

const client = new SentinelClient({
  apiUrl: process.env.SENTINEL_API_URL,
  tokenStorage: new BrowserTokenStorage()
});

// Tokens are automatically saved to localStorage
await client.auth.login('[email protected]', 'your-password');

// On page reload, tokens are automatically loaded
const client2 = new SentinelClient({
  apiUrl: process.env.SENTINEL_API_URL,
  tokenStorage: new BrowserTokenStorage()
});
// Already authenticated!

Node.js (File Storage)

import { SentinelClient, FileTokenStorage } from '@kilwar/sentinel-client-sdk';

const client = new SentinelClient({
  apiUrl: process.env.SENTINEL_API_URL,
  tokenStorage: new FileTokenStorage('./.tokens.json')
});

React Native (AsyncStorage)

import AsyncStorage from '@react-native-async-storage/async-storage';

const tokenStorage = {
  getAccessToken: () => AsyncStorage.getItem('access_token'),
  getRefreshToken: () => AsyncStorage.getItem('refresh_token'),
  setTokens: (access, refresh) => {
    AsyncStorage.setItem('access_token', access);
    AsyncStorage.setItem('refresh_token', refresh);
  },
  clear: () => {
    AsyncStorage.removeItem('access_token');
    AsyncStorage.removeItem('refresh_token');
  }
};

const client = new SentinelClient({
  tokenStorage
});

Multi-Tenancy

// Set default tenant for all requests
client.setTenantId('tenant-123');

// Or override per request
const projects = await client.projects.list({
  tenantId: 'different-tenant'
});

// Invite user to tenant
const invitation = await client.tenants.inviteUser('tenant-id', {
  email: '[email protected]',
  roleName: 'Viewer'
});

Projects

// List all projects
const projects = await client.projects.list();

// Create a project
const project = await client.projects.create({
  name: 'My App',
  description: 'Application monitoring',
  region: 'us-east-1',
  settings: {
    notifications: {
      email: true,
      slack: true
    }
  }
});

// Update project
await client.projects.update(project.id, {
  status: 'paused',
  settings: {
    notifications: {
      email: false
    }
  }
});

// Archive project
await client.projects.archive(project.id);

Operator Chains

// Configure operator chain for a project
await client.chains.set(project.id, {
  operators: [
    {
      operatorId: 'op-newrelic',
      config: { apiKey: 'xxx', accountId: '123' }
    },
    {
      operatorId: 'op-datadog',
      config: { apiKey: 'yyy' }
    },
    {
      operatorId: 'op-sentinel-brain',
      config: { model: 'gpt-4' }
    }
  ]
});

// Get current chain
const chain = await client.chains.get(project.id);
console.log(`Chain has ${chain.operators.length} operators`);

// Add operator to chain
await client.chains.addOperator(project.id, {
  operatorId: 'op-slack',
  config: { webhookUrl: 'https://...' }
});

Batch Execution

// Start a batch
const batch = await client.batches.create({
  projectId: project.id,
  name: 'Hourly check',
  metadata: {
    triggeredBy: 'scheduler'
  }
});

// Monitor batch status
const status = await client.batches.get(batch.id);
console.log('State:', status.state);

// Control batch execution
await client.batches.pause(batch.id, 'Manual pause');
await client.batches.resume(batch.id);
await client.batches.cancel(batch.id, 'No longer needed');

// Wait for completion
const completed = await client.batches.waitForCompletion(batch.id, {
  pollInterval: 5000, // Check every 5 seconds
  maxWaitTime: 300000 // Max 5 minutes
});

Reports & Results

// Get batch report
const report = await client.reports.getForBatch(batch.id);
console.log('Report:', report.status);

// Get operator runs
const runs = await client.reports.getOperatorRuns(batch.id);
runs.data.forEach(run => {
  console.log(`${run.operatorId}: ${run.state} (${run.duration}ms)`);
});

// Get batch statistics
const stats = await client.reports.getBatchStats(batch.id);
console.log('Success rate:', (stats.successful / stats.totalOperators) * 100);

// Check if all succeeded
if (await client.reports.allOperatorsSucceeded(batch.id)) {
  console.log('All operators completed successfully!');
}

Error Handling

import {
  SentinelClient,
  AuthenticationError,
  ValidationError,
  NotFoundError
} from '@kilwar/sentinel-client-sdk';

try {
  await client.auth.login('[email protected]', 'badpass');
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid credentials');
  }
}

try {
  await client.projects.get('non-existent');
} catch (error) {
  if (error instanceof NotFoundError) {
    console.error('Project not found');
  }
}

try {
  await client.projects.create({
    name: '', // Invalid
    region: 'invalid-region'
  });
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Validation failed:', error.details);
  }
}

TypeScript Support

Full TypeScript support with all types exported:

import type {
  Project,
  Batch,
  Operator,
  Chain,
  User,
  Tenant
} from '@kilwar/sentinel-client-sdk';

function processProject(project: Project): void {
  console.log(project.name);
  console.log(project.region);
  console.log(project.settings?.notifications?.email);
}

Advanced Usage

Custom Headers

const client = new SentinelClient({
  headers: {
    'X-Custom-Header': 'value'
  }
});

// Or per request
await client.projects.list({
  headers: {
    'X-Request-ID': 'abc123'
  }
});

Debug Mode

const client = new SentinelClient({
  debug: true // Logs all HTTP requests/responses
});

Custom Timeout

const client = new SentinelClient({
  timeout: 60000 // 60 seconds
});

// Or per request
await client.batches.create(data, {
  timeout: 120000 // 2 minutes for this request
});

Direct API Access

// Use the underlying HTTP client for custom endpoints
const httpClient = client.getHttpClient();
const customData = await httpClient.get('/v1/custom-endpoint');

Framework Examples

React

// hooks/useSentinel.ts
import { useState, useEffect } from 'react';
import { SentinelClient, BrowserTokenStorage } from '@kilwar/sentinel-client-sdk';

export function useSentinel() {
  const [client] = useState(() => new SentinelClient({
    apiUrl: process.env.REACT_APP_SENTINEL_API,
    tokenStorage: new BrowserTokenStorage()
  }));

  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    setIsAuthenticated(client.isAuthenticated());
  }, [client]);

  return { client, isAuthenticated };
}

// components/ProjectList.tsx
function ProjectList() {
  const { client } = useSentinel();
  const [projects, setProjects] = useState([]);

  useEffect(() => {
    client.projects.list().then(result => {
      setProjects(result.data);
    });
  }, [client]);

  return (
    <ul>
      {projects.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

Vue 3

// composables/useSentinel.ts
import { ref, readonly } from 'vue';
import { SentinelClient, BrowserTokenStorage } from '@kilwar/sentinel-client-sdk';

const client = new SentinelClient({
  apiUrl: import.meta.env.VITE_SENTINEL_API,
  tokenStorage: new BrowserTokenStorage()
});

const isAuthenticated = ref(client.isAuthenticated());

export function useSentinel() {
  const login = async (email: string, password: string) => {
    await client.auth.login(email, password);
    isAuthenticated.value = true;
  };

  const logout = async () => {
    await client.auth.logout();
    isAuthenticated.value = false;
  };

  return {
    client,
    isAuthenticated: readonly(isAuthenticated),
    login,
    logout
  };
}

Next.js

// lib/sentinel.ts
import { SentinelClient } from '@kilwar/sentinel-client-sdk';

export function getSentinelClient(accessToken?: string) {
  return new SentinelClient({
    apiUrl: process.env.SENTINEL_API_URL,
    accessToken
  });
}

// pages/api/projects.ts
export default async function handler(req, res) {
  const client = getSentinelClient(req.cookies.token);

  try {
    const projects = await client.projects.list();
    res.json(projects);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
}

API Reference

Full API documentation available at: https://docs.sentinel.dev/sdk

Support

  • GitHub Issues: https://github.com/KilwarCom/sentinel-platform/issues
  • Documentation: https://docs.sentinel.dev
  • Email: [email protected]

License

MIT