This section provides comprehensive examples of using the Asterisms JS SDK in different scenarios and frameworks.
// Basic setup with minimal configuration
import { createAsterismsSDK } from '@asterisms/sdk';
import { SRP6AuthProvider } from '@asterisms/auth-provider-srp6';
const sdk = createAsterismsSDK({
bundleId: 'com.yourcompany.yourapp',
rootDomain: 'yourapp.com',
navigationAdapter: {
navigate: (url) => (window.location.href = url),
getCurrentPath: () => window.location.pathname
}
});
// Register authentication provider
sdk.auth.registerProvider(
'srp6',
new SRP6AuthProvider({
serviceUrl: 'https://auth.yourapp.com'
})
);
console.log('SDK initialized:', sdk.isReady());async function loginExample() {
try {
// Login user
const result = await sdk.auth.login({
provider: 'srp6',
credentials: {
username: 'user@example.com',
password: 'userPassword'
}
});
console.log('Login successful:', result.user);
// Get current user
const user = sdk.auth.getCurrentUser();
console.log('Current user:', user);
// Check authentication status
const isAuthenticated = sdk.auth.isAuthenticated();
console.log('Is authenticated:', isAuthenticated);
} catch (error) {
console.error('Login failed:', error.message);
}
}
async function logoutExample() {
try {
await sdk.auth.logout();
console.log('Logout successful');
} catch (error) {
console.error('Logout failed:', error.message);
}
}// components/AuthProvider.tsx
import React, { createContext, useContext, useEffect, useState } from 'react';
import { sdk } from '../lib/sdk';
interface AuthState {
isAuthenticated: boolean;
user: any | null;
loading: boolean;
}
const AuthContext = createContext<AuthState>({
isAuthenticated: false,
user: null,
loading: true
});
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [authState, setAuthState] = useState<AuthState>({
isAuthenticated: false,
user: null,
loading: true
});
useEffect(() => {
// Subscribe to authentication state changes
const unsubscribe = sdk.auth.onAuthStateChanged((state) => {
setAuthState({
isAuthenticated: state.isAuthenticated,
user: state.user,
loading: false
});
});
// Initial auth check
setAuthState({
isAuthenticated: sdk.auth.isAuthenticated(),
user: sdk.auth.getCurrentUser(),
loading: false
});
return unsubscribe;
}, []);
return (
<AuthContext.Provider value={authState}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);// components/LoginForm.tsx
import React, { useState } from 'react';
import { sdk } from '../lib/sdk';
import { useAuth } from './AuthProvider';
export function LoginForm() {
const [credentials, setCredentials] = useState({ username: '', password: '' });
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <div>Already logged in!</div>;
}
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
try {
await sdk.auth.login({
provider: 'srp6',
credentials
});
} catch (err: any) {
setError(err.message || 'Login failed');
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleLogin}>
<div>
<label htmlFor="username">Username:</label>
<input
id="username"
type="email"
value={credentials.username}
onChange={(e) => setCredentials({
...credentials,
username: e.target.value
})}
required
/>
</div>
<div>
<label htmlFor="password">Password:</label>
<input
id="password"
type="password"
value={credentials.password}
onChange={(e) => setCredentials({
...credentials,
password: e.target.value
})}
required
/>
</div>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={loading}>
{loading ? 'Logging in...' : 'Login'}
</button>
</form>
);
}// components/FileUpload.tsx
import React, { useState, useCallback } from 'react';
import { sdk } from '../lib/sdk';
interface UploadProgress {
[fileId: string]: {
percentage: number;
status: 'uploading' | 'completed' | 'error';
};
}
export function FileUpload() {
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
const [uploadProgress, setUploadProgress] = useState<UploadProgress>({});
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
setSelectedFiles(Array.from(e.target.files));
}
};
const uploadFile = useCallback(async (file: File) => {
try {
const upload = sdk.storage.uploadWithProgress(file, {
folder: '/uploads',
metadata: {
originalName: file.name,
uploadedAt: new Date().toISOString()
}
});
// Track progress
upload.onProgress((progress) => {
setUploadProgress(prev => ({
...prev,
[progress.fileId]: {
percentage: progress.percentage,
status: 'uploading'
}
}));
});
const result = await upload.promise;
setUploadProgress(prev => ({
...prev,
[result.fileId]: {
percentage: 100,
status: 'completed'
}
}));
console.log('Upload completed:', result);
} catch (error) {
console.error('Upload failed:', error);
setUploadProgress(prev => ({
...prev,
[file.name]: {
percentage: 0,
status: 'error'
}
}));
}
}, []);
const handleUpload = async () => {
for (const file of selectedFiles) {
await uploadFile(file);
}
};
return (
<div>
<input
type="file"
multiple
onChange={handleFileSelect}
/>
<button onClick={handleUpload} disabled={selectedFiles.length === 0}>
Upload Files
</button>
{selectedFiles.map((file, index) => {
const progress = uploadProgress[file.name];
return (
<div key={index} className="file-item">
<span>{file.name}</span>
{progress && (
<div className="progress">
<div
className="progress-bar"
style={{ width: `${progress.percentage}%` }}
/>
<span>{progress.status}: {progress.percentage}%</span>
</div>
)}
</div>
);
})}
</div>
);
}// src/lib/stores/auth.ts
import { writable } from 'svelte/store';
import { sdk } from '$lib/sdk';
interface AuthState {
isAuthenticated: boolean;
user: any | null;
loading: boolean;
}
function createAuthStore() {
const { subscribe, set, update } = writable<AuthState>({
isAuthenticated: false,
user: null,
loading: true
});
// Subscribe to SDK auth changes
sdk.auth.onAuthStateChanged((state) => {
set({
isAuthenticated: state.isAuthenticated,
user: state.user,
loading: false
});
});
return {
subscribe,
login: async (credentials: any) => {
try {
await sdk.auth.login({
provider: 'srp6',
credentials
});
} catch (error) {
console.error('Login failed:', error);
throw error;
}
},
logout: async () => {
try {
await sdk.auth.logout();
} catch (error) {
console.error('Logout failed:', error);
throw error;
}
}
};
}
export const auth = createAuthStore();<!-- src/routes/login/+page.svelte -->
<script lang="ts">
import { auth } from '$lib/stores/auth';
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
let username = '';
let password = '';
let loading = false;
let error = '';
$: if ($auth.isAuthenticated) {
goto('/dashboard');
}
async function handleLogin() {
loading = true;
error = '';
try {
await auth.login({ username, password });
} catch (err: any) {
error = err.message || 'Login failed';
} finally {
loading = false;
}
}
</script>
<div class="login-container">
<form on:submit|preventDefault={handleLogin}>
<h1>Login</h1>
<div class="field">
<label for="username">Username:</label>
<input
id="username"
type="email"
bind:value={username}
required
/>
</div>
<div class="field">
<label for="password">Password:</label>
<input
id="password"
type="password"
bind:value={password}
required
/>
</div>
{#if error}
<div class="error">{error}</div>
{/if}
<button type="submit" disabled={loading}>
{loading ? 'Logging in...' : 'Login'}
</button>
</form>
</div>
<style>
.login-container {
max-width: 400px;
margin: 2rem auto;
padding: 2rem;
border: 1px solid #ccc;
border-radius: 8px;
}
.field {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
}
input {
width: 100%;
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
}
.error {
color: red;
margin-bottom: 1rem;
}
button {
width: 100%;
padding: 0.75rem;
background: #007cba;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>// src/hooks.server.ts
import { sdk } from '$lib/sdk';
import { redirect } from '@sveltejs/kit';
export async function handle({ event, resolve }) {
// Get token from cookies or headers
const token = event.cookies.get('auth-token') || event.request.headers.get('authorization');
if (token) {
// Set token in SDK
sdk.auth.setToken(token);
}
// Check if route requires authentication
if (event.url.pathname.startsWith('/protected')) {
if (!sdk.auth.isAuthenticated()) {
throw redirect(302, '/login');
}
}
return resolve(event);
}// composables/useAuth.ts
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { sdk } from '../lib/sdk';
export function useAuth() {
const authState = ref({
isAuthenticated: false,
user: null,
loading: true
});
let unsubscribe: (() => void) | null = null;
onMounted(() => {
unsubscribe = sdk.auth.onAuthStateChanged((state) => {
authState.value = {
isAuthenticated: state.isAuthenticated,
user: state.user,
loading: false
};
});
// Initial state
authState.value = {
isAuthenticated: sdk.auth.isAuthenticated(),
user: sdk.auth.getCurrentUser(),
loading: false
};
});
onUnmounted(() => {
if (unsubscribe) {
unsubscribe();
}
});
const login = async (credentials: any) => {
try {
await sdk.auth.login({
provider: 'srp6',
credentials
});
} catch (error) {
console.error('Login failed:', error);
throw error;
}
};
const logout = async () => {
try {
await sdk.auth.logout();
} catch (error) {
console.error('Logout failed:', error);
throw error;
}
};
return {
authState: computed(() => authState.value),
isAuthenticated: computed(() => authState.value.isAuthenticated),
user: computed(() => authState.value.user),
loading: computed(() => authState.value.loading),
login,
logout
};
}<!doctype html>
<html>
<head>
<title>Asterisms JS SDK Example</title>
</head>
<body>
<div id="app">
<div id="login-form" style="display: none;">
<h2>Login</h2>
<form id="loginForm">
<input type="email" id="username" placeholder="Username" required />
<input type="password" id="password" placeholder="Password" required />
<button type="submit">Login</button>
</form>
<div id="error" style="color: red;"></div>
</div>
<div id="dashboard" style="display: none;">
<h2>Dashboard</h2>
<p>Welcome, <span id="userName"></span>!</p>
<button id="logoutBtn">Logout</button>
<div>
<h3>Upload File</h3>
<input type="file" id="fileInput" />
<button id="uploadBtn">Upload</button>
<div id="uploadProgress"></div>
</div>
</div>
</div>
<script type="module">
import { createAsterismsSDK } from 'https://unpkg.com/@asterisms/sdk';
import { SRP6AuthProvider } from 'https://unpkg.com/@asterisms/auth-provider-srp6';
// Initialize SDK
const sdk = createAsterismsSDK({
bundleId: 'com.example.app',
rootDomain: 'example.com',
navigationAdapter: {
navigate: (url) => (window.location.href = url),
getCurrentPath: () => window.location.pathname
}
});
// Register auth provider
sdk.auth.registerProvider(
'srp6',
new SRP6AuthProvider({
serviceUrl: 'https://auth.example.com'
})
);
// DOM elements
const loginForm = document.getElementById('login-form');
const dashboard = document.getElementById('dashboard');
const loginFormEl = document.getElementById('loginForm');
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');
const errorDiv = document.getElementById('error');
const userNameSpan = document.getElementById('userName');
const logoutBtn = document.getElementById('logoutBtn');
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadBtn');
const uploadProgress = document.getElementById('uploadProgress');
// Auth state handler
sdk.auth.onAuthStateChanged((state) => {
if (state.isAuthenticated) {
loginForm.style.display = 'none';
dashboard.style.display = 'block';
userNameSpan.textContent = state.user.displayName || state.user.email;
} else {
loginForm.style.display = 'block';
dashboard.style.display = 'none';
}
});
// Login form handler
loginFormEl.addEventListener('submit', async (e) => {
e.preventDefault();
errorDiv.textContent = '';
try {
await sdk.auth.login({
provider: 'srp6',
credentials: {
username: usernameInput.value,
password: passwordInput.value
}
});
} catch (error) {
errorDiv.textContent = error.message;
}
});
// Logout handler
logoutBtn.addEventListener('click', async () => {
try {
await sdk.auth.logout();
} catch (error) {
console.error('Logout failed:', error);
}
});
// Upload handler
uploadBtn.addEventListener('click', async () => {
const file = fileInput.files[0];
if (!file) return;
try {
const upload = sdk.storage.uploadWithProgress(file);
upload.onProgress((progress) => {
uploadProgress.innerHTML = `
<div>Uploading: ${progress.percentage}%</div>
<div style="width: 100%; background: #f0f0f0;">
<div style="width: ${progress.percentage}%; background: #007cba; height: 20px;"></div>
</div>
`;
});
const result = await upload.promise;
uploadProgress.innerHTML = `<div style="color: green;">Upload completed!</div>`;
console.log('Upload result:', result);
} catch (error) {
uploadProgress.innerHTML = `<div style="color: red;">Upload failed: ${error.message}</div>`;
}
});
// Initial auth check
if (sdk.auth.isAuthenticated()) {
const user = sdk.auth.getCurrentUser();
userNameSpan.textContent = user.displayName || user.email;
dashboard.style.display = 'block';
} else {
loginForm.style.display = 'block';
}
</script>
</body>
</html>async function fileManagementExample() {
// Create a folder
const folder = await sdk.drive.createFolder({
name: 'My Documents',
parent: 'root'
});
// Upload files to the folder
const files = document.getElementById('fileInput').files;
for (const file of files) {
const result = await sdk.storage.upload(file, {
folder: folder.id,
metadata: {
category: 'document',
tags: ['important']
}
});
console.log('File uploaded:', result);
}
// List folder contents
const contents = await sdk.drive.listFolder(folder.id);
console.log('Folder contents:', contents);
// Share the folder
await sdk.drive.share(folder.id, {
users: ['colleague@example.com'],
permission: 'write',
message: 'Shared documents folder'
});
}function notificationExample() {
// Subscribe to notifications
sdk.notification.onNotificationReceived((notification) => {
// Show notification in UI
showNotification(notification);
// Show browser notification if permission granted
if (Notification.permission === 'granted') {
new Notification(notification.title, {
body: notification.message,
icon: notification.icon
});
}
});
// Request permission for browser notifications
if (Notification.permission === 'default') {
Notification.requestPermission().then((permission) => {
if (permission === 'granted') {
console.log('Notification permission granted');
}
});
}
// Mark notifications as read
async function markAsRead(notificationIds) {
await sdk.notification.markAsRead(notificationIds);
}
}
function showNotification(notification) {
const notificationEl = document.createElement('div');
notificationEl.className = 'notification';
notificationEl.innerHTML = `
<h4>${notification.title}</h4>
<p>${notification.message}</p>
<button onclick="markAsRead(['${notification.id}'])">Mark as Read</button>
`;
document.getElementById('notifications').appendChild(notificationEl);
}async function profileManagementExample() {
// Get current profile
const profile = await sdk.profile.getProfile();
console.log('Current profile:', profile);
// Update profile
await sdk.profile.updateProfile({
displayName: 'John Doe',
bio: 'Software Developer',
website: 'https://johndoe.dev'
});
// Upload avatar
const avatarFile = document.getElementById('avatarInput').files[0];
if (avatarFile) {
await sdk.profile.uploadAvatar(avatarFile);
}
// Update preferences
await sdk.profile.updatePreferences({
theme: 'dark',
language: 'en',
notifications: {
email: true,
push: true,
inApp: true
}
});
}import {
AsterismsError,
AsterismsBackendError,
InvalidTokenError,
HttpFetchError
} from '@asterisms/sdk';
async function robustErrorHandling() {
try {
const result = await sdk.storage.upload(file);
return result;
} catch (error) {
if (error instanceof InvalidTokenError) {
// Handle authentication errors
console.log('Authentication required');
// Redirect to login
window.location.href = '/login';
} else if (error instanceof AsterismsBackendError) {
// Handle backend errors
switch (error.status) {
case 413:
showError('File too large');
break;
case 429:
showError('Too many requests, please try again later');
break;
case 503:
showError('Service temporarily unavailable');
break;
default:
showError(`Server error: ${error.message}`);
}
} else if (error instanceof HttpFetchError) {
// Handle network errors
if (error.isNetworkError) {
showError('Network connection error');
} else {
showError('Request failed');
}
} else if (error instanceof AsterismsError) {
// Handle other SDK errors
showError(`SDK Error: ${error.message}`);
} else {
// Handle unexpected errors
console.error('Unexpected error:', error);
showError('An unexpected error occurred');
}
}
}
function showError(message) {
// Show error in UI
const errorEl = document.createElement('div');
errorEl.className = 'error';
errorEl.textContent = message;
document.body.appendChild(errorEl);
// Auto-remove after 5 seconds
setTimeout(() => {
document.body.removeChild(errorEl);
}, 5000);
}See the Testing Guide for comprehensive testing examples.