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

@agstack/plugin-sdk

v0.1.0

Published

Foundation SDK for the AGStack plugin ecosystem — interfaces, contracts, types, and base classes for every AGStack plugin

Readme

@agstack/plugin-sdk

Foundation SDK for the AGStack plugin ecosystem — interfaces, contracts, types, and base classes for every AGStack plugin.

Zero runtime dependencies. TypeScript-first. Framework-agnostic.

Features

  • Plugin interfaces — 13 typed plugin interfaces (IPlugin, IStoragePlugin, IAIPlugin, INotificationPlugin, IFrameworkAdapter, ISecurityPlugin, IPayloadPlugin, IDatabaseObserver, IMetricsPlugin, ICloudPlugin, ITracingPlugin, IAnalyticsPlugin, IEnricherPlugin)
  • Base classes — 9 abstract base classes with lifecycle management (BasePlugin, BaseStoragePlugin, BaseAIPlugin, BaseNotificationPlugin, BaseSecurityPlugin, BasePayloadPlugin, BaseDatabaseObserver, BaseMetricsPlugin, BaseEnricherPlugin)
  • Event system — 38 typed runtime events with discriminated union payload map
  • Hook system — 15 hook points with typed payload maps
  • Error classes — 9 semantic error types with code and suggestion properties
  • Versioning — SemVer utilities, version range constraints, compatibility checks
  • Validation — Plugin metadata validation, configuration validation, dependency validation
  • Transaction model — Full data model: RawTransaction, EnrichedTransaction, ClientInfo, GeoInfo, PerformanceInfo, SecurityInfo, DatabaseOperationData, ExternalCallData, PayloadInfo
  • Utilitiesdelay, withTimeout, createRetryPolicy, DisposableGroup, generateId, circularSafeStringify, truncate, maskField
  • Configuration — Typed configs for plugins, storage, AI, notifications, payload, security
  • Runtime contextIRuntimeContext with event bus, logger, lifecycle, health reporter

Installation

npm install @agstack/plugin-sdk

Quick Start

1. Create a plugin

import {
  BasePlugin,
  type PluginMetadata,
  type IRuntimeContext,
  type PluginConfiguration,
} from "@agstack/plugin-sdk";

export class MyPlugin extends BasePlugin {
  readonly metadata: PluginMetadata = {
    name: "@org/my-plugin",
    version: "1.0.0",
    description: "Does something useful",
    type: "custom",
    capabilities: ["custom_action"],
    priority: 50,
    supportedRuntimeVersions: {
      pluginSdk: { min: "0.1.0" },
      runtime: { min: "0.2.0" },
    },
  };

  async initialize(context: IRuntimeContext, config?: PluginConfiguration): Promise<void> {
    await super.initialize(context, config);
    this.logger.info("Plugin initialized");
  }

  async start(): Promise<void> {
    await super.start();
    this.logger.info("Plugin started");
  }

  async shutdown(): Promise<void> {
    await super.shutdown();
    this.logger.info("Plugin stopped");
  }
}

2. Implement a storage plugin

import { BaseStoragePlugin, type RawTransaction } from "@agstack/plugin-sdk";

export class MyStoragePlugin extends BaseStoragePlugin {
  readonly metadata = {
    name: "@org/storage",
    version: "1.0.0",
    description: "Custom storage backend",
    type: "storage" as const,
    capabilities: ["store", "retrieve"],
    priority: 60,
    supportedRuntimeVersions: {
      pluginSdk: { min: "0.1.0" },
      runtime: { min: "0.2.0" },
    },
  };

  private transactions: RawTransaction[] = [];

  async save(transaction: unknown): Promise<void> {
    this.transactions.push(transaction as RawTransaction);
  }

  async saveBatch(transactions: unknown[]): Promise<void> {
    this.transactions.push(...(transactions as RawTransaction[]));
  }

  async flush(): Promise<void> {
    // Persist to database
  }
}

3. Validate a plugin

import { validatePluginMetadata, isValidPluginName } from "@agstack/plugin-sdk";

const errors = validatePluginMetadata(myPlugin.metadata);
if (errors.length > 0) {
  console.error("Plugin validation failed:", errors);
}

if (!isValidPluginName("@org/my-plugin")) {
  console.error("Invalid plugin name format");
}

4. Check version compatibility

import { checkPluginCompatibility, AGSTACK_SDK_VERSION } from "@agstack/plugin-sdk";

const result = checkPluginCompatibility(AGSTACK_SDK_VERSION, {
  pluginSdk: { min: "0.1.0", max: "1.0.0" },
  runtime: { min: "0.2.0" },
});

if (!result.compatible) {
  console.error(result.reason);
}

Architecture

The plugin-sdk defines the contract between AGStack runtime and all ecosystem plugins:

┌─────────────────────────────────────────────────────┐
│                   Runtime Kernel                      │
│  (@agstack/logger or other runtime)                   │
│                                                       │
│  ┌──────────────┐  ┌──────────────┐  ┌────────────┐  │
│  │   EventBus   │  │   Lifecycle  │  │  Plugin    │  │
│  │              │  │   Manager    │  │  Manager   │  │
│  └──────────────┘  └──────────────┘  └─────┬──────┘  │
│                                            │          │
├────────────────────────────────────────────┼──────────┤
│  @agstack/plugin-sdk Contract              │          │
│                                            ▼          │
│  ┌─────────────────────────────────────────────────┐  │
│  │  IPlugin.initialize(context, config)              │  │
│  │  IPlugin.start() / .pause() / .resume()           │  │
│  │  IPlugin.shutdown() / .dispose()                  │  │
│  │  IPlugin.health() / .validate()                   │  │
│  └─────────────────────────────────────────────────┘  │
│                                            │          │
├────────────────────────────────────────────┼──────────┤
│  Plugin Packages                            │          │
│                                            ▼          │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│  │ Storage  │ │   AI     │ │ Notif.   │ │ Security │ │
│  │ Plugin   │ │ Plugin   │ │ Plugin   │ │ Plugin   │ │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│  │Payload   │ │Metrics   │ │Database  │ │Enricher  │ │
│  │ Plugin   │ │ Plugin   │ │Observer  │ │ Plugin   │ │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────┘

Plugin Development Guide

Plugin Lifecycle

Every plugin goes through these states:

created → initializing → initialized → starting → running
                                               → pausing → paused → resuming → running
                                           → stopping → stopped

Errors during any phase transition to error state.

Using Base Classes

Extend BasePlugin to get automatic lifecycle management:

| Method | Description | |--------|-------------| | initialize() | Sets up context, validates metadata, publishes plugin.initialized event | | start() | Transitions to running | | pause() | Transitions to paused | | resume() | Transitions back to running | | shutdown() | Transitions to stopped | | dispose() | Cleans up error state | | validate() | Checks capabilities are non-empty | | health() | Returns HealthCheckResult based on current state | | recordError() | Publishes plugin.error event |

Direct Interface Implementation

If you prefer not to extend base classes:

import type { IPlugin, PluginMetadata, PluginState, IRuntimeContext, PluginConfiguration } from "@agstack/plugin-sdk";

export class MyPlugin implements IPlugin {
  readonly metadata: PluginMetadata = { ... };
  state: PluginState = "created";
  // Implement all IPlugin methods...
}

Event System

Publishing Events

import type { EventPayloadMap, RuntimeEventType } from "@agstack/plugin-sdk";

// The runtime publishes these events; plugins subscribe to them

Subscribing to Events

Via IRuntimeContext.eventBus:

context.eventBus.subscribe("transaction.created", (event) => {
  console.log("New transaction:", event.payload.transactionId);
});

context.eventBus.subscribe("queue.backpressure", (event) => {
  console.warn("Queue pressure:", event.payload.queueSize);
}, { filter: (e) => e.payload.queueSize > 1000 });

All Event Types

| Event | Payload | |-------|---------| | runtime.started | RuntimeStartedPayload | | runtime.shutdown | RuntimeShutdownPayload | | runtime.booted | {} | | runtime.stopping | { reason?: string } | | runtime.stopped | { uptimeMs: number } | | runtime.error | { message: string; stack?: string } | | transaction.created | TransactionCreatedPayload | | transaction.completed | TransactionCompletedPayload | | transaction.enriched | TransactionEnrichedPayload | | transaction.dropped | { transactionId: string; reason: string } | | queue.enqueued | { transactionId: string; queueSize: number } | | queue.dequeued | { transactionId: string; queueSize: number } | | queue.backpressure | QueueBackpressurePayload | | queue.drained | { itemsProcessed: number; durationMs: number } | | queue.overflow | { droppedTransactionId?: string } | | worker.* | Various worker payloads | | plugin.* | PluginEventPayload | | enrichment.* | EnrichmentEventPayload | | storage.* | StorageEventPayload | | ai.* | AIEventPayload | | notification.* | NotificationEventPayload | | hook.* | Hook payloads | | security.* | SecurityThreatPayload, masked payload | | configuration.* | config change payloads |

Hook System

Hook Points

15 hook points available: beforeTransaction, afterTransaction, beforeQueue, afterQueue, beforeEnrichment, afterEnrichment, beforeStorage, afterStorage, beforePlugin, afterPlugin, beforeAI, afterAI, beforeNotification, afterNotification, beforeShutdown, afterShutdown, onError.

Implementing Hooks

import { HookEngine } from "@agstack/plugin-sdk";

const engine = new HookEngine();
engine.register("afterTransaction", "my-plugin", (input) => {
  console.log("Transaction completed:", input.transactionId);
  return { cancelled: false as const };
});

Transaction Data Model

RawTransaction

interface RawTransaction {
  id: string;
  correlationId: string;
  traceId: string;
  status: TransactionStatus;
  request: RawRequestInfo;
  response?: RawResponseInfo;
  errors: ErrorEventData[];
  events: TimelineEventData[];
  metadata: Record<string, unknown>;
  startedAt: number;
  completedAt?: number;
  duration?: number;
}

EnrichedTransaction

Extends RawTransaction with:

  • request: EnrichedRequestInfo — adds bodySize, bodyText, bodyHash, bodyTruncated, bodyPreview
  • client?: ClientInfo — browser, OS, device, IP
  • geo?: GeoInfo — city, region, country, ISP, ASN, coordinates
  • performance?: PerformanceInfo — memory, CPU, event loop, GC
  • security?: SecurityInfo — masked fields, detected threats
  • payload?: PayloadInfo — raw, text, hash, preview, classification, threat score
  • databaseOps, externalCalls, pluginResults, aiMetadata, storageMetadata, notificationMetadata

Error Reference

| Error Class | Code | When Thrown | |-------------|------|-------------| | ConfigurationError | CONFIGURATION_ERROR | Invalid runtime or plugin configuration | | PluginError | PLUGIN_ERROR | Plugin-level failures (initialization, runtime, shutdown) | | ValidationError | VALIDATION_ERROR | Metadata or configuration validation failures | | InitializationError | INITIALIZATION_ERROR | Component initialization failures | | ShutdownError | SHUTDOWN_ERROR | Component shutdown failures | | DependencyError | DEPENDENCY_ERROR | Missing plugin dependencies | | CompatibilityError | COMPATIBILITY_ERROR | Version incompatibility between plugin and runtime | | TimeoutError | TIMEOUT_ERROR | Operation exceeded time limit | | QueueError | QUEUE_ERROR | Queue overflow or backpressure |

Every error class provides a suggestion property with remediation guidance.

Utility Reference

| Function | Description | |----------|-------------| | delay(ms) | Promise-based setTimeout | | withTimeout(promise, ms, name) | Race promise against timeout | | createRetryPolicy(options) | Exponential backoff with jitter | | DisposableGroup | Dispose resources in reverse order | | generateId(prefix?) | UUID v4 with optional prefix | | circularSafeStringify(value) | JSON.stringify safe for circular refs | | truncate(str, maxLength) | Truncate with ellipsis | | maskField(value) | Mask sensitive data (passwords, tokens) |

Retry Policy

const policy = createRetryPolicy({
  maxRetries: 3,
  baseDelayMs: 100,
  maxDelayMs: 10_000,
  jitter: true,
});

await policy.execute(async () => {
  return await fetch("https://api.example.com/data");
});

Configuration Defaults

DEFAULT_RUNTIME_CONFIG

{
  queueMaxSize: 10_000,
  workerConcurrency: 4,
  workerPollIntervalMs: 100,
  shutdownTimeoutMs: 30_000,
  debug: false,
}

DEFAULT_PAYLOAD_CONFIG

{
  maxBodySize: 102_400,         // 100 KB
  previewSize: 1024,            // 1 KB preview
  captureContentTypes: ["application/json", "application/xml", "text/plain", "application/x-www-form-urlencoded"],
  maskFields: ["password", "secret", "token", "jwt", "authorization", "api_key",
               "credit_card", "ssn", "otp", "pin", "cvv", "access_token",
               "refresh_token", "private_key"],
  enableHashing: true,
  enableThreatDetection: false,
}

DEFAULT_STORAGE_CONFIG

{
  retryCount: 3,
  batchSize: 100,
  flushIntervalMs: 5000,
}

Best Practices

Plugin Naming

Use scoped names following the pattern @org/plugin-name:

  • @agstack/storage-file — File-based storage plugin
  • @agstack/enricher-geo — Geo-enrichment plugin
  • @mycompany/security-scanner — Custom security plugin

Versioning

  • Follow SemVer for your plugins
  • Use AGSTACK_SDK_VERSION to check compatibility with the SDK
  • Set realistic supportedRuntimeVersions constraints
  • Use checkPluginCompatibility() during registration

Error Handling

  • Always call super.initialize() when extending BasePlugin
  • Use recordError() helper for recoverable errors
  • Provide meaningful suggestion messages in custom errors
  • Clean up resources in shutdown() — don't rely on dispose()

Performance

  • Avoid blocking operations in plugin methods
  • Use batches where possible (e.g., saveBatch, analyzeBatch)
  • Respect the configuration's maxBodySize and previewSize
  • Register for relevant events only — don't subscribe to everything

API Reference

Exported Types

Interfaces: IPlugin, IStoragePlugin, IAIPlugin, INotificationPlugin, IFrameworkAdapter, ISecurityPlugin, IPayloadPlugin, IDatabaseObserver, IMetricsPlugin, ICloudPlugin, ITracingPlugin, IAnalyticsPlugin, IEnricherPlugin

Configuration: PluginConfiguration, RuntimeConfiguration, StorageConfiguration, AIConfiguration, NotificationConfiguration, NotificationFilter, PayloadConfiguration, SecurityConfiguration, PluginConfigSchema, SchemaProperty, ConfigurationSchema, ConfigurationValidationResult, ConfigurationValidationError

Context: IRuntimeContext, IEventBus, ILogger, ILifecycle, EventHandler

Events: RuntimeEventType, EventPriority, EventMetadata, EventPayloadMap, BusEvent, plus all XxxPayload types

Hooks: HookPoint, HookPriority, HookContext, HookCancellation, HookResult, HookPayloadMap, plus all XxxInput types

Contracts: TransactionStatus, HttpMethod, RawRequestInfo, RawResponseInfo, RawTransaction, EnrichedRequestInfo, EnrichedResponseInfo, ClientInfo, GeoInfo, PerformanceInfo, MemoryUsage, HeapUsage, CPUUsage, GCEventData, DatabaseOperationData, ExternalCallData, SecurityInfo, SecurityThreat, ErrorEventData, TimelineEventData, PayloadInfo, PluginResult, EnrichedTransaction

Metadata: PluginType, PluginMetadata

Version: SemVer, VersionRange, VersionCompatibility, CompatibilityResult, VersionConstraint

Health: HealthStatus, HealthCheckResult, HealthMetrics, HealthError, HealthWarning, HealthReporter

Errors: ConfigurationError, PluginError, ValidationError, InitializationError, ShutdownError, DependencyError, CompatibilityError, TimeoutError, QueueError, SDKError

Exported Values

Classes: BasePlugin, BaseStoragePlugin, BaseAIPlugin, BaseNotificationPlugin, BaseSecurityPlugin, BasePayloadPlugin, BaseDatabaseObserver, BaseMetricsPlugin, BaseEnricherPlugin, ConfigurationError, PluginError, ValidationError, InitializationError, ShutdownError, DependencyError, CompatibilityError, TimeoutError, QueueError

Functions: compareVersions, satisfiesVersion, checkPluginCompatibility, validatePluginMetadata, validatePluginConfiguration, validateVersionCompatibility, validatePluginDependencies, isValidSemVer, isValidPluginName, validateAgainstSchema, delay, withTimeout, createRetryPolicy, DisposableGroup, generateId, circularSafeStringify, truncate, maskField

Constants: AGSTACK_SDK_VERSION, AGSTACK_MIN_RUNTIME_VERSION, PLUGIN_PRIORITY_HIGHEST, PLUGIN_PRIORITY_HIGH, PLUGIN_PRIORITY_NORMAL, PLUGIN_PRIORITY_LOW, PLUGIN_PRIORITY_LOWEST, DEFAULT_RETRY_COUNT, DEFAULT_TIMEOUT_MS, DEFAULT_QUEUE_MAX_SIZE, DEFAULT_HEALTH_INTERVAL_MS, EVENT_PRIORITY_CRITICAL, EVENT_PRIORITY_HIGH, EVENT_PRIORITY_NORMAL, EVENT_PRIORITY_LOW, HOOK_PRIORITY_FIRST, HOOK_PRIORITY_EARLY, HOOK_PRIORITY_NORMAL, HOOK_PRIORITY_LATE, HOOK_PRIORITY_LAST, DEFAULT_PAYLOAD_CONFIG, DEFAULT_STORAGE_CONFIG, DEFAULT_RUNTIME_CONFIG

Migrating from v1.x

If you were using the old plugin system integrated into the logger:

  1. Install @agstack/plugin-sdk as a dependency
  2. Change import { IPlugin } from "@agstack/logger" to import type { IPlugin } from "@agstack/plugin-sdk"
  3. Change extends Plugin to extends BasePlugin (or implement IPlugin directly)
  4. Update metadata to include supportedRuntimeVersions
  5. Use validatePluginMetadata() instead of inline validation
  6. Import error classes from @agstack/plugin-sdk instead of @agstack/logger

License

MIT