The Asterisms JS SDK provides a comprehensive event system that enables real-time updates and reactive programming patterns. This guide covers how to work with events, observables, and real-time data flows.
The SDK uses an observer pattern with strongly-typed events for:
// Basic event subscription
const unsubscribe = sdk.auth.onAuthStateChanged((state) => {
console.log('Authentication changed:', state);
});
// Unsubscribe when done
unsubscribe();// Strongly-typed events
interface AuthStateEvent {
isAuthenticated: boolean;
user?: User;
timestamp: Date;
}
interface UploadProgressEvent {
fileId: string;
progress: {
percentage: number;
loaded: number;
total: number;
};
}Monitor authentication state and token lifecycle:
// Authentication state changes
sdk.auth.onAuthStateChanged((state) => {
if (state.isAuthenticated) {
console.log('User logged in:', state.user);
// Update UI, redirect to dashboard
} else {
console.log('User logged out');
// Clear user data, redirect to login
}
});
// Token refresh events
sdk.auth.onTokenRefresh((tokenInfo) => {
console.log('Token refreshed:', tokenInfo.expiresAt);
});
// Authentication errors
sdk.auth.onAuthError((error) => {
console.error('Auth error:', error);
if (error.code === 'TOKEN_EXPIRED') {
// Handle token expiration
}
});
// Login attempts
sdk.auth.onLoginAttempt((attempt) => {
console.log('Login attempt:', attempt.provider, attempt.status);
});import { useEffect, useState } from 'react';
import { sdk } from './sdk';
function useAuth() {
const [authState, setAuthState] = useState({
isAuthenticated: false,
user: null,
loading: true
});
useEffect(() => {
const unsubscribe = sdk.auth.onAuthStateChanged((state) => {
setAuthState({
isAuthenticated: state.isAuthenticated,
user: state.user,
loading: false
});
});
return unsubscribe;
}, []);
return authState;
}
// Usage in component
function App() {
const { isAuthenticated, user, loading } = useAuth();
if (loading) return <div>Loading...</div>;
return isAuthenticated ?
<Dashboard user={user} /> :
<LoginForm />;
}Track file uploads and storage operations:
// Upload progress for individual files
sdk.storage.onUploadProgress((progress) => {
console.log(`File ${progress.fileId}: ${progress.percentage}%`);
// Update progress bar
updateProgressBar(progress.fileId, progress.percentage);
});
// Upload completion
sdk.storage.onUploadComplete((result) => {
console.log('Upload completed:', result.fileId, result.url);
// Show success notification
showNotification('File uploaded successfully!');
});
// Upload errors
sdk.storage.onUploadError((error) => {
console.error('Upload failed:', error.fileId, error.error);
// Show error message
showError(`Failed to upload ${error.fileName}: ${error.error.message}`);
});
// Batch upload progress
sdk.storage.onBatchProgress((batch) => {
const progress = (batch.completedCount / batch.totalCount) * 100;
console.log(`Batch upload: ${progress}% (${batch.completedCount}/${batch.totalCount})`);
});import { useEffect, useState } from 'react';
function UploadProgress({ fileId }) {
const [progress, setProgress] = useState(0);
const [status, setStatus] = useState('uploading');
useEffect(() => {
const unsubscribeProgress = sdk.storage.onUploadProgress((progressEvent) => {
if (progressEvent.fileId === fileId) {
setProgress(progressEvent.percentage);
}
});
const unsubscribeComplete = sdk.storage.onUploadComplete((result) => {
if (result.fileId === fileId) {
setStatus('completed');
setProgress(100);
}
});
const unsubscribeError = sdk.storage.onUploadError((error) => {
if (error.fileId === fileId) {
setStatus('error');
}
});
return () => {
unsubscribeProgress();
unsubscribeComplete();
unsubscribeError();
};
}, [fileId]);
return (
<div className="upload-progress">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${progress}%` }}
/>
</div>
<div className="status">{status}: {progress}%</div>
</div>
);
}Monitor file system operations and sharing activities:
// File/folder operations
sdk.drive.onItemCreated((item) => {
console.log('New item created:', item.name, item.type);
// Refresh file list
});
sdk.drive.onItemUpdated((item) => {
console.log('Item updated:', item.id, item.name);
// Update item in UI
});
sdk.drive.onItemDeleted((itemId) => {
console.log('Item deleted:', itemId);
// Remove from UI
});
// Sharing events
sdk.drive.onItemShared((shareEvent) => {
console.log('Item shared:', shareEvent.itemId, 'with', shareEvent.sharedWith);
// Update sharing indicators
});
sdk.drive.onPermissionChanged((permissionEvent) => {
console.log('Permission changed:', permissionEvent.itemId, permissionEvent.newPermission);
// Update UI permissions
});
// Folder synchronization
sdk.drive.onFolderSynced((folder) => {
console.log('Folder synced:', folder.id, folder.syncStatus);
// Update sync indicators
});Handle real-time notifications and messages:
// New notifications
sdk.notification.onNotificationReceived((notification) => {
console.log('New notification:', notification);
// Show notification in UI
showNotification({
id: notification.id,
title: notification.title,
message: notification.message,
type: notification.type,
timestamp: notification.timestamp
});
// Play notification sound
if (notification.priority === 'high') {
playNotificationSound();
}
});
// Notification read status changes
sdk.notification.onNotificationRead((notificationId) => {
console.log('Notification marked as read:', notificationId);
// Update UI read status
});
// Bulk notification operations
sdk.notification.onBulkOperation((operation) => {
console.log('Bulk operation:', operation.type, operation.count);
// Update notification counters
});import { useEffect, useState } from 'react';
function NotificationCenter() {
const [notifications, setNotifications] = useState([]);
const [unreadCount, setUnreadCount] = useState(0);
useEffect(() => {
// Load initial notifications
sdk.notification.getNotifications().then(setNotifications);
// Subscribe to new notifications
const unsubscribe = sdk.notification.onNotificationReceived((notification) => {
setNotifications(prev => [notification, ...prev]);
setUnreadCount(prev => prev + 1);
// Show browser notification if permission granted
if (Notification.permission === 'granted') {
new Notification(notification.title, {
body: notification.message,
icon: '/notification-icon.png'
});
}
});
// Subscribe to read status changes
const unsubscribeRead = sdk.notification.onNotificationRead((notificationId) => {
setNotifications(prev =>
prev.map(n =>
n.id === notificationId ? { ...n, read: true } : n
)
);
setUnreadCount(prev => Math.max(0, prev - 1));
});
return () => {
unsubscribe();
unsubscribeRead();
};
}, []);
const markAsRead = (notificationId) => {
sdk.notification.markAsRead([notificationId]);
};
return (
<div className="notification-center">
<h3>Notifications ({unreadCount})</h3>
{notifications.map(notification => (
<div
key={notification.id}
className={`notification ${notification.read ? 'read' : 'unread'}`}
onClick={() => markAsRead(notification.id)}
>
<h4>{notification.title}</h4>
<p>{notification.message}</p>
<span className="timestamp">
{new Date(notification.timestamp).toLocaleString()}
</span>
</div>
))}
</div>
);
}Monitor platform-wide events and system status:
// Application events
sdk.platform.onApplicationLaunched((app) => {
console.log('Application launched:', app.id, app.name);
});
sdk.platform.onApplicationClosed((appId) => {
console.log('Application closed:', appId);
});
// System status changes
sdk.platform.onStatusChanged((status) => {
console.log('Platform status:', status);
if (status === 'maintenance') {
showMaintenanceNotice();
}
});
// Feature availability changes
sdk.platform.onFeatureChanged((feature) => {
console.log('Feature changed:', feature.name, feature.enabled);
// Update UI based on feature availability
});Create and handle custom events for your application:
// Define custom event types
interface CustomEvent {
type: string;
data: any;
timestamp: Date;
}
// Create custom event emitter
class CustomEventEmitter {
private listeners = new Map<string, Function[]>();
on(eventType: string, callback: Function) {
if (!this.listeners.has(eventType)) {
this.listeners.set(eventType, []);
}
this.listeners.get(eventType)!.push(callback);
// Return unsubscribe function
return () => {
const callbacks = this.listeners.get(eventType);
if (callbacks) {
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
};
}
emit(eventType: string, data: any) {
const callbacks = this.listeners.get(eventType);
if (callbacks) {
callbacks.forEach((callback) => callback(data));
}
}
}
// Usage
const eventEmitter = new CustomEventEmitter();
const unsubscribe = eventEmitter.on('data-updated', (data) => {
console.log('Data updated:', data);
});
eventEmitter.emit('data-updated', { id: 1, name: 'Updated Item' });Debug events and troubleshoot issues:
// Enable event debugging
sdk.enableEventDebugging(true);
// Log all events
sdk.onAnyEvent((event) => {
console.log('Event:', event.type, event.data, event.timestamp);
});
// Track event performance
sdk.onEventPerformance((metrics) => {
console.log('Event performance:', metrics);
if (metrics.duration > 1000) {
console.warn('Slow event handler:', metrics.eventType, metrics.duration);
}
});
// Error tracking
sdk.onEventError((error) => {
console.error('Event error:', error.eventType, error.error);
// Send to error tracking service
});// Always clean up event subscriptions
useEffect(() => {
const unsubscribe = sdk.auth.onAuthStateChanged(handleAuthChange);
return () => {
unsubscribe(); // Prevent memory leaks
};
}, []);// Wrap event handlers in try-catch
sdk.notification.onNotificationReceived((notification) => {
try {
handleNotification(notification);
} catch (error) {
console.error('Error handling notification:', error);
// Fallback behavior
}
});import { debounce } from 'lodash';
// Debounce frequent events
const debouncedHandler = debounce((progress) => {
updateProgressBar(progress);
}, 100);
sdk.storage.onUploadProgress(debouncedHandler);// Subscribe only when needed
useEffect(() => {
if (isUploading) {
const unsubscribe = sdk.storage.onUploadProgress(handleProgress);
return unsubscribe;
}
}, [isUploading]);// src/lib/stores/auth.ts
import { writable } from 'svelte/store';
import { sdk } from './sdk';
function createAuthStore() {
const { subscribe, set } = writable({
isAuthenticated: false,
user: null
});
// Subscribe to auth changes
sdk.auth.onAuthStateChanged((state) => {
set({
isAuthenticated: state.isAuthenticated,
user: state.user
});
});
return { subscribe };
}
export const auth = createAuthStore();// composables/useEvents.js
import { ref, onMounted, onUnmounted } from 'vue';
import { sdk } from './sdk';
export function useAuthState() {
const authState = ref({
isAuthenticated: false,
user: null
});
let unsubscribe;
onMounted(() => {
unsubscribe = sdk.auth.onAuthStateChanged((state) => {
authState.value = state;
});
});
onUnmounted(() => {
if (unsubscribe) {
unsubscribe();
}
});
return { authState };
}