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

claude-code-ts-hooks

v2.1.2

Published

TypeScript types and utilities for Claude Code hooks - providing type safety for hook implementations

Readme

claude-code-ts-hooks

Cross-platform TypeScript types and utilities for Claude Code hooks - Providing type safety and runtime validation for hook implementations across Node.js, Deno, and Bun.

npm version TypeScript License: MIT Node.js Deno Bun

Overview

This package provides comprehensive TypeScript support for Claude Code hooks with cross-platform compatibility, enabling developers to write type-safe hook implementations that work seamlessly across Node.js, Deno, and Bun runtimes. It includes:

  • Complete type definitions for all Claude Code hook events
  • Cross-platform runtime detection and compatibility layer
  • Runtime validation using Zod schemas
  • Utility functions for creating and managing hooks
  • Type guards for runtime type checking
  • Helper functions for common hook patterns
  • Zero-config usage with Deno and Bun (no build step required)

Installation & Usage

Naming note: On npm the package is published as claude-code-ts-hooks (unscoped), while the Deno/JSR distribution remains scoped as @lucacri/claude-code-ts-hooks.

Node.js (NPM/Yarn/PNPM)

npm install claude-code-ts-hooks
# or
yarn add claude-code-ts-hooks
# or
pnpm add claude-code-ts-hooks

Requirements:

  • Node.js 18+
  • TypeScript 5.0+ (for development)

Deno

Import the scoped package directly from JSR:

import { runHook, log, type HookHandlers } from 'jsr:@lucacri/claude-code-ts-hooks';

Or use the source distribution when you need a specific revision:

import { runHook, log, type HookHandlers } from 'https://deno.land/x/claude_code_ts_hooks/src/index.ts';
// or from your local copy
import { runHook, log, type HookHandlers } from './src/index.ts';

Requirements:

  • Deno 1.0+
  • Run with: deno run --allow-read --allow-env your-hook.ts

Bun

Use directly from source:

bun run your-hook.ts
import { runHook, log, type HookHandlers } from './src/index.ts';

Requirements:

  • Bun 1.0+

Quick Start

Node.js Example

import { runHook, log, type HookHandlers } from 'claude-code-ts-hooks';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    log(`About to use tool: ${payload.tool_name}`);
    
    // Block dangerous tools
    if (payload.tool_name === 'dangerous_tool') {
      return {
        decision: 'block',
        reason: 'Tool not allowed'
      };
    }
    
    return { decision: 'approve' };
  },

  stop: async (payload) => {
    log('🎉 Task completed!');
    return {};
  }
};

runHook(handlers);

Deno Example

Create hook.ts:

#!/usr/bin/env -S deno run --allow-read --allow-env

import { runHook, log, type HookHandlers } from './src/index.ts';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    log(`About to use tool: ${payload.tool_name}`);
    return { decision: 'approve' };
  },

  stop: async (payload) => {
    log('🎉 Task completed!');
    return {};
  }
};

runHook(handlers);

Run with:

deno run --allow-read --allow-env hook.ts

Bun Example

Create hook.ts:

#!/usr/bin/env bun

import { runHook, log, type HookHandlers } from './src/index.ts';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    log(`About to use tool: ${payload.tool_name}`);
    return { decision: 'approve' };
  },

  stop: async (payload) => {
    log('🎉 Task completed!');
    return {};
  }
};

runHook(handlers);

Run with:

bun run hook.ts

Cross-Platform Features

Runtime Detection

The library automatically detects the runtime environment and adapts accordingly:

import { detectRuntime, getArgs, getEnv } from 'claude-code-ts-hooks';

const runtime = detectRuntime(); // 'node' | 'deno' | 'bun' | 'unknown'
const args = getArgs(); // Cross-platform command line arguments
const envVar = getEnv('MY_VAR'); // Cross-platform environment variable access

Platform-Specific Examples

  • Node.js: examples/simple-hooks.ts
  • Deno: examples/simple-hooks-deno.ts
  • Bun: examples/simple-hooks-bun.ts

Hook Types

Supported Hook Events

| Hook Event | Description | Input Type | Output Type | |------------|-------------|------------|-------------| | PreToolUse | Before tool execution | PreToolUseHookInput | PreToolUseHookOutput | | PostToolUse | After tool execution | PostToolUseHookInput | PostToolUseHookOutput | | Stop | When Claude finishes | StopHookInput | StopHookOutput | | UserPromptSubmit | When user submits prompt | UserPromptSubmitHookInput | UserPromptSubmitHookOutput | | Notification | System notifications | NotificationHookInput | NotificationHookOutput | | SubagentStop | When subagent stops | SubagentStopHookInput | SubagentStopHookOutput | | PreCompact | Before compaction | PreCompactHookInput | PreCompactHookOutput |

Hook Input Structure

All hook inputs extend BaseHookInput:

interface BaseHookInput {
  session_id: string;
  transcript_path: string;
  hook_event_name: string;
}

Example PreToolUseHookInput:

interface PreToolUseHookInput extends BaseHookInput {
  hook_event_name: 'PreToolUse';
  tool_name: string;
  tool_input: Record<string, unknown>;
}

Hook Output Structure

All hook outputs extend BaseHookOutput:

interface BaseHookOutput {
  continue?: boolean;
  stopReason?: string;
  suppressOutput?: boolean;
}

Usage Examples

1. Creating Hook Handlers

import { runHook, log, type HookHandlers } from 'claude-code-ts-hooks';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    log(`🔧 About to use tool: ${payload.tool_name}`);
    log(`📋 Tool parameters:`, payload.tool_input);
    
    return { decision: 'approve', reason: 'Tool usage approved' };
  },

  postToolUse: async (payload) => {
    log(`✅ Tool ${payload.tool_name} completed successfully`);
    return {};
  },

  stop: async (payload) => {
    log('🎉 Claude finished processing!');
    // You could play a sound, send a notification, etc.
    return {};
  },

  userPromptSubmit: async (payload) => {
    log(`👤 User submitted: ${payload.prompt.substring(0, 50)}...`);
    return { decision: 'approve' };
  }
};

runHook(handlers);

2. Hook with Conditional Logic

import { runHook, type HookHandlers } from 'claude-code-ts-hooks';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    // Block dangerous tools
    const dangerousTools = ['rm', 'delete', 'format'];
    
    if (dangerousTools.some(tool => payload.tool_name.includes(tool))) {
      return {
        decision: 'block',
        reason: `Tool ${payload.tool_name} is not allowed`
      };
    }
    
    // Log tool usage for audit
    console.log(`📊 Audit: Tool ${payload.tool_name} used at ${new Date().toISOString()}`);
    
    return { decision: 'approve' };
  }
};

runHook(handlers);

3. Input Validation

import { 
  validateHookInput, 
  type PreToolUsePayload 
} from 'claude-code-ts-hooks';

// Sample input
const sampleInput: PreToolUsePayload = {
  session_id: 'session-123',
  transcript_path: '/path/to/transcript',
  hook_type: 'PreToolUse',
  tool_name: 'write_file',
  tool_input: { path: './file.txt', content: 'Hello!' }
};

// General validation
const result = validateHookInput(sampleInput);
if (result.success) {
  console.log('Valid hook input:', result.data);
} else {
  console.error('Invalid input:', result.error);
}

4. Complete Example

#!/usr/bin/env bun

import { runHook, log, type HookHandlers } from 'claude-code-ts-hooks';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    log(`🔧 About to use: ${payload.tool_name}`);
    
    // Safety check
    if (payload.tool_name.includes('rm')) {
      return { decision: 'block', reason: 'Dangerous command blocked' };
    }
    
    return { decision: 'approve' };
  },

  postToolUse: async (payload) => {
    log(`✅ Completed: ${payload.tool_name}`);
    return {};
  },

  stop: async (payload) => {
    log('🎉 All done!');
    return {};
  }
};

runHook(handlers);

5. Integration with Claude Code

The hooks are designed to work as standalone scripts that Claude Code calls:

#!/usr/bin/env bun

import { runHook, type HookHandlers } from 'claude-code-ts-hooks';

const handlers: HookHandlers = {
  preToolUse: async (payload) => {
    // Your hook logic here
    console.log(`Tool: ${payload.tool_name}`);
    return { decision: 'approve' };
  }
};

runHook(handlers);

Save this as a .ts file and configure it in your Claude Code settings.

API Reference

Types

  • Input Types: PreToolUseHookInput, PostToolUseHookInput, StopHookInput, etc.
  • Output Types: PreToolUseHookOutput, PostToolUseHookOutput, StopHookOutput, etc.
  • Handler Types: HookHandler, HookHandlerFor, HookRegistry
  • Utility Types: ToolInput, ToolResponse, HookEventName, HookConfig

Validation Functions

  • validateHookInput(input) - Validate any hook input
  • validateHookOutput(output) - Validate any hook output
  • parseHookInput(input, eventName) - Parse and validate specific event input
  • safeParseJSON(jsonString) - Safely parse JSON with validation

Type Guards

  • isHookInputOfType(input, eventName) - Generic type guard
  • isPreToolUseInput(input) - Specific type guards for each event
  • isHookEventName(value) - Check if value is valid event name

Helper Functions

  • createHookHandler(eventName, handler) - Create type-safe handler
  • createHookRegistry(handlers) - Create handler registry
  • executeHook(handler, input, context) - Execute with error handling
  • withLogging(handler, logger) - Add logging to handler
  • withTimeout(handler, timeout) - Add timeout to handler
  • createHookOutput.success() - Create success output
  • createHookOutput.block(reason) - Create blocking output

TypeScript Configuration

This package is built with TypeScript 5.0+ and uses modern features. Make sure your tsconfig.json includes:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true
  }
}

Distribution & Publishing

This package is designed to work seamlessly across different JavaScript runtimes:

NPM Registry (Node.js)

Published to NPM for Node.js users:

npm install claude-code-ts-hooks

The npm release uses the unscoped name claude-code-ts-hooks; earlier planning documents referenced a scoped variant, but the first public npm publish will be unscoped.

JSR (Deno)

The package can be published to JSR (JavaScript Registry) for Deno:

# Publish to JSR
deno publish

Deno users can import directly using the scoped name:

import { runHook } from "jsr:@lucacri/claude-code-ts-hooks";

Direct Source Usage

For maximum compatibility, users can clone this repository and import directly from source:

git clone https://github.com/lucacri/claude-code-ts-hooks.git
cd claude-code-ts-hooks

Then import from source:

// Deno
import { runHook } from "./src/index.ts";

// Bun  
import { runHook } from "./src/index.ts";

// Node.js (with TypeScript)
import { runHook } from "./src/index.ts";

Development

Pre-commit Hooks

This project uses pre-commit hooks to ensure code quality. The hooks are automatically installed when you run npm install.

The pre-commit hook runs:

  • Branch sync check (ensures local branch is up-to-date with origin/main)
  • TypeScript type checking (npm run typecheck)
  • ESLint linting (npm run lint)
  • Vitest tests (npm test)
  • Build verification (npm run build)
  • JSR validation (slow types check)

Manual Setup:

npm run setup-hooks

Skip Hooks (Emergency Only):

git commit --no-verify

⚠️ Note: Skipping hooks should be avoided as it may push broken code to CI/CD.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

If you touch the build system, follow the Rollup patch maintenance guide to keep the patch-package fallback in sync with upstream releases.

License

MIT License - see the LICENSE file for details.

Related

  • Claude Code SDK - Official Claude Code TypeScript SDK
  • Zod - TypeScript-first schema validation library

Made with ❤️ for the Claude Code community