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

@aimform/apps

v0.1.1

Published

Aimform App Store SDK — define, validate, and publish apps for the Aimform platform

Readme

@aimform/apps

The official SDK for building, validating, and publishing apps on the Aimform platform.

@aimform/apps gives third-party developers everything they need to define app manifests, entity types, tools, onboarding flows, and profile sections — all with full TypeScript support and runtime validation via Zod.

Installation

npm install @aimform/apps
# or
pnpm add @aimform/apps

Quick Start

Use defineApp() to create a complete app manifest:

import { defineApp } from "@aimform/apps";

const myApp = defineApp({
  id: "my-slack-bot",
  name: "Slack Bot",
  version: "1.0.0",
  avatar: "https://example.com/slack-icon.png",
  description: "Bring Slack messages into Aimform.",
  category: "communication",
  entryPoint: {
    type: "mcp",
    url: "https://slack-bot.example.com/mcp",
  },
  auth: {
    type: "oauth2",
    provider: "slack",
  },
  declaresEntityTypes: [
    {
      name: "slack_message",
      properties: [
        { name: "text", type: "text", label: "Message", required: true },
        { name: "channel", type: "string", label: "Channel" },
        { name: "sent_at", type: "date", label: "Sent" },
      ],
    },
  ],
  scopes: {
    read: ["slack_message"],
    write: ["slack_message"],
  },
  tools: [
    {
      name: "send_slack_message",
      description: "Send a message to a Slack channel",
      riskTier: "confirm",
      exposedToAi: true,
      inputSchema: {
        type: "object",
        properties: {
          channel: { type: "string" },
          text: { type: "string" },
        },
        required: ["channel", "text"],
      },
    },
  ],
  onboarding: {
    steps: [
      {
        id: "connect-slack",
        type: "oauth_connect",
        title: "Connect your Slack workspace",
        provider: "slack",
      },
    ],
  },
  profile: {
    sections: [
      {
        id: "recent-messages",
        type: "view",
        title: "Recent Messages",
        entityType: "slack_message",
        fields: ["text", "channel", "sent_at"],
        defaultSort: "sent_at",
      },
    ],
  },
});

Entity Types

Entity types define the data model your app brings into Aimform. Use the fluent builder or inline array syntax:

import { defineEntityType } from "@aimform/apps";

// Fluent builder
const taskEntity = defineEntityType("task")
  .addProperty("title", "string", { label: "Title", required: true, searchable: true })
  .addProperty("status", "string", { label: "Status" })
  .addProperty("due_date", "date", { label: "Due Date" })
  .build();

// Inline array
const noteEntity = defineEntityType("note", [
  { name: "title", type: "string", label: "Title", required: true },
  { name: "content", type: "text", label: "Content", searchable: true },
  { name: "created_at", type: "date", label: "Created" },
]);

Tools

Tools are actions exposed by your app that users and the AI assistant can invoke:

import { defineTool } from "@aimform/apps";

// Safe read-only tool (auto-executable)
const searchTasks = defineTool({
  name: "search_tasks",
  description: "Search tasks by title or status",
  riskTier: "auto",
  exposedToAi: true,
  inputSchema: {
    type: "object",
    properties: {
      query: { type: "string", description: "Search query" },
    },
    required: ["query"],
  },
});

// Write operation (requires user confirmation)
const createTask = defineTool({
  name: "create_task",
  description: "Create a new task",
  riskTier: "confirm",
  exposedToAi: true,
  inputSchema: {
    type: "object",
    properties: {
      title: { type: "string", description: "Task title" },
      dueDate: { type: "string", description: "Due date (ISO 8601)" },
    },
    required: ["title"],
  },
});

// Blocked tool (requires explicit user action)
const deleteTask = defineTool({
  name: "delete_task",
  description: "Permanently delete a task",
  riskTier: "blocked",
  exposedToAi: false,
  inputSchema: {
    type: "object",
    properties: {
      taskId: { type: "string", description: "Task ID" },
    },
    required: ["taskId"],
  },
});

Risk Tiers

| Tier | Behavior | |------|----------| | auto | Executes automatically without user confirmation. Use for safe read-only operations. | | confirm | Requires user confirmation before execution. Use for write/delete operations. | | blocked | Never auto-executes. Requires explicit user trigger. Use for dangerous or irreversible actions. |

Onboarding Steps

Onboarding steps guide users through connecting your app:

import { defineOnboardingStep } from "@aimform/apps";

// OAuth2 connection
const connectStep = defineOnboardingStep({
  id: "connect",
  type: "oauth_connect",
  title: "Connect your account",
  description: "Authorize access to your data.",
  provider: "google",
});

// API key entry
const apiKeyStep = defineOnboardingStep({
  id: "api-key",
  type: "api_key_form",
  title: "Enter your API key",
  description: "Find your API key in your account settings.",
  apiKeyLabel: "API Key",
  apiKeyHelpText: "Paste the API key from your provider dashboard.",
});

// Permission review
const reviewStep = defineOnboardingStep({
  id: "review",
  type: "permission_review",
  title: "Review permissions",
  description: "This app will be able to read your emails.",
});

// Custom setup
const customStep = defineOnboardingStep({
  id: "setup",
  type: "custom",
  title: "Configure your workspace",
  customUrl: "https://my-app.example.com/setup",
});

Profile Sections

Profile sections display your app's data in Aimform entity detail views:

import { defineProfileSection } from "@aimform/apps";

// Table/list view
const listView = defineProfileSection({
  id: "recent-items",
  type: "view",
  title: "Recent Items",
  entityType: "task",
  fields: ["title", "status", "due_date"],
  defaultSort: "due_date",
});

// Document view (rich content)
const docView = defineProfileSection({
  id: "note-content",
  type: "document",
  title: "Note",
  entityType: "note",
  documentType: "text/markdown",
});

// Freeform board
const board = defineProfileSection({
  id: "kanban",
  type: "space",
  title: "Project Board",
  entityType: "task",
});

Full Gmail App Example

A complete Gmail app manifest using all the SDK features:

import {
  defineApp,
  defineEntityType,
  defineTool,
  defineOnboardingStep,
  defineProfileSection,
  defineScopes,
} from "@aimform/apps";

const gmail = defineApp({
  id: "gmail",
  name: "Gmail",
  version: "1.0.0",
  avatar: "https://example.com/gmail-icon.png",
  description: "Read, search, and send emails from Gmail.",
  category: "communication",
  entryPoint: {
    type: "mcp",
    url: "https://gmail-app.example.com/mcp",
  },
  auth: {
    type: "oauth2",
    provider: "google",
  },
  declaresEntityTypes: [
    defineEntityType("email_thread", [
      { name: "subject", type: "string", label: "Subject", required: true, searchable: true },
      { name: "snippet", type: "text", label: "Snippet", searchable: true },
      { name: "sender", type: "email", label: "Sender" },
      { name: "recipients", type: "json", label: "Recipients" },
      { name: "received_at", type: "date", label: "Received" },
      { name: "is_read", type: "boolean", label: "Read" },
      { name: "labels", type: "json", label: "Labels" },
    ]) as ReturnType<typeof defineEntityType>,
  ],
  scopes: defineScopes(["email_thread"], ["email_thread"]),
  tools: [
    defineTool({
      name: "search_emails",
      description: "Search Gmail messages by query",
      riskTier: "auto",
      exposedToAi: true,
      inputSchema: {
        type: "object",
        properties: {
          query: { type: "string", description: "Gmail search query (supports Gmail search operators)" },
          maxResults: { type: "number", description: "Maximum results to return", default: 10 },
        },
        required: ["query"],
      },
    }),
    defineTool({
      name: "get_email",
      description: "Get full content of a specific email",
      riskTier: "auto",
      exposedToAi: true,
      inputSchema: {
        type: "object",
        properties: {
          emailId: { type: "string", description: "Email message ID" },
        },
        required: ["emailId"],
      },
    }),
    defineTool({
      name: "send_email",
      description: "Send an email via Gmail",
      riskTier: "confirm",
      exposedToAi: true,
      inputSchema: {
        type: "object",
        properties: {
          to: { type: "string", description: "Recipient email address(es)" },
          cc: { type: "string", description: "CC recipients" },
          subject: { type: "string", description: "Email subject" },
          body: { type: "string", description: "Email body (plain text or HTML)" },
        },
        required: ["to", "subject", "body"],
      },
    }),
    defineTool({
      name: "delete_email",
      description: "Delete an email (moves to trash)",
      riskTier: "confirm",
      exposedToAi: true,
      inputSchema: {
        type: "object",
        properties: {
          emailId: { type: "string", description: "Email message ID" },
        },
        required: ["emailId"],
      },
    }),
  ],
  onboarding: {
    steps: [
      defineOnboardingStep({
        id: "connect-gmail",
        type: "oauth_connect",
        title: "Connect your Gmail account",
        description: "We'll redirect you to Google to authorize access to your Gmail.",
        provider: "google",
      }),
      defineOnboardingStep({
        id: "review-permissions",
        type: "permission_review",
        title: "Review permissions",
        description: "This app needs access to read, search, and send emails from your Gmail account.",
      }),
    ],
  },
  profile: {
    sections: [
      defineProfileSection({
        id: "recent-emails",
        type: "view",
        title: "Recent Emails",
        entityType: "email_thread",
        fields: ["subject", "snippet", "sender", "received_at", "is_read"],
        defaultSort: "received_at",
      }),
      defineProfileSection({
        id: "email-content",
        type: "document",
        title: "Email Body",
        entityType: "email_thread",
        documentType: "text/html",
      }),
    ],
  },
});

Validation

The SDK includes runtime validation via Zod schemas, accessible from the server entry point:

import { validateManifest, scanApp } from "@aimform/apps/server";

// Validate a manifest loaded from JSON
const rawManifest = JSON.parse(
  await Deno.readTextFile("aimform.manifest.json"),
);
const result = validateManifest(rawManifest);

if (!result.success) {
  console.error("Manifest is invalid:");
  for (const error of result.errors) {
    console.error(`  - ${error}`);
  }
  process.exit(1);
}

// Deep scan for warnings and blocking issues
const report = scanApp(result.data);

if (!report.passed) {
  console.error("Scan found blocking issues:");
  for (const error of report.errors) {
    console.error(`  - ${error}`);
  }
}

if (report.warnings.length > 0) {
  console.warn("Warnings (non-blocking):");
  for (const warning of report.warnings) {
    console.warn(`  - ${warning}`);
  }
}

API Reference

Main Entry (@aimform/apps)

| Export | Description | |--------|-------------| | defineApp(manifest) | Create a complete app manifest | | defineEntityType(name, properties?) | Define an entity type (returns builder or declaration) | | defineTool(config) | Define a tool/action | | defineOnboardingStep(step) | Define an onboarding step | | defineProfileSection(section) | Define a profile section | | defineScopes(read, write?) | Define scoped permissions | | OAUTH2_PROVIDERS | Constants for known OAuth2 providers | | InferAppManifest<T> | Infer the type of a specific manifest |

Server Entry (@aimform/apps/server)

| Export | Description | |--------|-------------| | validateManifest(input) | Validate unknown input against the manifest schema | | scanApp(manifest) | Deep scan a manifest for warnings and errors | | aimformAppManifestSchema | Raw Zod schema for custom validation logic |

Client Entry (@aimform/apps/client)

Type-only exports for browser-safe imports. All manifest types are re-exported: AimformAppManifest, ToolDeclaration, EntityTypeDeclaration, AppScopes, etc.

Types

AimformAppManifest

The top-level manifest type. See the Quick Start example for full shape.

EntityTypeDeclaration

interface EntityTypeDeclaration {
  name: string;
  properties: PropertyDefinition[];
}

ToolDeclaration

interface ToolDeclaration {
  name: string;
  description?: string;
  riskTier: "auto" | "confirm" | "blocked";
  exposedToAi: boolean;
  inputSchema?: Record<string, unknown>;
}

OnboardingStep

interface OnboardingStep {
  id: string;
  type: "oauth_connect" | "api_key_form" | "permission_review" | "custom";
  title: string;
  description?: string;
  provider?: string;
  apiKeyLabel?: string;
  apiKeyHelpText?: string;
  customUrl?: string;
}

ProfileSection

interface ProfileSection {
  id: string;
  type: "view" | "document" | "space";
  title: string;
  entityType?: string;
  fields?: string[];
  defaultSort?: string;
  documentType?: string;
}

AuthConfig

interface AuthConfig {
  type: "oauth2" | "api_key" | "none";
  provider?: string;
}

EntryPointConfig

interface EntryPointConfig {
  type: "mcp" | "sandboxed_code" | "external_call";
  url?: string;
}

License

MIT