Registration Services

Learn how to register your application with the Asterisms ecosystem using the SDK Backend.

Overview

The registration service handles application registration within the Asterisms ecosystem. Registration typically happens automatically during SDK initialization, but you can also manually register your application when needed.

Basic Usage

Getting the Registration Service

const registration = sdk.registration();

Get Application Information

// Get current product information
const information = sdk.information();
const currentProduct = information.currentProduct();

console.log('Current Product:', {
  bundleId: currentProduct.bundleId,
  name: currentProduct.name,
  version: currentProduct.version,
  capabilities: currentProduct.capabilities,
  subdomain: currentProduct.subdomain,
  description: currentProduct.description
});

// Get root domain
const rootDomain = information.rootDomain();
console.log('Root Domain:', rootDomain);

Manual Registration

import { type ProductRegistrationData } from '@asterisms/common-core';

try {
  const registrationData: ProductRegistrationData = {
    product: {
      bundleId: 'com.example.myapp',
      name: 'MyApp',
      title: 'My Business App',
      description: 'A comprehensive business management application',
      subdomain: 'myapp',
      capabilities: ['FRONTEND_WEBSITE', 'API_SERVICE'],
      group: 'productivity',
      version: '1.0.0',
      build: 'abc123',
      sdktype: 'JAVASCRIPT'
    },
    version: '1.0.0',
    build: 'abc123',
    sdktype: 'JAVASCRIPT'
  };

  const response = await registration.register(registrationData);
  console.log('Registration successful:', response.entity.product);
} catch (error) {
  console.error('Registration failed:', error);
}

Application Registration

Registration Data Structure

import { type ProductRegistrationData, type RegistrationData } from '@asterisms/common-core';

interface ProductRegistrationData {
  product: RegistrationData;
  version: string;
  build: string;
  sdktype: 'JAVASCRIPT';
  supportedFeatures?: SupportedFeature[];
  frontendWebsites?: RegistrationData[];
}

interface RegistrationData {
  bundleId: string;
  name: string;
  title: string;
  description: string;
  subdomain: string;
  capabilities: ProductCapability[];
  group?: string;
  version: string;
  build: string;
  sdktype: 'JAVASCRIPT';
  icon?: string;
  order?: number;
}

SDK Initialization Registration

// Registration typically happens automatically during SDK initialization
const sdk = getAsterismsBackendSDK({
  bundleId: 'com.example.myapp',
  domain: 'asterisms.example.com',
  subdomain: 'myapp',
  httpServiceAdapterFactory: createFetchAdapter(fetch),
  registrationData: {
    bundleId: 'com.example.myapp',
    name: 'MyApp',
    title: 'My Business App',
    description: 'A comprehensive business management application',
    subdomain: 'myapp',
    capabilities: ['FRONTEND_WEBSITE', 'API_SERVICE'],
    group: 'productivity',
    version: '1.0.0',
    build: 'abc123',
    sdktype: 'JAVASCRIPT',
    icon: 'business',
    order: 1
  }
});

// Boot the SDK to trigger registration
await sdk.boot();

Application Capabilities

Standard Capabilities

import { type ProductCapability } from '@asterisms/common-core';

const CAPABILITIES: ProductCapability[] = ['API_SERVICE', 'FRONTEND_WEBSITE', 'DASHBOARD_DATA'];

// Example usage
const registrationData = {
  product: {
    bundleId: 'com.example.myapp',
    name: 'MyApp',
    title: 'My Business App',
    description: 'A comprehensive business management application',
    subdomain: 'myapp',
    capabilities: ['FRONTEND_WEBSITE', 'API_SERVICE'],
    group: 'productivity',
    version: '1.0.0',
    build: 'abc123',
    sdktype: 'JAVASCRIPT' as const
  },
  version: '1.0.0',
  build: 'abc123',
  sdktype: 'JAVASCRIPT' as const
};

Checking Current Product Information

function getCurrentProductInfo() {
  const information = sdk.information();
  const currentProduct = information.currentProduct();

  console.log('Current Product Information:', {
    bundleId: currentProduct.bundleId,
    name: currentProduct.name,
    capabilities: currentProduct.capabilities,
    version: currentProduct.version,
    build: currentProduct.build,
    subdomain: currentProduct.subdomain,
    description: currentProduct.description
  });

  return currentProduct;
}

SvelteKit Integration

Registration Information API Route

// src/routes/api/registration/+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 });
    }

    const information = sdk.information();
    const currentProduct = information.currentProduct();
    const rootDomain = information.rootDomain();

    return json({
      product: currentProduct,
      rootDomain,
      success: true
    });
  } catch (error) {
    console.error('Registration API error:', error);
    return json({ error: 'Failed to get registration info' }, { status: 500 });
  }
};

Manual Registration API Route

// src/routes/api/registration/register/+server.ts
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { type ProductRegistrationData } from '@asterisms/common-core';

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

    const registrationData: ProductRegistrationData = await request.json();

    // Validate required fields
    if (!registrationData.product?.bundleId || !registrationData.product?.name) {
      return json({ error: 'BundleId and name are required' }, { status: 400 });
    }

    // Check authorization
    const auth = sdk.authorization();
    const currentUser = await auth.getCurrentUser();
    if (!currentUser) {
      return json({ error: 'Authentication required' }, { status: 401 });
    }

    const registration = sdk.registration();
    const response = await registration.register(registrationData);

    return json({
      success: true,
      entity: response.entity
    });
  } catch (error) {
    console.error('Registration API error:', error);
    return json({ error: 'Registration failed' }, { status: 500 });
  }
};

Registration Component

<!-- src/lib/components/AppRegistration.svelte -->
<script lang="ts">
    import { onMount } from 'svelte';

    interface ProductInfo {
        bundleId: string;
        name: string;
        title: string;
        description: string;
        capabilities: string[];
        version: string;
        subdomain: string;
        icon?: string;
        group?: string;
    }

    let productInfo: ProductInfo | null = null;
    let loading = true;
    let error: string | null = null;
    let rootDomain = '';

    onMount(async () => {
        await loadProductInfo();
    });

    async function loadProductInfo() {
        try {
            loading = true;
            error = null;

            const response = await fetch('/api/registration');
            if (!response.ok) {
                throw new Error('Failed to load product info');
            }

            const data = await response.json();
            productInfo = data.product;
            rootDomain = data.rootDomain;
        } catch (err) {
            error = err instanceof Error ? err.message : 'Unknown error';
        } finally {
            loading = false;
        }
    }

    function getCapabilityDescription(capability: string): string {
        const descriptions: Record<string, string> = {
            'API_SERVICE': 'Provides API endpoints for other services',
            'FRONTEND_WEBSITE': 'Serves web interface to users',
            'DASHBOARD_DATA': 'Provides data for dashboard displays'
        };
        return descriptions[capability] || 'Unknown capability';
    }
</script>

<div class="app-registration">
    <h3>Application Registration</h3>

    {#if loading}
        <div class="loading">Loading product information...</div>
    {:else if error}
        <div class="error">Error: {error}</div>
        <button on:click={loadProductInfo}>Retry</button>
    {:else if productInfo}
        <div class="product-info">
            <div class="info-grid">
                <div class="info-item">
                    <label>Bundle ID:</label>
                    <span>{productInfo.bundleId}</span>
                </div>
                <div class="info-item">
                    <label>Name:</label>
                    <span>{productInfo.name}</span>
                </div>
                <div class="info-item">
                    <label>Title:</label>
                    <span>{productInfo.title}</span>
                </div>
                <div class="info-item">
                    <label>Subdomain:</label>
                    <span>{productInfo.subdomain}.{rootDomain}</span>
                </div>
                <div class="info-item">
                    <label>Version:</label>
                    <span>{productInfo.version}</span>
                </div>
                <div class="info-item">
                    <label>Group:</label>
                    <span>{productInfo.group || 'None'}</span>
                </div>
            </div>

            <div class="capabilities">
                <h4>Capabilities</h4>
                <div class="capability-list">
                    {#each productInfo.capabilities as capability}
                        <div class="capability-item">
                            <span class="capability-name">{capability}</span>
                            <span class="capability-description">{getCapabilityDescription(capability)}</span>
                        </div>
                    {/each}
                </div>
            </div>

            <div class="description">
                <h4>Description</h4>
                <p>{productInfo.description}</p>
            </div>
        </div>
    {/if}
</div>

<style>
    .app-registration {
        background: white;
        padding: 20px;
        border-radius: 8px;
        border: 1px solid #ddd;
        max-width: 800px;
    }

    .loading, .error {
        text-align: center;
        padding: 20px;
    }

    .error {
        color: #d32f2f;
    }

    .info-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 15px;
        margin-bottom: 20px;
    }

    .info-item {
        display: flex;
        flex-direction: column;
        gap: 5px;
    }

    .info-item label {
        font-weight: bold;
        color: #555;
    }

    .info-item span {
        font-family: monospace;
        background: #f5f5f5;
        padding: 4px 8px;
        border-radius: 4px;
    }

    .capabilities {
        margin-bottom: 20px;
    }

    .capability-list {
        display: flex;
        flex-direction: column;
        gap: 10px;
    }

    .capability-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 10px;
        background: #f9f9f9;
        border-radius: 4px;
    }

    .capability-name {
        font-weight: bold;
        color: #1976d2;
    }

    .capability-description {
        color: #666;
        font-size: 0.9em;
    }

    .description {
        background: #f5f5f5;
        padding: 15px;
        border-radius: 4px;

Express.js Integration

API Route

// routes/registration.js
const express = require('express');
const router = express.Router();

// Get product information
router.get('/registration', async (req, res) => {
  try {
    const sdk = req.sdk;
    if (!sdk) {
      return res.status(503).json({ error: 'SDK not available' });
    }

    // Get product information
    const information = sdk.information();
    const product = information.currentProduct();
    const rootDomain = information.rootDomain();

    res.json({
      product,
      rootDomain
    });
  } catch (error) {
    console.error('Registration GET error:', error);
    res.status(500).json({ error: 'Failed to get product info' });
  }
});

// Register application
router.post('/registration', async (req, res) => {
  try {
    const sdk = req.sdk;
    if (!sdk) {
      return res.status(503).json({ error: 'SDK not available' });
    }

    const { bundleId, name, title, description, capabilities, version, subdomain, icon, group } =
      req.body;

    // Validate required fields
    if (!bundleId || !name || !title || !description || !capabilities || !version || !subdomain) {
      return res.status(400).json({ error: 'Missing required fields' });
    }

    // Create registration data
    const registrationData = {
      bundleId,
      name,
      title,
      description,
      capabilities,
      version,
      subdomain,
      icon,
      group
    };

    // Register the application
    const registration = sdk.registration();
    await registration.register(registrationData);

    res.json({ success: true, message: 'Application registered successfully' });
  } catch (error) {
    console.error('Registration POST error:', error);
    res.status(500).json({ error: 'Failed to register application' });
  }
});

module.exports = router;

Middleware Setup

// app.js
const express = require('express');
const registrationRoutes = require('./routes/registration');

const app = express();

// Middleware to attach SDK
app.use((req, res, next) => {
  // Assuming SDK is available in some way
  req.sdk = getSdkInstance();
  next();
});

// Use registration routes
app.use('/api', registrationRoutes);

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Error Handling

Common Error Scenarios

// Error handling utility
export async function handleRegistrationErrors(operation: () => Promise<any>) {
  try {
    return await operation();
  } catch (error) {
    if (error instanceof Error) {
      // Handle specific error types
      if (error.message.includes('bundle ID already exists')) {
        throw new Error('An application with this bundle ID is already registered');
      }

      if (error.message.includes('invalid subdomain')) {
        throw new Error('The subdomain contains invalid characters or is reserved');
      }

      if (error.message.includes('capability not supported')) {
        throw new Error('One or more capabilities are not supported');
      }

      if (error.message.includes('insufficient permissions')) {
        throw new Error('You do not have permission to register applications');
      }
    }

    // Default error
    throw new Error('Registration failed. Please try again.');
  }
}

Validation Helpers

// Validation utilities
export function validateRegistrationData(data: ProductRegistrationData): string[] {
  const errors: string[] = [];

  // Bundle ID validation
  if (!data.bundleId || !/^[a-zA-Z0-9._-]+$/.test(data.bundleId)) {
    errors.push('Bundle ID must contain only letters, numbers, dots, hyphens, and underscores');
  }

  // Subdomain validation
  if (!data.subdomain || !/^[a-zA-Z0-9-]+$/.test(data.subdomain)) {
    errors.push('Subdomain must contain only letters, numbers, and hyphens');
  }

  // Capability validation
  const validCapabilities = ['API_SERVICE', 'FRONTEND_WEBSITE', 'DASHBOARD_DATA'];
  if (!data.capabilities || !Array.isArray(data.capabilities)) {
    errors.push('Capabilities must be an array');
  } else {
    const invalidCapabilities = data.capabilities.filter((cap) => !validCapabilities.includes(cap));
    if (invalidCapabilities.length > 0) {
      errors.push(`Invalid capabilities: ${invalidCapabilities.join(', ')}`);
    }
  }

  // Version validation
  if (!data.version || !/^\d+\.\d+\.\d+/.test(data.version)) {
    errors.push('Version must follow semantic versioning (e.g., 1.0.0)');
  }

  return errors;
}

Best Practices

1. Registration Flow

// Recommended registration flow
export async function registerApplication(sdk: BackendSDK, data: ProductRegistrationData) {
  // 1. Validate data
  const validationErrors = validateRegistrationData(data);
  if (validationErrors.length > 0) {
    throw new Error(`Validation failed: ${validationErrors.join(', ')}`);
  }

  // 2. Check if already registered
  const information = sdk.information();
  const currentProduct = information.currentProduct();

  if (currentProduct && currentProduct.bundleId === data.bundleId) {
    console.log('Application already registered with this bundle ID');
    return currentProduct;
  }

  // 3. Register
  const registration = sdk.registration();
  await registration.register(data);

  // 4. Verify registration
  const updatedProduct = information.currentProduct();
  if (!updatedProduct) {
    throw new Error('Registration completed but product information not available');
  }

  return updatedProduct;
}

2. Environment-Specific Configuration

// Environment-specific registration
export function getRegistrationConfig(
  environment: 'dev' | 'staging' | 'prod'
): Partial<ProductRegistrationData> {
  const baseConfig = {
    name: 'My App',
    title: 'My Application',
    description: 'A sample application',
    capabilities: ['API_SERVICE', 'FRONTEND_WEBSITE'] as ProductCapability[],
    version: '1.0.0'
  };

  switch (environment) {
    case 'dev':
      return {
        ...baseConfig,
        bundleId: 'com.example.myapp.dev',
        subdomain: 'myapp-dev'
      };
    case 'staging':
      return {
        ...baseConfig,
        bundleId: 'com.example.myapp.staging',
        subdomain: 'myapp-staging'
      };
    case 'prod':
      return {
        ...baseConfig,
        bundleId: 'com.example.myapp',
        subdomain: 'myapp'
      };
    default:
      throw new Error('Invalid environment');
  }
}

3. Registration Status Monitoring

// Monitor registration status
export class RegistrationMonitor {
  private sdk: BackendSDK;
  private checkInterval: NodeJS.Timeout | null = null;

  constructor(sdk: BackendSDK) {
    this.sdk = sdk;
  }

  startMonitoring(intervalMs: number = 30000) {
    this.checkInterval = setInterval(() => {
      this.checkRegistrationStatus();
    }, intervalMs);
  }

  stopMonitoring() {
    if (this.checkInterval) {
      clearInterval(this.checkInterval);
      this.checkInterval = null;
    }
  }

  private async checkRegistrationStatus() {
    try {
      const information = this.sdk.information();
      const product = information.currentProduct();

      if (!product) {
        console.warn('Application is not registered');
        return;
      }

      // Check if registration is still valid
      const rootDomain = information.rootDomain();
      console.log(`Application ${product.name} is registered on ${rootDomain}`);
    } catch (error) {
      console.error('Registration status check failed:', error);
    }
  }
}

Troubleshooting

Common Issues

  1. Registration Fails with "Bundle ID already exists"

    • Each application must have a unique bundle ID
    • Use environment-specific bundle IDs for different deployments
  2. Subdomain Validation Errors

    • Subdomains must be unique across the platform
    • Use only letters, numbers, and hyphens
    • Cannot start or end with hyphens
  3. Capability Validation Errors

    • Ensure all capabilities are from the valid set
    • Check that your application actually supports the claimed capabilities
  4. Permission Errors

    • Verify that the authenticated user has registration permissions
    • Check that the SDK is properly configured with valid credentials

Debug Information

// Get debug information
export async function getRegistrationDebugInfo(sdk: BackendSDK) {
  try {
    const information = sdk.information();
    const product = information.currentProduct();
    const rootDomain = information.rootDomain();

    return {
      product,
      rootDomain,
      timestamp: new Date().toISOString()
    };
  } catch (error) {
    return {
      error: error instanceof Error ? error.message : 'Unknown error',
      timestamp: new Date().toISOString()
    };
  }
}

Security Considerations

  • Always validate registration data before processing
  • Use environment-specific bundle IDs to prevent conflicts
  • Implement proper authentication and authorization
  • Store registration credentials securely
  • Monitor for unauthorized registration attempts
  • Use HTTPS for all registration API calls

Performance Optimization

  • Cache product information to avoid repeated SDK calls
  • Use batch operations when registering multiple applications
  • Implement retry logic for transient failures
  • Monitor registration success rates
  • Use appropriate timeouts for registration operations

Registration Health Checks

Application Health Check

// src/routes/api/health/+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(
        {
          status: 'unhealthy',
          error: 'SDK not available'
        },
        { status: 503 }
      );
    }

    const registration = sdk.registration();
    const appInfo = await registration.getAppInfo();

    const health = {
      status: 'healthy',
      timestamp: new Date().toISOString(),
      application: {
        name: appInfo.name,
        version: appInfo.version,
        bundleId: appInfo.bundleId
      },
      sdk: {
        booted: sdk.isBooted(),
        version: '3.4.2' // From package.json
      },
      uptime: process.uptime()
    };

    return json(health);
  } catch (error) {
    console.error('Health check error:', error);
    return json(
      {
        status: 'unhealthy',
        error: 'Health check failed',
        timestamp: new Date().toISOString()
      },
      { status: 500 }
    );
  }
};

Registration Status Monitoring

class RegistrationMonitor {
  private registration: RegistrationService;
  private checkInterval: NodeJS.Timeout | null = null;

  constructor(sdk: AsterismsBackendSDK) {
    this.registration = sdk.registration();
  }

  start(intervalMs: number = 60000) {
    this.checkInterval = setInterval(async () => {
      try {
        const appInfo = await this.registration.getAppInfo();
        console.log('Registration status:', {
          name: appInfo.name,
          status: 'active',
          lastCheck: new Date().toISOString()
        });
      } catch (error) {
        console.error('Registration check failed:', error);
      }
    }, intervalMs);
  }

  stop() {
    if (this.checkInterval) {
      clearInterval(this.checkInterval);
      this.checkInterval = null;
    }
  }
}

// Usage
const monitor = new RegistrationMonitor(sdk);
monitor.start(60000); // Check every minute

Advanced Error Handling

Registration Errors

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

try {
  await registration.updateCapabilities(newCapabilities);
} catch (error) {
  if (error instanceof AsterismsSDKError) {
    switch (error.code) {
      case 'REGISTRATION_NOT_FOUND':
        console.error('Application not registered');
        break;
      case 'INVALID_CAPABILITIES':
        console.error('Invalid capabilities provided');
        break;
      case 'PERMISSION_DENIED':
        console.error('Permission denied to update registration');
        break;
      default:
        console.error('Registration error:', error.message);
    }
  } else {
    console.error('Unknown registration error:', error);
  }
}

Retry Logic for Registration

async function updateCapabilitiesWithRetry(
  capabilities: string[],
  maxRetries: number = 3
): Promise<boolean> {
  const registration = sdk.registration();

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await registration.updateCapabilities(capabilities);
      return true;
    } catch (error) {
      console.error(`Registration attempt ${attempt} failed:`, error);

      if (attempt === maxRetries) {
        return false;
      }

      // Wait before retry
      await new Promise((resolve) => setTimeout(resolve, 2000 * attempt));
    }
  }

  return false;
}

Testing Registration

Unit Tests

import { describe, it, expect, beforeEach } from 'vitest';
import { getAsterismsBackendSDK } from '@asterisms/sdk-backend';

describe('Registration Service', () => {
  let sdk: AsterismsBackendSDK;
  let registration: RegistrationService;

  beforeEach(async () => {
    sdk = getAsterismsBackendSDK(testProps);
    await sdk.boot();
    registration = sdk.registration();
  });

  it('should get app info', async () => {
    const appInfo = await registration.getAppInfo();

    expect(appInfo).toBeDefined();
    expect(appInfo.bundleId).toBe('com.example.test');
    expect(appInfo.name).toBeDefined();
    expect(appInfo.capabilities).toBeInstanceOf(Array);
  });

  it('should update capabilities', async () => {
    const newCapabilities = ['FRONTEND_WEBSITE', 'BACKEND_SERVICE'];

    await expect(registration.updateCapabilities(newCapabilities)).resolves.not.toThrow();

    const appInfo = await registration.getAppInfo();
    expect(appInfo.capabilities).toEqual(newCapabilities);
  });
});

Integration Tests

import { test, expect } from '@playwright/test';

test('registration API works correctly', async ({ page }) => {
  // Test getting registration info
  const response = await page.request.get('/api/registration');
  expect(response.ok()).toBeTruthy();

  const data = await response.json();
  expect(data.appInfo).toBeDefined();
  expect(data.appInfo.bundleId).toBeDefined();

  // Test updating capabilities
  const updateResponse = await page.request.put('/api/registration', {
    data: {
      capabilities: ['FRONTEND_WEBSITE', 'BACKEND_SERVICE']
    }
  });

  expect(updateResponse.ok()).toBeTruthy();
});

Production Best Practices

Bundle ID Naming

// ✅ Good: Use reverse domain notation
const bundleId = 'com.company.product.service';

// ✅ Good: Be specific and descriptive
const bundleId = 'io.asterisms.workspace.frontend';

// ❌ Bad: Generic or unclear names
const bundleId = 'myapp';
const bundleId = 'service1';

Capability Best Practices

// ✅ Good: Use constants for capabilities
const CAPABILITIES = {
  FRONTEND: 'FRONTEND_WEBSITE',
  BACKEND: 'BACKEND_SERVICE',
  WEBHOOKS: 'WEBHOOKS'
};

// ✅ Good: Validate capabilities before updating
function validateCapabilities(capabilities: string[]): boolean {
  const validCapabilities = Object.values(CAPABILITIES);
  return capabilities.every((cap) => validCapabilities.includes(cap));
}

// ❌ Bad: Hardcoded strings
await registration.updateCapabilities(['FRONTEND_WEBSITE']);

Version Management

// ✅ Good: Use semantic versioning
const registrationData = {
  // ... other fields
  version: '1.2.3',
  metadata: {
    buildDate: new Date().toISOString(),
    commitHash: process.env.GIT_COMMIT,
    environment: process.env.NODE_ENV
  }
};

Production Considerations

Monitoring and Alerting

// Monitor registration health
async function checkRegistrationHealth(): Promise<boolean> {
  try {
    const registration = sdk.registration();
    const appInfo = await registration.getAppInfo();

    // Check if registration is valid
    if (!appInfo.bundleId || !appInfo.name) {
      console.error('Invalid registration data');
      return false;
    }

    return true;
  } catch (error) {
    console.error('Registration health check failed:', error);
    return false;
  }
}

// Set up periodic health checks
setInterval(async () => {
  const isHealthy = await checkRegistrationHealth();
  if (!isHealthy) {
    // Send alert to monitoring system
    console.error('Registration health check failed');
  }
}, 60000); // Check every minute

Graceful Degradation

// Handle registration failures gracefully
async function initializeApp() {
  try {
    const sdk = getAsterismsBackendSDK(props);
    await sdk.boot();

    // Verify registration
    const registration = sdk.registration();
    const appInfo = await registration.getAppInfo();

    console.log('App registered successfully:', appInfo.name);
  } catch (error) {
    console.error('Registration failed:', error);

    // Continue with limited functionality
    console.log('Starting in offline mode...');
  }
}

Next Steps