Sign In

@neeter/server

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@neeter/server - npm Package Compare versions

Comparing version
0.10.0
to
0.10.1
+5
-0
dist/json-store.d.ts
import type { SessionStore } from "@neeter/types";
/**
* File-based `SessionStore` using append-only JSONL event logs and JSON metadata sidecars.
* Creates `{dataDir}/sessions/` on first call. Data is written unencrypted —
* use for development and trusted environments only.
*/
export declare function createJsonSessionStore(dataDir: string): SessionStore;

@@ -6,2 +6,7 @@ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";

}
/**
* File-based `SessionStore` using append-only JSONL event logs and JSON metadata sidecars.
* Creates `{dataDir}/sessions/` on first call. Data is written unencrypted —
* use for development and trusted environments only.
*/
export function createJsonSessionStore(dataDir) {

@@ -8,0 +13,0 @@ const sessionsDir = join(dataDir, "sessions");

import type { PermissionRequest, PermissionResponse } from "@neeter/types";
type RequestListener = (request: PermissionRequest) => void;
/**
* Deferred-promise map for browser-side tool approval and user questions.
* `request()` returns a Promise that blocks the SDK until the user responds
* via `respond()`. `cancelAll()` denies all pending requests (used on abort).
*/
export declare class PermissionGate {

@@ -4,0 +9,0 @@ private pending;

@@ -0,1 +1,6 @@

/**
* Deferred-promise map for browser-side tool approval and user questions.
* `request()` returns a Promise that blocks the SDK until the user responds
* via `respond()`. `cancelAll()` denies all pending requests (used on abort).
*/
export class PermissionGate {

@@ -2,0 +7,0 @@ pending = new Map();

@@ -0,1 +1,6 @@

/**
* Unbounded async iterable queue. Push values with `push()`, close with `close()`.
* Consumers `for await` over the channel; they block until a value is available
* or the channel is closed.
*/
export declare class PushChannel<T> implements AsyncIterable<T> {

@@ -2,0 +7,0 @@ private queue;

@@ -0,1 +1,6 @@

/**
* Unbounded async iterable queue. Push values with `push()`, close with `close()`.
* Consumers `for await` over the channel; they block until a value is available
* or the channel is closed.
*/
export class PushChannel {

@@ -2,0 +7,0 @@ queue = [];

import { Hono } from "hono";
import { type SessionManager } from "./session.js";
import { type MessageTranslator } from "./translator.js";
/**
* Returns a Hono app with eight routes for session management, SSE streaming,
* permissions, and abort. Mounts under `basePath` (default: `"/api"`).
*/
export declare function createAgentRouter<TCtx>(config: {
sessions: SessionManager<TCtx>;
translator: MessageTranslator<TCtx>;
/** URL prefix for all routes. Defaults to `"/api"`. */
basePath?: string;
}): Hono;
+4
-0

@@ -16,2 +16,6 @@ import { Hono } from "hono";

]);
/**
* Returns a Hono app with eight routes for session management, SSE streaming,
* permissions, and abort. Mounts under `basePath` (default: `"/api"`).
*/
export function createAgentRouter(config) {

@@ -18,0 +22,0 @@ const { sessions, translator, basePath = "/api" } = config;

@@ -5,13 +5,22 @@ import { type HookCallbackMatcher, type HookEvent, query } from "@anthropic-ai/claude-agent-sdk";

type SDKMessage = ReturnType<typeof query> extends AsyncGenerator<infer T> ? T : never;
/** Configuration returned by the `SessionManager` factory for each new session. */
export interface SessionInit<TCtx> {
/** Per-session application state, accessible in translator hooks. */
context: TCtx;
/** Claude model ID (e.g. `"claude-sonnet-4-5-20250929"`). */
model: string;
systemPrompt: string;
/** MCP servers keyed by name — the name becomes the middle segment of tool names (`mcp__{name}__{tool}`). */
mcpServers?: Record<string, unknown>;
tools?: unknown[];
/** Glob patterns for allowed tools (e.g. `["mcp__myServer__*"]`). */
allowedTools?: string[];
disallowedTools?: string[];
/** Maximum SDK turns before the session stops. Defaults to 200. */
maxTurns?: number;
/** Working directory for file-based tools. */
cwd?: string;
/** Controls browser-side tool approval. Defaults to `"bypassPermissions"`. */
permissionMode?: "default" | "acceptEdits" | "plan" | "bypassPermissions";
/** Enable extended thinking (chain-of-thought). Off by default. */
thinking?: {

@@ -23,2 +32,3 @@ type: "enabled";

};
/** SDK lifecycle hooks (e.g. `PreToolUse` for sandbox enforcement via `createSandboxHook`). */
hooks?: Partial<Record<HookEvent, HookCallbackMatcher[]>>;

@@ -48,2 +58,10 @@ }

}
/**
* Manages agent sessions — create, resume, look up, and clean up.
*
* The `factory` callback runs once per session and returns a `SessionInit`.
* When resuming, the original session is passed so you can carry context forward.
*
* Pass `options.store` to persist session history and event logs across restarts.
*/
export declare class SessionManager<TCtx> {

@@ -50,0 +68,0 @@ private sessions;

@@ -21,2 +21,10 @@ import { query, } from "@anthropic-ai/claude-agent-sdk";

const DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
/**
* Manages agent sessions — create, resume, look up, and clean up.
*
* The `factory` callback runs once per session and returns a `SessionInit`.
* When resuming, the original session is passed so you can carry context forward.
*
* Pass `options.store` to persist session history and event logs across restarts.
*/
export class SessionManager {

@@ -23,0 +31,0 @@ sessions = new Map();

import type { CustomEvent, SSEEvent } from "@neeter/types";
import type { Session } from "./session.js";
export interface TranslatorConfig<TCtx> {
/** Inspect completed tool results and optionally return custom events to send to the client. */
onToolResult?: (toolName: string, result: string, session: Session<TCtx>) => CustomEvent[];
}
/** Converts raw Claude Agent SDK messages into semantically named SSE events. */
export declare class MessageTranslator<TCtx> {

@@ -14,3 +16,9 @@ private config;

}
/** Formats an SSEEvent as an `event: ...\ndata: ...\n\n` string for the wire. */
export declare function sseEncode(evt: SSEEvent): string;
/**
* Drives the SDK message loop and yields translated SSE events.
* The optional `onEvent` callback fires for each event — use it
* to persist events to a `SessionStore`.
*/
export declare function streamSession<TCtx>(session: Session<TCtx>, translator: MessageTranslator<TCtx>, onEvent?: (evt: SSEEvent) => void): AsyncGenerator<SSEEvent>;
import { PushChannel } from "./push-channel.js";
/** Converts raw Claude Agent SDK messages into semantically named SSE events. */
export class MessageTranslator {

@@ -207,5 +208,11 @@ config;

}
/** Formats an SSEEvent as an `event: ...\ndata: ...\n\n` string for the wire. */
export function sseEncode(evt) {
return `event: ${evt.event}\ndata: ${evt.data}\n\n`;
}
/**
* Drives the SDK message loop and yields translated SSE events.
* The optional `onEvent` callback fires for each event — use it
* to persist events to a `SessionStore`.
*/
export async function* streamSession(session, translator, onEvent) {

@@ -212,0 +219,0 @@ const output = new PushChannel();

+2
-2
{
"name": "@neeter/server",
"version": "0.10.0",
"version": "0.10.1",
"description": "Hono server toolkit for building chat UIs on top of the Claude Agent SDK",

@@ -24,3 +24,3 @@ "license": "MIT",

"dependencies": {
"@neeter/types": "0.10.0"
"@neeter/types": "0.10.1"
},

@@ -27,0 +27,0 @@ "peerDependencies": {

@@ -48,26 +48,2 @@ # @neeter/server

This gives you eight endpoints:
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/sessions` | Create a session |
| `POST` | `/api/sessions/resume` | Resume or fork a session by SDK session ID |
| `GET` | `/api/sessions/history` | List previous sessions |
| `GET` | `/api/sessions/replay/:sdkSessionId` | Load persisted events for UI replay |
| `POST` | `/api/sessions/:id/messages` | Send a message |
| `GET` | `/api/sessions/:id/events` | SSE event stream |
| `POST` | `/api/sessions/:id/permissions` | Respond to a permission request |
| `POST` | `/api/sessions/:id/abort` | Abort the current turn |
## Key features
- **Multi-turn sessions** — `SessionManager` + `PushChannel` let users send messages at any time, even while the agent is running.
- **Named SSE events** — `MessageTranslator` reshapes the SDK's flat message stream into `text_delta`, `tool_start`, `tool_call`, `tool_result`, and more.
- **Tool result hooks** — `onToolResult` lets you inspect what the agent did and emit structured custom events.
- **Permission modes** — `bypassPermissions`, `default`, `acceptEdits`, or `plan` — with browser-side approval via `PermissionGate`.
- **Extended thinking** — Pass `thinking: { type: "enabled", budgetTokens: N }` to stream chain-of-thought reasoning.
- **Session resume & persistence** — Resume past conversations with `SessionManager.resume()`. Opt into persistence with `createJsonSessionStore` for history and event replay that survive server restarts.
- **Abort** — Cancel the current agent turn mid-stream.
- **Sandbox hooks** — `createSandboxHook` restricts file operations to a directory.
## Examples

@@ -82,3 +58,4 @@

See the [neeter README](https://github.com/quantumleeps/neeter#readme) for full API reference, session context examples, and permission configuration.
- [Server Guide](https://github.com/quantumleeps/neeter/blob/main/docs/server.md) — endpoints, permissions, persistence, session context, sandbox hooks
- [API Reference](https://github.com/quantumleeps/neeter/blob/main/docs/api-reference.md) — all exports and types

@@ -85,0 +62,0 @@ ## License