@dispatch9/client-sdk
Version:
Official Node.js SDK for Dispatch9 API - Complete solution with email/phone client creation, order management, client management, and dual-method authentication
532 lines (454 loc) โข 20.5 kB
JavaScript
require('dotenv').config();
const Dispatch9Client = require('../src/client');
/**
* Client Authentication Example
* Demonstrates the new client authentication features:
* - Login with email address or phone number
* - Multi-provider client handling
* - First-time login OTP verification
* - Profile management and session handling
* - Comprehensive error handling and validation
*/
async function clientAuthenticationExample() {
console.log('๐ Dispatch9 SDK - Client Authentication Example\n');
console.log('๐ Demonstrating email and phone number login capabilities\n');
try {
// Initialize the SDK (no API key needed for client auth)
const dispatch9 = new Dispatch9Client({
baseURL: process.env.DISPATCH9_BASE_URL || 'https://api.dispatch9.com',
debug: false
});
console.log('โ
SDK initialized successfully\n');
// ==========================================
// PART 1: EMAIL AND PHONE LOGIN EXAMPLES
// ==========================================
console.log('๐ง PART 1: Email and Phone Number Authentication');
console.log('โ'.repeat(60));
// Example credentials (replace with real test credentials)
const testCredentials = {
email: 'testclient@example.com',
phone: '+1234567890',
formattedPhone: '+1 (234) 567-8900',
password: 'testPassword123'
};
console.log('โ ๏ธ Note: Using example credentials. Replace with real test credentials for actual testing.\n');
// Example 1: Email Login
console.log('๐ง Example 1: Email Address Login');
console.log('-'.repeat(40));
try {
const emailLogin = await dispatch9.loginClient({
identifier: testCredentials.email,
password: testCredentials.password
});
if (emailLogin.success) {
console.log('โ
Email login successful!');
console.log(` Client ID: ${emailLogin.client.id}`);
console.log(` Name: ${emailLogin.client.name}`);
console.log(` Email: ${emailLogin.client.email}`);
console.log(` First Login: ${emailLogin.client.isFirstLogin ? 'Yes' : 'No'}`);
console.log(` Registration Status: ${emailLogin.client.registrationStatus}`);
if (emailLogin.tokens) {
console.log(' ๐ Authentication tokens received');
console.log(` Access Token Expires: ${emailLogin.tokens.access.expires}`);
}
} else if (emailLogin.requiresProviderSelection) {
console.log('๐ Multiple providers detected - see provider selection example below');
} else if (emailLogin.requiresOTP) {
console.log('๐ฒ OTP verification required - see OTP example below');
} else {
console.log('โ Email login failed:', emailLogin.message);
}
} catch (error) {
console.log('โ Email login error:', error.message);
}
console.log('');
// Example 2: Phone Number Login
console.log('๐ฑ Example 2: Phone Number Login');
console.log('-'.repeat(40));
try {
const phoneLogin = await dispatch9.loginClient({
identifier: testCredentials.phone,
password: testCredentials.password
});
if (phoneLogin.success) {
console.log('โ
Phone login successful!');
console.log(` Client ID: ${phoneLogin.client.id}`);
console.log(` Name: ${phoneLogin.client.name}`);
console.log(` Phone: ${phoneLogin.client.phone}`);
console.log(` Email: ${phoneLogin.client.email || 'Not provided'}`);
} else {
console.log('โ Phone login failed:', phoneLogin.message);
}
} catch (error) {
console.log('โ Phone login error:', error.message);
}
console.log('');
// Example 3: Formatted Phone Number Login
console.log('๐ Example 3: Formatted Phone Number Login');
console.log('-'.repeat(40));
try {
const formattedPhoneLogin = await dispatch9.loginClient({
identifier: testCredentials.formattedPhone,
password: testCredentials.password
});
if (formattedPhoneLogin.success) {
console.log('โ
Formatted phone login successful!');
console.log(` Identifier used: ${testCredentials.formattedPhone}`);
console.log(` Client Name: ${formattedPhoneLogin.client.name}`);
} else {
console.log('โ Formatted phone login failed:', formattedPhoneLogin.message);
}
} catch (error) {
console.log('โ Formatted phone login error:', error.message);
}
console.log('');
// ==========================================
// PART 2: MULTI-PROVIDER CLIENT HANDLING
// ==========================================
console.log('๐ข PART 2: Multi-Provider Client Authentication');
console.log('โ'.repeat(60));
// Simulate multi-provider login response
console.log('๐ Example: Handling Multi-Provider Clients');
console.log('-'.repeat(40));
const handleMultiProviderAuth = async (identifier, password) => {
try {
// Step 1: Initial login attempt
const loginResult = await dispatch9.loginClient({
identifier,
password
});
if (loginResult.success && loginResult.tokens) {
// Direct login success (single provider)
console.log('โ
Single provider login successful');
return { success: true, client: loginResult.client };
} else if (loginResult.requiresProviderSelection) {
// Multiple providers available
console.log('๐ Multiple providers detected:');
loginResult.providers.forEach((provider, index) => {
console.log(` ${index + 1}. Database: ${provider.database}`);
console.log(` Provider ID: ${provider.providerId}`);
console.log(` Registered: ${new Date(provider.registeredAt).toLocaleDateString()}`);
console.log(` Permissions: ${Object.keys(provider.permissions).length} granted`);
});
// Step 2: Select first provider (in real app, user would choose)
console.log('\n๐ Selecting first provider...');
const selectedProvider = loginResult.providers[0];
const providerResult = await dispatch9.selectClientProvider({
clientId: loginResult.clientId,
providerId: selectedProvider.providerId
});
if (providerResult.success) {
console.log('โ
Provider selection successful!');
console.log(` Connected to: ${providerResult.client.selectedProvider.database}`);
console.log(` Provider ID: ${providerResult.client.selectedProvider.providerId}`);
return { success: true, client: providerResult.client };
} else {
console.log('โ Provider selection failed:', providerResult.message);
return { success: false, message: providerResult.message };
}
} else {
console.log('โ Login failed:', loginResult.message);
return { success: false, message: loginResult.message };
}
} catch (error) {
console.log('โ Multi-provider auth error:', error.message);
return { success: false, message: error.message };
}
};
// Test multi-provider authentication
const multiProviderResult = await handleMultiProviderAuth(
testCredentials.email,
testCredentials.password
);
if (multiProviderResult.success) {
console.log('๐ Multi-provider authentication completed successfully!\n');
} else {
console.log('โน๏ธ Multi-provider test completed (may not have multiple providers)\n');
}
// ==========================================
// PART 3: FIRST-TIME LOGIN OTP VERIFICATION
// ==========================================
console.log('๐ฒ PART 3: First-Time Login OTP Verification');
console.log('โ'.repeat(60));
const handleFirstTimeLogin = async (identifier, password, otpCode) => {
try {
// Step 1: Initial login attempt
console.log('๐ Attempting first-time login...');
const loginResult = await dispatch9.loginClient({
identifier,
password
});
if (loginResult.success && loginResult.tokens) {
// Login successful without OTP
console.log('โ
Login successful (no OTP required)');
return { success: true, client: loginResult.client };
} else if (loginResult.requiresOTP) {
// OTP verification required
console.log('๐ง First-time login detected!');
console.log(` Client ID: ${loginResult.clientId}`);
console.log(` OTP sent to email: ${loginResult.message}`);
if (otpCode) {
// Step 2: Verify OTP
console.log('๐ข Verifying OTP code...');
const otpResult = await dispatch9.verifyClientLoginOTP({
clientId: loginResult.clientId,
otp: otpCode
});
if (otpResult.success) {
console.log('โ
OTP verification successful!');
console.log(` Welcome ${otpResult.client.name}`);
console.log(' ๐ Authentication tokens received');
return { success: true, client: otpResult.client };
} else {
console.log('โ OTP verification failed:', otpResult.message);
return { success: false, message: otpResult.message };
}
} else {
console.log('โน๏ธ OTP code needed for verification');
return { success: false, requiresOTP: true, clientId: loginResult.clientId };
}
} else {
console.log('โ Login failed:', loginResult.message);
return { success: false, message: loginResult.message };
}
} catch (error) {
console.log('โ First-time login error:', error.message);
return { success: false, message: error.message };
}
};
// Test first-time login (without actual OTP)
console.log('๐งช Example: First-Time Login Flow');
console.log('-'.repeat(40));
const firstTimeResult = await handleFirstTimeLogin(
testCredentials.email,
testCredentials.password,
null // No OTP provided in example
);
if (firstTimeResult.requiresOTP) {
console.log('โน๏ธ First-time login would require OTP verification');
console.log(' In a real application:');
console.log(' 1. User receives OTP via email');
console.log(' 2. User enters OTP in your app');
console.log(' 3. Call verifyClientLoginOTP with the code');
// Example of OTP verification (with example code)
console.log('\n๐ข Example OTP verification:');
try {
await dispatch9.verifyClientLoginOTP({
clientId: firstTimeResult.clientId,
otp: '123456' // Example OTP
});
} catch (error) {
console.log(' Expected error (invalid OTP):', error.message);
}
}
console.log('');
// ==========================================
// PART 4: CLIENT PROFILE MANAGEMENT
// ==========================================
console.log('๐ค PART 4: Client Profile Management');
console.log('โ'.repeat(60));
console.log('๐ Example: Getting Client Profile');
console.log('-'.repeat(40));
try {
// Note: This requires authentication tokens
const profile = await dispatch9.getClientProfile();
console.log('โ
Profile retrieved successfully:');
console.log(` ID: ${profile.id}`);
console.log(` Name: ${profile.name}`);
console.log(` Email: ${profile.email}`);
console.log(` Phone: ${profile.phone || 'Not provided'}`);
console.log(` Business: ${profile.businessName || 'Not specified'}`);
console.log(` Status: ${profile.status}`);
console.log(` Registration: ${profile.registrationStatus}`);
console.log(` First Login: ${profile.isFirstLogin ? 'Yes' : 'No'}`);
console.log(` Last Login: ${profile.lastLogin || 'Never'}`);
if (profile.providers && profile.providers.length > 0) {
console.log('\n๐ข Available Providers:');
profile.providers.forEach((provider, index) => {
console.log(` ${index + 1}. Database: ${provider.database}`);
console.log(` Status: ${provider.status}`);
});
}
} catch (error) {
console.log('โน๏ธ Profile access requires authentication:', error.message);
console.log(' In a real application, ensure client is logged in first');
}
console.log('');
// ==========================================
// PART 5: VALIDATION AND ERROR HANDLING
// ==========================================
console.log('๐ก๏ธ PART 5: Validation and Error Handling');
console.log('โ'.repeat(60));
console.log('โ Testing Input Validation:');
console.log('-'.repeat(40));
// Test various validation scenarios
const validationTests = [
{
name: 'Empty credentials',
test: () => dispatch9.loginClient(),
expectedError: 'credentials object is required'
},
{
name: 'Missing identifier',
test: () => dispatch9.loginClient({ password: 'test' }),
expectedError: 'identifier is required'
},
{
name: 'Invalid email format',
test: () => dispatch9.loginClient({ identifier: 'invalid-email', password: 'test' }),
expectedError: 'identifier must be a valid email address or phone number'
},
{
name: 'Invalid phone format',
test: () => dispatch9.loginClient({ identifier: '123', password: 'test' }),
expectedError: 'identifier must be a valid email address or phone number'
},
{
name: 'Missing password',
test: () => dispatch9.loginClient({ identifier: 'test@example.com' }),
expectedError: 'password is required'
},
{
name: 'Invalid OTP format',
test: () => dispatch9.verifyClientLoginOTP({
clientId: '507f1f77bcf86cd799439011',
otp: '12345'
}),
expectedError: 'otp must be a 6-digit number'
}
];
for (const validation of validationTests) {
try {
await validation.test();
console.log(` โ ${validation.name}: Validation failed to catch error`);
} catch (error) {
if (error.message.includes(validation.expectedError)) {
console.log(` โ
${validation.name}: Correctly validated`);
} else {
console.log(` โ ๏ธ ${validation.name}: Unexpected error - ${error.message}`);
}
}
}
console.log('');
// ==========================================
// PART 6: AUTHENTICATION UTILITIES
// ==========================================
console.log('๐ง PART 6: Authentication Utility Functions');
console.log('โ'.repeat(60));
// Utility function to detect identifier type
const detectIdentifierType = (identifier) => {
if (!identifier) return 'invalid';
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
const cleanPhone = identifier.replace(/[\s\-\(\)]/g, '');
if (emailRegex.test(identifier)) return 'email';
if (phoneRegex.test(cleanPhone)) return 'phone';
return 'invalid';
};
// Test identifier detection
const testIdentifiers = [
'user@example.com',
'+1234567890',
'+1 (234) 567-8900',
'1234567890',
'invalid-identifier',
''
];
console.log('๐ Identifier Type Detection:');
console.log('-'.repeat(40));
testIdentifiers.forEach(identifier => {
const type = detectIdentifierType(identifier);
console.log(` "${identifier}" โ ${type}`);
});
console.log('');
// Authentication state helper
const createAuthHelper = () => {
let currentClient = null;
let authTokens = null;
return {
login: async (identifier, password) => {
try {
const result = await dispatch9.loginClient({ identifier, password });
if (result.success && result.tokens) {
currentClient = result.client;
authTokens = result.tokens;
return { success: true, client: result.client };
}
return { success: false, message: result.message };
} catch (error) {
return { success: false, message: error.message };
}
},
logout: () => {
currentClient = null;
authTokens = null;
console.log('๐ช Client logged out');
},
isAuthenticated: () => {
return !!(currentClient && authTokens);
},
getCurrentClient: () => currentClient,
getTokens: () => authTokens
};
};
console.log('๐ Authentication Helper Example:');
console.log('-'.repeat(40));
const authHelper = createAuthHelper();
console.log(` Is Authenticated: ${authHelper.isAuthenticated()}`);
console.log(` Current Client: ${authHelper.getCurrentClient() || 'None'}`);
console.log(` Tokens: ${authHelper.getTokens() || 'None'}`);
// Simulate login
console.log(' Simulating login...');
const authResult = await authHelper.login(testCredentials.email, testCredentials.password);
console.log(` Login Result: ${authResult.success ? 'Success' : authResult.message}`);
authHelper.logout();
console.log('');
// ==========================================
// SUMMARY AND BEST PRACTICES
// ==========================================
console.log('๐ SUMMARY AND BEST PRACTICES');
console.log('โ'.repeat(60));
console.log('๐ฏ Key Features Demonstrated:');
console.log(' โ Email address login');
console.log(' โ Phone number login (various formats)');
console.log(' โ Multi-provider client handling');
console.log(' โ First-time login OTP verification');
console.log(' โ Client profile management');
console.log(' โ Comprehensive input validation');
console.log(' โ Error handling and edge cases');
console.log('\n๐ก Best Practices:');
console.log(' โข Always validate user input before API calls');
console.log(' โข Handle all authentication scenarios (OTP, multi-provider)');
console.log(' โข Implement secure token storage in production');
console.log(' โข Provide clear feedback for authentication states');
console.log(' โข Support both email and phone login for flexibility');
console.log(' โข Implement proper error handling and user messaging');
console.log('\n๐ Security Considerations:');
console.log(' โข Store tokens securely (encrypted storage)');
console.log(' โข Implement token refresh mechanisms');
console.log(' โข Use HTTPS in production environments');
console.log(' โข Validate OTP codes server-side');
console.log(' โข Implement rate limiting for login attempts');
console.log(' โข Log authentication events for security monitoring');
console.log('\n๐ Client Authentication Example Completed Successfully!');
} catch (error) {
console.error('โ Error in client authentication example:', error.message);
if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch')) {
console.error('\n๐ง Connection Issue:');
console.error(' โข Check that the backend server is running');
console.error(' โข Verify the DISPATCH9_BASE_URL environment variable');
console.error(' โข Ensure the client-auth endpoints are available');
} else if (error.message.includes('credentials')) {
console.error('\n๐ง Credentials Issue:');
console.error(' โข Replace example credentials with real test accounts');
console.error(' โข Ensure test clients exist in the system');
console.error(' โข Verify client registration is complete');
}
process.exit(1);
}
}
// Run the example
if (require.main === module) {
clientAuthenticationExample();
}
module.exports = clientAuthenticationExample;