milton-fcm-client-sdk
v1.1.4
Published
Milton Health Coach FCM Client SDK for React Native - Async request processing with Firebase Cloud Messaging push notifications and intelligent polling coordination
Maintainers
Readme
Milton Health Coach FCM Client SDK
A React Native FCM Client SDK for the Milton Health Coach platform that provides asynchronous request processing with intelligent polling and mandatory push notification support for optimal background processing.
🚨 FCM Required
Firebase Cloud Messaging (FCM) is mandatory for this SDK. The SDK is specifically designed to handle Milton's async APIs efficiently using push notifications for background processing. Without FCM, the SDK will not function.
Features
- ✅ Async Request Processing: Submit requests and get immediate responses
- ✅ Intelligent Polling: Configurable exponential backoff polling (default: 5s, 10s, 20s, 40s, 80s, 120s)
- ✅ Push Notifications: Firebase Cloud Messaging integration for instant results (REQUIRED)
- ✅ Unified Coordination: Automatically stops polling when push notification received
- ✅ Background Handling: Continues processing when app is backgrounded
- ✅ Battery Optimized: Smart polling intervals and background management
- ✅ Offline Support: Request queuing and automatic retry when network restored
- ✅ Network Resilience: Handles network failures gracefully with persistent storage
- ✅ JavaScript: Pure JavaScript implementation for React Native projects
- ✅ Fully Configurable: Customize polling intervals, retry attempts, timeouts, and offline behavior
- ✅ Automatic Client ID: Generates unique client identifiers for request tracking
📋 Prerequisites
Before installing the SDK, you MUST have:
- ✅ Firebase project created
- ✅ Android/iOS apps added to Firebase
- ✅ Push notification certificates/keys configured
- ✅ React Native 0.60.0 or higher
Installation
Step 1: Install the SDK
npm install milton-fcm-client-sdkStep 2: Install Required Dependencies
npm install @react-native-firebase/app @react-native-firebase/messaging @react-native-async-storage/async-storage @react-native-community/netinfo react-native-device-infoStep 3: Verify Installation
npm run verifyThis will check your setup and provide guidance on any missing dependencies or configuration.
Step 3: Firebase Configuration (MANDATORY)
iOS Setup
- Add GoogleService-Info.plist to your iOS project
- Enable push notifications capability in Xcode
- Configure APNs certificates or keys in Firebase Console
- Follow our detailed Firebase Setup Guide
Android Setup
- Add google-services.json to
android/app/ - Update build.gradle files with Firebase plugin
- Configure FCM in Firebase Console
- Follow our detailed Firebase Setup Guide
Step 4: Verify Installation
import { MiltonAsyncClient } from 'milton-fcm-client-sdk';
// This will fail if FCM is not properly configured
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key'
// enablePushNotifications defaults to true and is required
});🔥 Firebase Setup Guide
FCM setup is mandatory. Choose your setup approach:
📋 Quick Setup Checklist
Use our FCM Setup Checklist for a step-by-step verification process.
📖 Detailed Setup Guide
See our comprehensive Firebase Setup Guide for detailed instructions including:
- Creating Firebase project
- Configuring Android and iOS apps
- Setting up push notification certificates
- Testing FCM integration
🚀 Complete API Examples
See All Milton APIs Example for a complete React Native component demonstrating all three async APIs:
- User Message Processing
- Survey Processing
- Fitness Calculations
Quick Start
⚠️ Ensure Firebase is configured before using the SDK - See Firebase Setup Guide
import { MiltonAsyncClient } from 'milton-fcm-client-sdk';
// Basic configuration (FCM enabled by default - REQUIRED)
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key'
// enablePushNotifications: true (default - MANDATORY)
});
// Full configuration with all Milton async APIs
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key',
enablePushNotifications: true, // MANDATORY - DO NOT SET TO FALSE
clientIdConfig: {
autoGenerate: true, // Auto-generate client ID
prefix: 'myapp', // Custom prefix
includeDeviceInfo: true, // Include device info
includePlatform: true, // Include platform (iOS/Android)
includeAppVersion: true // Include app version
},
pollingConfig: {
intervals: [5, 10, 20, 40, 80, 120], // Custom polling intervals
maxAttempts: 6, // Custom max attempts
batteryOptimized: true // Optimize for battery life
},
offlineConfig: {
maxQueueSize: 100, // Custom queue size
retryAttempts: 3 // Custom retry attempts
}
});
// Example 1: User Message Processing
const userResponse = await client.submitUserMessage({
orgId: 123,
userId: 456,
question: "Log my breakfast: scrambled eggs and toast",
image: imageUri, // optional
}, {
onProgress: (status) => {
console.log('Processing status:', status.status);
},
onComplete: (result) => {
console.log('Analysis complete:', result);
},
onError: (error) => {
console.error('Processing failed:', error);
}
});
// Example 2: Survey Processing
const surveyResponse = await client.submitSurvey({
phone_number: "+1234567890",
survey: "Q. What's your gender?\nA. Male\n\nQ. What's your current weight?\nA. 173 lbs\n\nQ. How tall are you?\nA. 5 ft 11 in\n\nQ. What's your primary health goal right now?\nA. Lose weight\n\nQ. When do you want to reach your goal?\nA. 12/29/2025\n\nQ. What five things have you eaten the most over the last two to four weeks?\nA. I've eaten Paneer curry and rice, Dal and rice, homemade pizza, potato curry\n\nQ. Any food allergies, intolerances or other reasons you avoid foods?\nA. \n\nQ. How many meals do you usually eat in a day?\nA. 3\n\nQ. How often do you cook at home vs. eat out?\nA. Mostly home\n\nQ. How many days per week are you currently active?\nA. 6\n\nQ. How long are your typical workouts?\nA. 45-60 minutes\n\nQ. What is the intensity?\nA. Low: Light activity, easy pace\n\nQ. Any current or past injuries we should know about?\nA. \n\nQ. Do you have any chronic conditions we should consider when creating your plan?\nA. None of the above\n\nQ. Have you ever been told by a doctor to avoid certain types of exercise?\nA. Yes: Heavy weightlifting and water sports",
birthday: "1990-01-01",
default_timezone: "UTC-6"
}, {
onComplete: (result) => {
console.log('Survey processed:', result);
}
});
// Example 3: Fitness Calculation
const fitnessResponse = await client.calculateFitness({
orgId: 123,
userId: 456,
fitnessData: {
steps: 8500,
heart_rate_avg: 72,
active_minutes: 45,
calories_burned: 320
}
}, {
onComplete: (result) => {
console.log('Fitness calculated:', result);
}
});
console.log('All requests submitted with push notification support');Configuration
The SDK is fully configurable with custom polling intervals, retry attempts, and offline settings. See the Configuration Guide for complete details on all available parameters.
Key Configurable Parameters
- baseUrl & apiKey: Required connection parameters
- clientIdConfig.autoGenerate: Auto-generate unique client IDs (default: true)
- clientIdConfig.prefix: Custom prefix for generated client IDs (default: 'milton')
- pollingConfig.intervals: Custom polling intervals (default: [5, 10, 20, 40, 80, 120])
- pollingConfig.maxAttempts: Maximum polling attempts (default: 6)
- offlineConfig.maxQueueSize: Offline queue size (default: 50)
- offlineConfig.retryAttempts: Retry attempts for failed requests (default: 3)
API Reference
MiltonAsyncClient
Constructor
new MiltonAsyncClient(config: MiltonSDKConfig)Config Options:
baseUrl(string): Milton API base URLapiKey(string): Your API keytimeout(number, optional): Request timeout in ms (default: 30000)enablePushNotifications(boolean, optional): Enable FCM push notifications (default: true)pollingConfig(PollingConfig, optional): Custom polling configurationofflineConfig(OfflineConfig, optional): Offline handling configuration
Methods
submitUserMessage(request, options?)
Submit a user message for async processing.
await client.submitUserMessage({
orgId: 123,
userId: 456,
question: "What should I eat for lunch?",
image: "data:image/jpeg;base64,..." // optional
}, {
onProgress: (status) => console.log(status),
onComplete: (result) => console.log(result),
onError: (error) => console.error(error)
});submitSurvey(request, options?)
Submit survey data for async processing.
await client.submitSurvey({
phone_number: "+1234567890",
survey: "Mood: good, Energy: 8/10, Sleep: 7 hours",
birthday: "1990-01-01",
default_timezone: "America/New_York"
}, {
onComplete: (result) => console.log('Survey processed:', result)
});calculateFitness(request, options?)
Submit fitness calculation request.
await client.calculateFitness({
orgId: 123,
userId: 456,
fitnessData: {
steps: 8500,
heart_rate: 72,
activity_minutes: 45
}
}, {
onComplete: (result) => console.log('Fitness calculated:', result)
});getRequestStatus(requestId)
Get current status of a request.
const status = await client.getRequestStatus('request-uuid');
console.log('Status:', status.status); // 'queued', 'processing', 'completed', 'failed'cancelRequest(requestId)
Cancel a pending or processing request.
await client.cancelRequest('request-uuid');getOfflineQueueStatus()
Get current offline queue and network status.
const status = client.getOfflineQueueStatus();
console.log('Queue length:', status.queueLength);
console.log('Is online:', status.isOnline);
console.log('Active polling:', status.activePollingRequests);clearOfflineQueue()
Clear all queued offline requests.
await client.clearOfflineQueue();dispose()
Clean up resources when done with the client.
client.dispose();Client ID Management
The SDK automatically generates and manages unique client identifiers to help track requests across different devices and app instances.
Automatic Client ID Generation
By default, the SDK generates a unique client ID that includes:
- Custom prefix (default: 'milton')
- Platform (iOS/Android)
- App version
- Device identifier
- Timestamp
Example generated ID: milton-ios-v1.2.3-abc12345-1k2j3h4g
Configuration Options
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key',
clientIdConfig: {
autoGenerate: true, // Enable auto-generation (default: true)
prefix: 'myapp', // Custom prefix (default: 'milton')
includeDeviceInfo: true, // Include device info (default: true)
includePlatform: true, // Include platform (default: true)
includeAppVersion: true, // Include app version (default: true)
customClientId: null, // Use custom ID instead of auto-generation
storageKey: 'my_client_id' // Custom storage key (default: 'milton_client_id')
}
});Manual Client ID Management
// Get current client ID
const clientId = client.getClientId();
console.log('Current client ID:', clientId);
// Set custom client ID
await client.setClientId('my-custom-client-id');
// Regenerate client ID
await client.regenerateClientId();
// Override per request
await client.submitUserMessage({
orgId: 123,
userId: 456,
question: "What should I eat?"
}, {
clientId: 'request-specific-id' // Override auto-generated ID
});Persistent Storage
Client IDs are automatically stored in AsyncStorage and persist across app restarts. The same client ID will be used until:
- The app is uninstalled
- You manually regenerate it
- You set a custom client ID
How It Works
Unified Polling + Push Strategy
The SDK uses a smart coordination strategy:
- Submit Request: Returns immediately with request ID
- Start Polling: Begins intelligent polling with exponential backoff
- Push Notification: Server sends push when processing completes
- Stop Polling: SDK automatically stops polling when push received
- Fallback: If push fails, polling continues until completion
Polling Intervals
Default exponential backoff: [1, 2, 4, 8, 15, 30] seconds
- Attempt 1: Poll after 1 second
- Attempt 2: Poll after 2 seconds
- Attempt 3: Poll after 4 seconds
- Attempt 4: Poll after 8 seconds
- Attempt 5: Poll after 15 seconds
- Attempt 6+: Poll every 30 seconds
Background Handling
- App Active: Normal polling intervals
- App Background: Polling paused, relies on push notifications
- App Resumed: Polling resumes for any active requests
Offline Handling
The SDK provides robust offline support with automatic request queuing and retry mechanisms.
How Offline Handling Works
- Network Detection: Automatically detects when device goes offline
- Request Queuing: Queues requests in persistent storage when offline
- Automatic Retry: Processes queued requests when network is restored
- Battery Optimization: Uses longer polling intervals in background mode
- Push Fallback: Switches to push notifications when polling times out
Offline Configuration
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key',
offlineConfig: {
enableOfflineQueue: true, // Enable offline request queuing
maxQueueSize: 50, // Maximum requests to queue
retryAttempts: 3, // Retry attempts for failed requests
retryDelay: 5000, // Delay between retries (ms)
storageKey: 'milton_queue' // AsyncStorage key for persistence
}
});Battery Optimization
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key',
pollingConfig: {
intervals: [1, 2, 4, 8, 15, 30], // Foreground intervals
backgroundIntervals: [30, 60, 120, 300], // Background intervals
maxAttempts: 6,
batteryOptimized: true // Enable battery optimization
}
});Offline Usage Example
// Submit request - works both online and offline
const response = await client.submitUserMessage({
orgId: 123,
userId: 456,
question: "Log my lunch"
}, {
onProgress: (status) => {
if (status.status === 'queued_offline') {
showMessage('Request queued - will process when online');
} else if (status.status === 'waiting_for_push') {
showMessage('Waiting for push notification...');
}
},
onComplete: (result) => {
showMessage('Request completed successfully');
},
onError: (error) => {
if (error.message.includes('offline')) {
showMessage('Request failed - check connection');
}
}
});
// Check offline queue status
const queueStatus = client.getOfflineQueueStatus();
console.log(`${queueStatus.queueLength} requests queued`);Network State Handling
The SDK automatically handles network state changes:
// Network goes offline
// → Current requests switch to offline mode
// → New requests are queued automatically
// Network restored
// → Queued requests are processed automatically
// → Polling resumes for active requests
// → User receives completion notificationsBattery Optimization Features
Foreground Mode:
- Normal polling intervals: 1s, 2s, 4s, 8s, 15s, 30s
- Full polling attempts (6 attempts)
- Immediate network retry on failure
Background Mode:
- Extended intervals: 30s, 60s, 120s, 300s
- Reduced polling attempts (4 attempts)
- Switches to push notification mode faster
- Pauses polling to save battery
Push Notification Fallback:
- Automatically switches to push mode after 2 minutes of polling
- Resumes polling when app becomes active
- Provides seamless user experience
Advanced Usage
Custom Polling Configuration
const client = new MiltonAsyncClient({
baseUrl: 'https://api.milton.com',
apiKey: 'your-api-key',
pollingConfig: {
intervals: [2, 5, 10, 20], // Custom intervals in seconds
maxAttempts: 4,
timeoutMs: 60000
}
});Webhook Integration (Web Clients)
For web applications that can receive webhooks:
await client.submitUserMessage({
orgId: 123,
userId: 456,
question: "Analyze my meal"
}, {
webhookUrl: 'https://your-app.com/webhook/milton',
clientId: 'web-client-123'
});Error Handling
try {
const response = await client.submitUserMessage(request, {
onError: (error) => {
if (error.message.includes('HTTP 503')) {
// Server overloaded, retry later
setTimeout(() => retryRequest(), 5000);
} else {
// Handle other errors
showErrorMessage(error.message);
}
}
});
} catch (error) {
// Handle submission errors
console.error('Failed to submit request:', error);
}Firebase Cloud Messaging Setup
1. Create Firebase Project
- Go to Firebase Console
- Create a new project or use existing
- Add your iOS and Android apps
2. Download Configuration Files
- iOS: Download
GoogleService-Info.plist - Android: Download
google-services.json
3. Configure React Native Firebase
Follow the official React Native Firebase setup guide.
4. Test Push Notifications
import messaging from '@react-native-firebase/messaging';
// Test FCM token generation
messaging().getToken().then(token => {
console.log('FCM Token:', token);
});
// Test notification reception
messaging().onMessage(async remoteMessage => {
console.log('FCM Message received:', remoteMessage);
});Troubleshooting
Common Issues
Push notifications not working:
- Verify Firebase configuration files are correctly added
- Check that FCM token is being generated
- Ensure push notification permissions are granted
- Test with Firebase Console test message
Polling not stopping:
- Check that push notification data includes
request_id - Verify notification type is
analysis_complete - Check console logs for push notification handling
Requests timing out:
- Increase
timeoutin SDK config - Check network connectivity
- Verify API endpoint URLs are correct
Debug Logging
Enable debug logging to troubleshoot issues:
// The SDK automatically logs to console
// Check React Native debugger or device logs for:
// - "Milton SDK: FCM Token obtained"
// - "Milton SDK: Received completion notification"
// - "Milton SDK: Polling error" or other error messagesMigration from Sync API
Before (Synchronous)
// Old synchronous approach
const response = await fetch('/user', {
method: 'POST',
body: JSON.stringify(request)
});
const result = await response.json(); // Waits 5-15 secondsAfter (Asynchronous)
// New asynchronous approach
const response = await client.submitUserMessage(request, {
onComplete: (result) => {
// Handle result when ready (via push notification or polling)
updateUI(result);
}
});
// Returns immediately with request IDLicense
MIT
Documentation
Complete Documentation Suite
- Installation Guide - Step-by-step setup instructions
- Firebase Setup Guide - Comprehensive Firebase configuration
- API Reference - Complete API documentation
- TypeScript Definitions - TypeScript support and examples
- Migration Guide - Migrate from sync to async API
- Troubleshooting Guide - Common issues and solutions
- Offline Handling Guide - Offline support documentation
Examples
- Basic Usage - Simple integration example
- Advanced Usage - Multiple endpoints and request management
- Complete Integration - Full-featured example app
- Unified Polling + Push - Polling and push coordination
- Offline Handling - Offline queue management
Support
For issues and questions:
- Email: Email: [email protected]
