@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/sdkQuick 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_sessioncookie 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_sessioncookie - 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
With
user_idoption: If you provide auser_idin the init options, it will be used and stored in theappmorph_user_idcookie.Without
user_idoption: A random UUID is generated and stored in theappmorph_user_idcookie. 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
- Submit a task → Task ID becomes the session ID
- Click "Open Stage" → Cookie is set with session ID
- Deploy server reads cookie → Routes to
./deploy/<session_id>/ - 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