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

@appmorph/sdk

v0.1.5

Published

Appmorph SDK - Embeddable widget for AI-powered app customization

Readme

@appmorph/sdk

Embeddable widget for Appmorph. Allows users to customize applications using natural language prompts.

Installation

npm install @appmorph/sdk
# or
pnpm add @appmorph/sdk
# or
yarn add @appmorph/sdk

Quick Start

import Appmorph, { createStaticAuthAdapter } from '@appmorph/sdk';

// Initialize the widget
Appmorph.init({
  endpoint: 'http://localhost:3002',  // API server
  auth: createStaticAuthAdapter(),
  position: 'bottom-right',
  theme: 'auto',
  buttonLabel: 'Customize',
});

Features

Real-time Progress Streaming

When a task is submitted, the widget shows real-time output from the AI agent as it modifies your code.

Open Stage

After a task completes, click "Open Stage" to view the modified version:

  • Sets the appmorph_session cookie with your session ID
  • Opens the deploy server URL in a new tab
  • The deploy server routes to your modified variant based on the cookie

Revert to Default

When viewing a modified version (cookie exists), the widget shows a "Revert" button:

  • Deletes the appmorph_session cookie
  • Refreshes the page to load the default version

This allows seamless switching between the original and modified versions.

Bundle Formats

The SDK is available in multiple formats:

| Format | File | Size (gzipped) | |--------|------|----------------| | ESM | dist/appmorph.js | ~10KB | | UMD | dist/appmorph.umd.cjs | ~9KB |

ESM (Recommended)

import Appmorph from '@appmorph/sdk';

UMD (Browser Global)

<script src="https://unpkg.com/@appmorph/sdk/dist/appmorph.umd.cjs"></script>
<script>
  window.Appmorph.default.init({ ... });
</script>

API Reference

Appmorph.init(options)

Initialize the SDK and render the widget.

interface AppmorphInitOptions {
  // Required: Backend endpoint URL
  endpoint: string;

  // Required: Authentication adapter
  auth: AuthAdapter;

  // Widget position (default: 'bottom-right')
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';

  // Color theme (default: 'auto')
  theme?: 'light' | 'dark' | 'auto';

  // Button label (default: icon only)
  buttonLabel?: string;

  // Optional: User ID for persistence tracking
  // If not provided, a random UUID is generated and stored in appmorph_user_id cookie
  user_id?: string;
}

Appmorph.open()

Programmatically open the widget panel.

Appmorph.open();

Appmorph.close()

Programmatically close the widget panel.

Appmorph.close();

Appmorph.isOpen()

Check if the widget panel is currently open.

if (Appmorph.isOpen()) {
  console.log('Widget is open');
}

Appmorph.destroy()

Remove the widget and clean up resources.

Appmorph.destroy();

Appmorph.submitPrompt(prompt)

Submit a prompt programmatically (without using the widget UI).

const response = await Appmorph.submitPrompt('Add a logout button');
console.log('Task created:', response.taskId);

Appmorph.getTaskStatus(taskId)

Get the status of a task.

const status = await Appmorph.getTaskStatus('task-uuid');
console.log('Status:', status.task.status);

Auth Adapters

The SDK requires an auth adapter to provide user context and authentication tokens.

Static Adapter

For simple use cases. Can be called with no arguments for anonymous access:

import { createStaticAuthAdapter } from '@appmorph/sdk';

// Simple anonymous usage
const auth = createStaticAuthAdapter();

// Or with custom user context and token
const auth = createStaticAuthAdapter(
  { userId: 'user-123', groupIds: ['team-a'] },
  'static-token'
);

Callback Adapter

For dynamic credentials from your auth system:

import { createCallbackAuthAdapter } from '@appmorph/sdk';

const auth = createCallbackAuthAdapter(
  async () => {
    // Fetch user context from your auth system
    const user = await myAuthService.getCurrentUser();
    return {
      userId: user.id,
      groupIds: user.teams.map(t => t.id),
      tenantId: user.organizationId,
      roles: user.roles,
    };
  },
  async () => {
    // Get current auth token
    return myAuthService.getAccessToken();
  }
);

localStorage Adapter

For apps that store auth in localStorage:

import { createLocalStorageAuthAdapter } from '@appmorph/sdk';

const auth = createLocalStorageAuthAdapter(
  'auth_token',      // localStorage key for token
  'user_context'     // localStorage key for user context JSON
);

Custom Adapter

Implement the AuthAdapter interface directly:

import type { AuthAdapter, UserContext } from '@appmorph/sdk';

const customAuth: AuthAdapter = {
  async getUserContext(): Promise<UserContext> {
    return {
      userId: 'user-123',
      groupIds: ['team-a'],
      tenantId: 'acme',
      roles: ['admin'],
    };
  },
  async getAuthToken(): Promise<string> {
    return 'your-token';
  },
};

Styling

The widget uses CSS custom properties scoped to [data-appmorph]. You can override these in your CSS:

[data-appmorph] {
  --appmorph-primary: #6366f1;
  --appmorph-primary-hover: #818cf8;
  --appmorph-bg: #ffffff;
  --appmorph-bg-panel: #f8fafc;
  --appmorph-text: #1a202c;
  --appmorph-text-muted: #718096;
  --appmorph-border: #e2e8f0;
}

/* Dark mode overrides */
[data-appmorph][data-theme="dark"] {
  --appmorph-bg: #1a1a2e;
  --appmorph-bg-panel: #16213e;
  --appmorph-text: #eaeaea;
  --appmorph-text-muted: #a0a0a0;
  --appmorph-border: #2d3748;
  --appmorph-primary: #6366f1;
  --appmorph-primary-hover: #818cf8;
}

User Identification

The SDK automatically manages user identification for persistence tracking.

How It Works

  1. With user_id option: If you provide a user_id in the init options, it will be used and stored in the appmorph_user_id cookie.

  2. Without user_id option: A random UUID is generated and stored in the appmorph_user_id cookie. This ID persists across sessions.

// Explicit user ID
Appmorph.init({
  endpoint: 'http://localhost:3002',
  auth,
  user_id: 'my-user-123'  // Will be stored in cookie
});

// Auto-generated user ID
Appmorph.init({
  endpoint: 'http://localhost:3002',
  auth
  // appmorph_user_id cookie will be created automatically with a UUID
});

The appmorph_user_id is sent with every API request via the X-Appmorph-User-Id header and is used by the backend for task persistence.

Session Management

The SDK uses cookies for session management:

| Cookie | Purpose | |--------|---------| | appmorph_user_id | Persistent user identifier for task tracking | | appmorph_session | Stores the current session ID for modified versions |

How Sessions Work

  1. Submit a task → Task ID becomes the session ID
  2. Click "Open Stage" → Cookie is set with session ID
  3. Deploy server reads cookie → Routes to ./deploy/<session_id>/
  4. Click "Revert" → Cookie is deleted, page refreshes to default

Manual Cookie Management

// Check if viewing a modified version
const hasSession = document.cookie.includes('appmorph_session=');

// Clear session manually
document.cookie = 'appmorph_session=; path=/; max-age=0';

TypeScript

The SDK is written in TypeScript and includes full type definitions:

import Appmorph, {
  AppmorphInitOptions,
  AppmorphSDK,
  AuthAdapter,
  UserContext,
} from '@appmorph/sdk';

Framework Integration

React

import { useEffect } from 'react';
import Appmorph, { createCallbackAuthAdapter } from '@appmorph/sdk';
import { useAuth } from './auth-context';

function App() {
  const { user, getToken } = useAuth();

  useEffect(() => {
    if (!user) return;

    const auth = createCallbackAuthAdapter(
      async () => ({
        userId: user.id,
        groupIds: user.teams,
      }),
      getToken
    );

    Appmorph.init({
      endpoint: process.env.REACT_APP_APPMORPH_URL!,
      auth,
    });

    return () => Appmorph.destroy();
  }, [user, getToken]);

  return <div>Your app content</div>;
}

Vue

<script setup>
import { onMounted, onUnmounted } from 'vue';
import Appmorph, { createStaticAuthAdapter } from '@appmorph/sdk';

onMounted(() => {
  Appmorph.init({
    endpoint: import.meta.env.VITE_APPMORPH_URL,
    auth: createStaticAuthAdapter(),
  });
});

onUnmounted(() => {
  Appmorph.destroy();
});
</script>

Development

# Build the SDK
pnpm build

# Watch mode
pnpm dev

# Type check
pnpm typecheck