Core Concepts

Understanding the core concepts of the Asterisms JS SDK Backend will help you build robust and scalable applications.

SDK Architecture

The Asterisms JS SDK Backend follows a service-oriented architecture where each service provides specific functionality:

interface AsterismsBackendSDK {
  authorization(): AuthorizationService;
  storage(): StorageService;
  notifications(): NotificationSendingService;
  registration(): RegistrationService;
  discovery(): DiscoveryService;
  information(): InformationService;
  logging(): AsterismsLogger;
  boot(): Promise<void>;
  isBooted(): boolean;
}

Service Lifecycle

1. Initialization

The SDK is initialized with configuration properties:

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

const sdk = getAsterismsBackendSDK({
  bundleId: 'com.example.app',
  domain: 'asterisms.example.com',
  subdomain: 'app',
  httpServiceAdapterFactory: createFetchAdapter(fetch),
  registrationData: {
    bundleId: 'com.example.app',
    capabilities: ['FRONTEND_WEBSITE'],
    description: 'My Application',
    name: 'My App',
    subdomain: 'app',
    title: 'My App'
  }
});

2. Booting

The SDK must be booted before use:

await sdk.boot();

During boot, the SDK:

  • Establishes connections to core services
  • Validates configuration
  • Registers the application with the ecosystem
  • Initializes internal services

3. Service Access

Once booted, services are available through the SDK:

const auth = sdk.authorization();
const storage = sdk.storage();
const notifications = sdk.notifications();

Key Concepts

Bundle ID

A Bundle ID is a unique identifier for your application within the Asterisms ecosystem:

// Good: Reverse domain notation
bundleId: 'com.company.product.service';

// Good: Organization-based
bundleId: 'io.asterisms.workspace';

// Avoid: Generic names
bundleId: 'myapp';

Registration Data

Registration data describes your application to the ecosystem:

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

Key fields:

  • bundleId: Unique application identifier
  • capabilities: What your app can do (e.g., 'FRONTEND_WEBSITE', 'BACKEND_SERVICE')
  • subdomain: URL subdomain for your service
  • name: Internal name for your service
  • title: Display name for users

Capabilities

Capabilities define what your application can do:

const capabilities = [
  'FRONTEND_WEBSITE', // Web frontend
  'BACKEND_SERVICE', // Backend API service
  'WEBHOOKS', // Webhook handling
  'SCHEDULED_TASKS', // Background tasks
  'DATA_PROCESSING' // Data processing
];

HTTP Service Adapter

The SDK uses adapters to handle HTTP requests:

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

const httpFactory = createFetchAdapter(fetch);

This abstraction allows the SDK to work in different environments (Node.js, browsers, edge functions).

Service Overview

Authorization Service

Handles user authentication and authorization:

const auth = sdk.authorization();

// Resolve authenticated actor from token
const actor = await auth.resolveAuthenticatedActor('Bearer token');

// Verify token
const verification = await auth.verifyToken('Bearer token');
if (verification.valid) {
  console.log('User claims:', verification.claims);
}

// Generate IPC token for service-to-service communication
const ipcToken = await auth.generateIpcToken('https://platform.example.com');

Storage Service

Provides secure data storage:

const storage = sdk.storage();

// Upload a file
const file = new File(['Hello World'], 'hello.txt', { type: 'text/plain' });
const uploadResult = await storage.upload(file, {
  prefix: 'documents',
  bucketId: 'user-data'
});

// List files
const files = await storage.list({ bucketId: 'user-data' });

// Get file data
const fileData = await storage.getData(uploadResult.externalId);

// Download file
const fileResponse = await storage.download(uploadResult.externalId);

// Delete file
await storage.delete(uploadResult.externalId);

Notification Service

Sends notifications to users and workspaces:

const notifications = sdk.notifications();

// Send notification to a specific account
await notifications.sendToAccount('user-account-id', {
  sender: 'MyApp',
  message: {
    subject: 'New Message',
    text: 'You have a new message',
    html: '<p>You have a new message</p>',
    urgency: 'NONE'
  },
  account: null,
  directive: 'PREFERRED',
  delivery: { schedule: 'IMMEDIATE', delay: '0' },
  subscriptionKey: null
});

// Send notification to a workspace
await notifications.sendToWorkspace('workspace-id', {
  sender: 'MyApp',
  message: {
    subject: 'Workspace Update',
    text: 'Your workspace has been updated',
    urgency: 'NONE'
  },
  account: null,
  directive: 'PREFERRED',
  delivery: { schedule: 'IMMEDIATE', delay: '0' },
  subscriptionKey: null
});

Registration Service

Manages app registration and metadata:

const registration = sdk.registration();

// Register application (usually done during boot)
const registrationData = {
  product: {
    bundleId: 'com.example.app',
    capabilities: ['BACKEND_SERVICE'],
    description: 'My Application',
    name: 'My App',
    subdomain: 'app',
    title: 'My App'
  }
};

const response = await registration.register(registrationData);
console.log('Registration response:', response);

Discovery Service

Discovers other services in the ecosystem:

const discovery = sdk.discovery();

// Load all services
const services = await discovery.load();
console.log('Available services:', services);

// Get specific service
const platformService = await discovery.getService('io.asterisms.platform');
console.log('Platform service URL:', platformService.url);

// Reload services (clears cache)
const refreshedServices = await discovery.reload();

Information Service

Provides system and app information:

const info = sdk.information();

// Get current product info
const product = info.currentProduct();
console.log('Product:', product.name, product.version);

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

SvelteKit Integration

The SDK provides special SvelteKit integration:

import { createSvelteKitBackendSDK } from '@asterisms/sdk-backend';
import { createFetchAdapter } from '@asterisms/common-core';

const provider = createSvelteKitBackendSDK({
  env: process.env,
  building,
  httpFactory: createFetchAdapter(fetch),
  registrationData: {
    // registration data
  }
});

This returns an AsterismsSDKProvider with:

  • sdk: The SDK instance
  • bootSDK(): Boots the SDK if not building
  • apiRouter: Express-compatible router for API endpoints

Error Handling

The SDK uses structured error handling:

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

try {
  await sdk.boot();
} catch (error) {
  if (error instanceof AsterismsSDKError) {
    console.error('SDK Error:', error.message);
    console.error('Error Code:', error.code);
  } else {
    console.error('Unknown error:', error);
  }
}

Configuration Best Practices

Environment Variables

Use environment variables for configuration:

ASTERISMS_DOMAIN=asterisms.example.com
ASTERISMS_BUNDLE_ID=com.example.app
ASTERISMS_SUBDOMAIN=app
ASTERISMS_NAME=My App
ASTERISMS_TITLE=My App
ASTERISMS_DESCRIPTION=My Asterisms Application

Security

Always use HTTPS in production:

const sdk = getAsterismsBackendSDK({
  // ... other config
  secure: true,
  proxyTerminatedSSL: true // If behind a proxy
});

Logging

Configure logging for debugging:

const logger = sdk.logging();
logger.setLevel('debug');

Performance Considerations

Singleton Pattern

The SDK uses a singleton pattern - only one instance per application:

// This returns the same instance
const sdk1 = getAsterismsBackendSDK(props);
const sdk2 = getAsterismsBackendSDK(props);
console.log(sdk1 === sdk2); // true

Service Caching

Services are cached after first access:

// First call creates the service
const auth1 = sdk.authorization();

// Second call returns cached service
const auth2 = sdk.authorization();
console.log(auth1 === auth2); // true

Boot Once

Only boot the SDK once per application lifecycle:

let booted = false;

async function ensureBooted() {
  if (!booted && !sdk.isBooted()) {
    await sdk.boot();
    booted = true;
  }
}

Next Steps