SvelteKit Integration Example

This example shows how to integrate the Asterisms JS SDK Backend with a SvelteKit application.

Complete Setup

1. Install Dependencies

npm install @asterisms/sdk-backend @asterisms/sdk @asterisms/common-core

2. Environment Configuration

Create .env file:

# Asterisms Configuration
ASTERISMS_DOMAIN=asterisms.example.com
ASTERISMS_BUNDLE_ID=com.example.myapp
ASTERISMS_SUBDOMAIN=myapp
ASTERISMS_NAME=My App
ASTERISMS_TITLE=My App
ASTERISMS_DESCRIPTION=My Asterisms Application

# Optional: Product Authorization Key
ASTERISMS_PRODUCT_AUTHORIZATION_KEY=your-product-key

3. SDK Instance Setup

Create src/lib/sdkInstance.ts:

import { createSvelteKitBackendSDK, type AsterismsSDKProvider } from '@asterisms/sdk-backend';
import { createFetchAdapter } from '@asterisms/sdk-backend';
import { building } from '$app/environment';
import * as dotenv from 'dotenv';

dotenv.config();

let provider: AsterismsSDKProvider | null = null;

export function useAsterismsBackendSDK(): AsterismsSDKProvider | undefined {
  if (building) return undefined;
  if (provider) return provider;

  try {
    provider = createSvelteKitBackendSDK({
      env: process.env,
      building,
      httpFactory: createFetchAdapter(fetch),
      registrationData: {
        bundleId: 'com.example.myapp',
        capabilities: ['FRONTEND_WEBSITE'],
        description: 'My Asterisms Application',
        name: 'My App',
        subdomain: 'myapp',
        title: 'My App',
        icon: 'app',
        group: 'apps'
      }
    });

    return provider;
  } catch (error) {
    console.error('Failed to initialize Asterisms JS SDK:', error);
    return undefined;
  }
}

export function getSDK() {
  const provider = useAsterismsBackendSDK();
  return provider?.sdk;
}

4. Hooks Setup

Create or update src/hooks.server.ts:

import { useAsterismsBackendSDK } from '$lib/sdkInstance';
import type { Handle } from '@sveltejs/kit';
import { sequence } from '@sveltejs/kit/hooks';

const asterismsHandle: Handle = async ({ event, resolve }) => {
  const provider = useAsterismsBackendSDK();

  if (provider) {
    try {
      // Boot the SDK
      await provider.bootSDK();

      // Make SDK available in locals
      event.locals.sdk = provider.sdk;

      // Handle Asterisms backend core API routes
      if (event.url.pathname.startsWith('/api/asterisms')) {
        return provider.apiRouter(event);
      }
    } catch (error) {
      console.error('SDK boot error:', error);
    }
  }

  return resolve(event);
};

const customHandle: Handle = async ({ event, resolve }) => {
  // Your custom logic here
  return resolve(event);
};

export const handle = sequence(asterismsHandle, customHandle);

5. TypeScript Definitions

Create or update src/app.d.ts:

import type { AsterismsBackendSDK } from '@asterisms/sdk-backend';

declare global {
  namespace App {
    interface Locals {
      sdk?: AsterismsBackendSDK;
    }

    interface PageData {
      user?: {
        id: string;
        name: string;
        email: string;
      };
    }
  }
}

export {};

6. API Routes

Create src/routes/api/user/+server.ts:

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async ({ locals }) => {
  try {
    const sdk = locals.sdk;
    if (!sdk) {
      return json({ error: 'SDK not available' }, { status: 503 });
    }

    // Use authorization service
    const auth = sdk.authorization();
    const user = await auth.getCurrentUser();

    return json({ user });
  } catch (error) {
    console.error('User API error:', error);
    return json({ error: 'Failed to get user' }, { status: 500 });
  }
};

export const POST: RequestHandler = async ({ request, locals }) => {
  try {
    const sdk = locals.sdk;
    if (!sdk) {
      return json({ error: 'SDK not available' }, { status: 503 });
    }

    const data = await request.json();

    // Use storage service
    const storage = sdk.storage();
    await storage.set(`user-data-${data.userId}`, data);

    return json({ success: true });
  } catch (error) {
    console.error('User data save error:', error);
    return json({ error: 'Failed to save user data' }, { status: 500 });
  }
};

7. Page Load Functions

Create src/routes/+layout.server.ts:

import type { LayoutServerLoad } from './$types';

export const load: LayoutServerLoad = async ({ locals }) => {
  const sdk = locals.sdk;

  if (!sdk) {
    return {
      user: null
    };
  }

  try {
    const auth = sdk.authorization();
    const user = await auth.getCurrentUser();

    return {
      user: user
        ? {
            id: user.id,
            name: user.name,
            email: user.email
          }
        : null
    };
  } catch (error) {
    console.error('Layout load error:', error);
    return {
      user: null
    };
  }
};

8. Svelte Components

Create src/routes/+layout.svelte:

<script lang="ts">
    import type { LayoutData } from './$types';

    export let data: LayoutData;

    $: user = data.user;
</script>

<div class="app">
    <header>
        <h1>My Asterisms App</h1>
        {#if user}
            <p>Welcome, {user.name}!</p>
        {:else}
            <p>Please log in</p>
        {/if}
    </header>

    <main>
        <slot />
    </main>
</div>

<style>
    .app {
        max-width: 1200px;
        margin: 0 auto;
        padding: 20px;
    }

    header {
        border-bottom: 1px solid #eee;
        padding-bottom: 20px;
        margin-bottom: 20px;
    }
</style>

9. Dashboard Page

Create src/routes/dashboard/+page.server.ts:

import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ locals }) => {
  const sdk = locals.sdk;

  if (!sdk) {
    return {
      notifications: [],
      userData: null
    };
  }

  try {
    const auth = sdk.authorization();
    const storage = sdk.storage();

    const user = await auth.getCurrentUser();
    if (!user) {
      return {
        notifications: [],
        userData: null
      };
    }

    // Get user data from storage
    const userData = await storage.get(`user-data-${user.id}`);

    return {
      notifications: [],
      userData
    };
  } catch (error) {
    console.error('Dashboard load error:', error);
    return {
      notifications: [],
      userData: null
    };
  }
};

Create src/routes/dashboard/+page.svelte:

<script lang="ts">
    import type { PageData } from './$types';

    export let data: PageData;

    let message = '';
    let sending = false;

    async function sendNotification() {
        sending = true;
        try {
            const response = await fetch('/api/notifications', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    title: 'Test Notification',
                    message: message
                })
            });

            if (response.ok) {
                message = '';
                alert('Notification sent!');
            } else {
                alert('Failed to send notification');
            }
        } catch (error) {
            console.error('Send notification error:', error);
            alert('Error sending notification');
        } finally {
            sending = false;
        }
    }
</script>

<div class="dashboard">
    <h2>Dashboard</h2>

    {#if data.userData}
        <div class="user-data">
            <h3>User Data</h3>
            <pre>{JSON.stringify(data.userData, null, 2)}</pre>
        </div>
    {/if}

    <div class="notification-form">
        <h3>Send Notification</h3>
        <textarea
            bind:value={message}
            placeholder="Enter notification message..."
            rows="3"
        ></textarea>
        <button
            on:click={sendNotification}
            disabled={sending || !message.trim()}
        >
            {sending ? 'Sending...' : 'Send Notification'}
        </button>
    </div>
</div>

<style>
    .dashboard {
        max-width: 800px;
        margin: 0 auto;
    }

    .user-data {
        background: #f5f5f5;
        padding: 20px;
        border-radius: 8px;
        margin-bottom: 20px;
    }

    .notification-form {
        background: white;
        padding: 20px;
        border: 1px solid #ddd;
        border-radius: 8px;
    }

    textarea {
        width: 100%;
        margin-bottom: 10px;
        padding: 10px;
        border: 1px solid #ddd;
        border-radius: 4px;
    }

    button {
        background: #007bff;
        color: white;
        border: none;
        padding: 10px 20px;
        border-radius: 4px;
        cursor: pointer;
    }

    button:disabled {
        background: #ccc;
        cursor: not-allowed;
    }
</style>

10. Notification API

Create src/routes/api/notifications/+server.ts:

import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';

export const POST: RequestHandler = async ({ request, locals }) => {
  try {
    const sdk = locals.sdk;
    if (!sdk) {
      return json({ error: 'SDK not available' }, { status: 503 });
    }

    const { title, message } = await request.json();

    if (!title || !message) {
      return json({ error: 'Title and message are required' }, { status: 400 });
    }

    // Get current user
    const auth = sdk.authorization();
    const user = await auth.getCurrentUser();

    if (!user) {
      return json({ error: 'User not authenticated' }, { status: 401 });
    }

    // Send notification
    const notifications = sdk.notifications();
    await notifications.sendToUser(user.id, {
      title,
      message
    });

    return json({ success: true });
  } catch (error) {
    console.error('Notification API error:', error);
    return json({ error: 'Failed to send notification' }, { status: 500 });
  }
};

Package.json Scripts

Add these scripts to your package.json:

{
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
    "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
    "lint": "eslint .",
    "format": "prettier --write ."
  }
}

Running the Application

  1. Install dependencies:

    npm install
  2. Configure environment variables in .env

  3. Start development server:

    npm run dev
  4. Visit http://localhost:5173

Key Features Demonstrated

SDK Integration

  • Proper SvelteKit integration with createSvelteKitBackendSDK
  • Environment-based configuration
  • Graceful handling of build-time vs runtime

Authentication

  • User authentication through authorization service
  • Protected API routes
  • User data in page loads

Storage

  • Storing and retrieving user data
  • Async storage operations
  • Error handling

Notifications

  • Sending notifications to users
  • API endpoint for notifications
  • Frontend integration

Error Handling

  • Comprehensive error handling
  • User-friendly error messages
  • Graceful fallbacks

Production Considerations

Security

  • Use HTTPS in production
  • Validate all user inputs
  • Implement proper rate limiting
  • Use secure environment variables

Performance

  • Implement caching strategies
  • Use database connections efficiently
  • Monitor SDK performance
  • Optimize bundle sizes

Monitoring

  • Add structured logging
  • Monitor API endpoints
  • Track user interactions
  • Set up error tracking

Next Steps

  1. Authentication Examples - Advanced auth patterns
  2. Storage Examples - Data management strategies
  3. Notification Examples - Notification patterns
  4. Testing Strategies - Testing your application

Troubleshooting

Common issues and solutions:

SDK Not Initializing

  • Check environment variables
  • Verify domain configuration
  • Ensure proper bundle ID

Build Errors

  • Verify TypeScript configuration
  • Check import paths
  • Ensure all dependencies installed

Runtime Errors

  • Check browser console
  • Verify API endpoints
  • Test SDK boot process

For more help, see the Troubleshooting Guide.