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

planelet-sdk-ts

v0.1.0

Published

TypeScript SDK for building SuperPlane Planelet Plugin servers.

Readme

Planelet SDK for TypeScript

Build Planelet plugin servers that SuperPlane can call directly. The SDK is fetch-native for Bun and ships a small node:http adapter for Node.js, so the same plugin definition works in both runtimes.

Install

bun add planelet-sdk-ts

For local development in this repo:

bun install
bun run check

Bun server

import { createPlugin, defineAction } from "planelet-sdk-ts";

const plugin = createPlugin({
  id: "demo",
  label: "Demo Plugin",
  actions: [
    defineAction({
      id: "echo",
      label: "Echo",
      parameters: [{ id: "message", label: "Message", type: "string", required: true }],
      execute: async ({ parameters, input }) => ({
        success: true,
        data: {
          message: parameters.message,
          input,
        },
      }),
    }),
  ],
  triggers: [],
});

Bun.serve({
  port: 3000,
  fetch: plugin.fetch,
});

Point the Planelet integration in SuperPlane at http://host.docker.internal:3000 when SuperPlane is running in Docker, or at the reachable host/port for your environment. You can edit and restart this local process without building a new SuperPlane container.

Node.js server

import { createNodeServer } from "planelet-sdk-ts/node";
import { createPlugin, defineAction } from "planelet-sdk-ts";

const plugin = createPlugin({
  id: "demo",
  label: "Demo Plugin",
  actions: [
    defineAction({
      id: "echo",
      label: "Echo",
      parameters: [],
      execute: async ({ parameters }) => ({
        success: true,
        data: { parameters },
      }),
    }),
  ],
  triggers: [],
});

createNodeServer(plugin).listen(3000, "127.0.0.1");

Node.js 18.17 or newer is required because the SDK uses the standard Request, Response, and fetch APIs.

Webhook trigger

import { createPlugin, decodeRawBodyText, defineTrigger, firstHeader } from "planelet-sdk-ts";

const plugin = createPlugin({
  id: "webhooks",
  label: "Webhooks",
  actions: [],
  triggers: [
    defineTrigger({
      id: "incoming",
      label: "Incoming Webhook",
      parameters: [],
      setup: async ({ webhook }) => ({
        success: true,
        metadata: { providerWebhookUrl: webhook.url },
      }),
      webhook: async ({ request }) => {
        const signature = firstHeader(request.headers, "x-provider-signature");
        const body = decodeRawBodyText(request.rawBodyBase64);

        if (!signature) {
          return { success: false, error: "Missing signature", status: 401 };
        }

        return {
          success: true,
          emit: true,
          eventType: "incoming.received",
          payload: JSON.parse(body),
        };
      },
      cleanup: async () => ({ success: true }),
    }),
  ],
});

Use metadata for provider webhook IDs or setup state. Do not put secrets in the manifest.

Auth

If the SuperPlane integration is configured with an auth token, require the same bearer token in the plugin:

import { createBearerAuth, createPlugin } from "planelet-sdk-ts";

const plugin = createPlugin({
  id: "secure-demo",
  label: "Secure Demo",
  auth: createBearerAuth(process.env.PLANELET_TOKEN ?? ""),
  actions: [],
  triggers: [],
});

Custom auth can be supplied as a function. Return false to reject the request or throw to return a plugin-level error.

Direct events

Plugins can emit events into SuperPlane without waiting for a third-party webhook:

import { createSuperPlaneClient } from "planelet-sdk-ts";

const superplane = createSuperPlaneClient({
  baseUrl: "https://superplane.example",
  integrationId: "integration-id",
  token: process.env.SUPERPLANE_TOKEN,
});

await superplane.emitEvent({
  eventType: "build.finished",
  payload: { status: "passed" },
});

Plugin API

A Plugin is an HTTP server that exposes a manifest and optional action/trigger endpoints for SuperPlane.

Basics

  • Base URL is configured by the user in SuperPlane.
  • All requests and responses use JSON.
  • All IDs in paths must be URL-safe or URL-escaped.
  • id is a stable machine identifier.
  • label is user-facing display text.
  • icon is a built-in icon slug.
  • iconUrl is a remote image URL. If both are present, SuperPlane should prefer iconUrl.
  • Unknown fields should be ignored for forward compatibility.

Auth

When an auth token is configured on the SuperPlane integration, SuperPlane sends it on every plugin request:

Authorization: Bearer <token>

Third-party webhook auth is provider-specific. SuperPlane forwards raw webhook headers and body to the plugin so the plugin can verify signatures.

Manifest

GET /manifest
type PluginManifest = {
  id: string;
  label: string;
  icon?: string;
  iconUrl?: string;
  description?: string;
  actions: ActionManifest[];
  triggers: TriggerManifest[];
};

type ActionManifest = {
  id: string;
  label: string;
  icon?: string;
  iconUrl?: string;
  description?: string;
  parameters: ParameterManifest[];
};

type TriggerManifest = {
  id: string;
  label: string;
  icon?: string;
  iconUrl?: string;
  description?: string;
  parameters: ParameterManifest[];
};

type ParameterManifest = {
  id: string;
  label: string;
  type: "string" | "text" | "number" | "bool" | "select" | "object";
  description?: string;
  required?: boolean;
  default?: unknown;
  options?: { label: string; value: string }[];
};

Actions

SuperPlane calls this when an action node runs.

POST /actions/{actionId}/execute
Content-Type: application/json
type ExecuteActionRequest = {
  parameters: Record<string, unknown>;
  input?: unknown;
};

type ExecuteActionResponse =
  | { success: true; data: Record<string, unknown> }
  | { success: false; error: string };

Webhook Triggers

All manifest triggers currently use the webhook lifecycle below.

Setup

Called when a configured trigger is published. The plugin should register or update the provider webhook using webhook.url.

POST /triggers/{triggerId}/setup
type SetupTriggerRequest = {
  parameters: Record<string, unknown>;
  webhook: {
    url: string;
    secret?: string;
  };
};

type SetupTriggerResponse =
  | { success: true; metadata?: Record<string, unknown> }
  | { success: false; error: string };

metadata is stored by SuperPlane and passed back to future webhook and cleanup calls.

Webhook Handling

Called after a third party hits SuperPlane's generated webhook URL.

POST /triggers/{triggerId}/webhook
type HandleTriggerWebhookRequest = {
  parameters: Record<string, unknown>;
  metadata?: Record<string, unknown>;
  request: {
    method: string;
    headers: Record<string, string[]>;
    query?: Record<string, string[]>;
    rawBodyBase64: string;
  };
};

type HandleTriggerWebhookResponse =
  | {
      success: true;
      emit: true;
      eventType: string;
      payload: unknown;
      response?: WebhookHttpResponse;
    }
  | {
      success: true;
      emit: false;
      reason?: string;
      response?: WebhookHttpResponse;
    }
  | {
      success: false;
      error: string;
      status?: number;
    };

type WebhookHttpResponse = {
  status?: number;
  headers?: Record<string, string>;
  body?: string;
};

The plugin should verify signatures, handle provider challenges, filter irrelevant events, and return normalized workflow payloads.

Cleanup

Called when the trigger is removed or no longer needs the provider webhook.

POST /triggers/{triggerId}/cleanup
type CleanupTriggerRequest = {
  parameters: Record<string, unknown>;
  metadata?: Record<string, unknown>;
};

type CleanupTriggerResponse = { success: true } | { success: false; error: string };

Direct Events

Plugins may also emit events directly into SuperPlane without a third-party webhook.

POST /api/v1/integrations/{integrationId}/events
Content-Type: application/json
type DirectPluginEvent = {
  eventType: string;
  payload: unknown;
};

Required Behavior

  • Return 404 for unknown actions/triggers.
  • Return { success: false, error } for plugin-level failures.
  • Keep IDs stable once users may have configured workflows with them.
  • Do not put secrets in manifests.
  • Use metadata for provider webhook IDs or other setup state.
  • rawBodyBase64 must be decoded before signature verification.
  • If a webhook should not start a workflow, return { success: true, emit: false }.
  • If a provider requires a challenge response, return emit: false with response.

The SDK routes each endpoint to the matching lifecycle function and returns 404 for unknown actions or triggers. Use decodeRawBodyBase64 or decodeRawBodyText before signature verification.