These best practices will help you build robust, secure, and efficient applications with the MindPeeker platform. Following these guidelines will ensure optimal performance, security, and user experience.
Never expose API keys in client-side code
// ❌ BAD - Exposed in frontend
const client = new MindPeekerClient({
apiKey: 'pk_live_1234567890abcdef' // Visible to users
});
// ✅ GOOD - Server-side only
// frontend.js
async function createSession(target) {
const response = await fetch('/api/sessions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ target })
});
return response.json();
}
// backend.js
const client = new MindPeekerClient({
apiKey: process.env.MINDPEEKER_API_KEY // Secure environment variable
});
Use environment variables for configuration
MINDPEEKER_API_KEY=your_api_key_here
MINDPEEKER_WEBHOOK_SECRET=your_webhook_secret
MINDPEEKER_API_URL=https://api.mindpeeker.com/v1
// config.js
const config = {
apiKey: process.env.MINDPEEKER_API_KEY,
webhookSecret: process.env.MINDPEEKER_WEBHOOK_SECRET,
apiUrl: process.env.MINDPEEKER_API_URL || 'https://api.mindpeeker.com/v1'
};
// Validate required configuration
const requiredEnvVars = ['MINDPEEKER_API_KEY'];
const missingVars = requiredEnvVars.filter(varName => !process.env[varName]);
if (missingVars.length > 0) {
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
}
Implement API key rotation
class ApiKeyManager {
constructor() {
this.currentKey = process.env.MINDPEEKER_API_KEY;
this.backupKey = process.env.MINDPEEKER_BACKUP_API_KEY;
this.currentKeyIndex = 0;
this.keys = [this.currentKey, this.backupKey];
}
getClient() {
return new MindPeekerClient({
apiKey: this.keys[this.currentKeyIndex]
});
}
async rotateKey() {
// Try backup key first
this.currentKeyIndex = 1;
const testClient = this.getClient();
try {
await testClient.sessions.list({ limit: 1 });
// Backup key works, make it primary
this.keys.reverse();
this.currentKeyIndex = 0;
console.log('API key rotation successful');
} catch (error) {
// Backup key failed, revert to original
this.currentKeyIndex = 0;
throw new Error('API key rotation failed: backup key invalid');
}
}
}
Validate all user inputs
const Joi = require('joi');
const sessionSchema = Joi.object({
type: Joi.string().valid('remote_viewing', 'dowsing', 'automatic_writing').required(),
target: Joi.string().min(1).max(1000).required(),
modality: Joi.string().valid('visual', 'kinesthetic', 'auditory').optional(),
duration_minutes: Joi.number().integer().min(5).max(180).optional()
});
function validateSessionInput(data) {
const { error, value } = sessionSchema.validate(data);
if (error) {
throw new Error(`Validation error: ${error.details[0].message}`);
}
return value;
}
// Usage
app.post('/api/sessions', async (req, res) => {
try {
const validatedData = validateSessionInput(req.body);
const session = await mindpeekerClient.sessions.create(validatedData);
res.json(session);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
Sanitize outputs to prevent data leakage
function sanitizeSessionResults(results) {
const sanitized = {
sessionId: results.session_id,
status: results.status,
confidenceScore: results.confidence_score,
completedAt: results.completed_at
};
// Only include results if they exist and user has permission
if (results.results && hasPermissionToViewResults(req.user)) {
sanitized.results = {
coordinates: results.results.coordinates,
descriptors: results.results.descriptors,
// Exclude sensitive internal data
internalMetadata: undefined,
analystNotes: undefined
};
}
return sanitized;
}
Verify webhook signatures
import hmac
import hashlib
from flask import Flask, request, abort
app = Flask(__name__)
def verify_webhook_signature(payload, signature, secret):
"""Verify webhook signature using HMAC-SHA256"""
if not signature:
return False
expected_signature = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(
f'sha256={expected_signature}',
signature
)
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-MindPeeker-Signature')
payload = request.data
if not verify_webhook_signature(payload, signature, app.config['WEBHOOK_SECRET']):
abort(401) # Unauthorized
# Process webhook
event = request.get_json()
process_webhook_event(event)
return '', 200
Implement replay protection
import redis
from datetime import datetime, timedelta
redis_client = redis.Redis(host='localhost', port=6379, db=0)
@app.route('/webhook', methods=['POST'])
def webhook():
# Verify signature first
if not verify_webhook_signature(...):
abort(401)
event = request.get_json()
event_id = event.get('id')
# Check for duplicate events
if redis_client.exists(f'webhook_event:{event_id}'):
return '', 200 # Already processed
# Mark event as processed
redis_client.setex(
f'webhook_event:{event_id}',
timedelta(hours=24), # Expire after 24 hours
'processed'
)
# Process event
process_webhook_event(event)
return '', 200
Use connection pooling
const { MindPeekerClient } = require('@mindpeeker/javascript');
class MindPeekerPool {
constructor(options = {}) {
this.maxSize = options.maxSize || 10;
this.minSize = options.minSize || 2;
this.clients = [];
this.availableClients = [];
this.waitingQueue = [];
this.initializePool();
}
async initializePool() {
for (let i = 0; i < this.minSize; i++) {
const client = new MindPeekerClient({
apiKey: process.env.MINDPEEKER_API_KEY,
timeout: 30000,
retryAttempts: 3
});
this.clients.push(client);
this.availableClients.push(client);
}
}
async getClient() {
if (this.availableClients.length > 0) {
return this.availableClients.pop();
}
if (this.clients.length < this.maxSize) {
const client = new MindPeekerClient({
apiKey: process.env.MINDPEEKER_API_KEY
});
this.clients.push(client);
return client;
}
// Wait for available client
return new Promise((resolve) => {
this.waitingQueue.push(resolve);
});
}
releaseClient(client) {
if (this.waitingQueue.length > 0) {
const resolve = this.waitingQueue.shift();
resolve(client);
} else {
this.availableClients.push(client);
}
}
}
// Usage
const pool = new MindPeekerPool({ maxSize: 5 });
async function createSession(target) {
const client = await pool.getClient();
try {
return await client.sessions.create({ target, type: 'remote_viewing' });
} finally {
pool.releaseClient(client);
}
}
Implement intelligent caching
const NodeCache = require('node-cache');
class MindPeekerCache {
constructor(options = {}) {
this.cache = new NodeCache({
stdTTL: options.defaultTTL || 300, // 5 minutes
checkperiod: options.checkPeriod || 60, // 1 minute
useClones: false
});
this.client = new MindPeekerClient({
apiKey: process.env.MINDPEEKER_API_KEY
});
}
async getSessionResults(sessionId, options = {}) {
const cacheKey = `session_results:${sessionId}`;
let results = this.cache.get(cacheKey);
if (results) {
return results;
}
// Fetch from API
results = await this.client.sessions.getResults(sessionId);
// Cache based on session status
if (results.status === 'completed') {
this.cache.set(cacheKey, results, options.completedTTL || 3600); // 1 hour
} else if (results.status === 'failed') {
this.cache.set(cacheKey, results, options.failedTTL || 300); // 5 minutes
} else {
this.cache.set(cacheKey, results, options.pendingTTL || 60); // 1 minute
}
return results;
}
invalidateSession(sessionId) {
this.cache.del(`session_results:${sessionId}`);
}
clearCache() {
this.cache.flushAll();
}
getStats() {
return this.cache.getStats();
}
}
Process multiple requests efficiently
class BatchProcessor {
constructor(client, options = {}) {
this.client = client;
this.batchSize = options.batchSize || 10;
this.concurrency = options.concurrency || 3;
this.delay = options.delay || 100; // ms between batches
}
async processSessions(sessionIds, processor) {
const results = [];
for (let i = 0; i < sessionIds.length; i += this.batchSize) {
const batch = sessionIds.slice(i, i + this.batchSize);
const batchResults = await Promise.all(
batch.map(sessionId =>
this.processWithRetry(sessionId, processor)
)
);
results.push(...batchResults);
// Rate limiting between batches
if (i + this.batchSize < sessionIds.length) {
await this.delay(this.delay);
}
}
return results;
}
async processWithRetry(sessionId, processor, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await processor(sessionId);
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
await this.delay(delay);
}
}
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const batchProcessor = new BatchProcessor(mindpeekerClient, {
batchSize: 5,
concurrency: 2,
delay: 200
});
const sessionIds = ['sess_1', 'sess_2', 'sess_3', 'sess_4', 'sess_5'];
const results = await batchProcessor.processSessions(
sessionIds,
async (sessionId) => {
return await mindpeekerClient.sessions.getResults(sessionId);
}
);
Implement custom error classes
class MindPeekerError extends Error {
constructor(message, code, details = {}) {
super(message);
this.name = 'MindPeekerError';
this.code = code;
this.details = details;
this.timestamp = new Date().toISOString();
}
}
class RateLimitError extends MindPeekerError {
constructor(retryAfter) {
super('Rate limit exceeded', 'RATE_LIMIT_EXCEEDED', { retryAfter });
this.name = 'RateLimitError';
}
}
class AuthenticationError extends MindPeekerError {
constructor() {
super('Authentication failed', 'AUTHENTICATION_ERROR');
this.name = 'AuthenticationError';
}
}
class ValidationError extends MindPeekerError {
constructor(field, value) {
super(`Invalid ${field}: ${value}`, 'VALIDATION_ERROR', { field, value });
this.name = 'ValidationError';
}
}
Centralized error handling middleware
function errorHandler(err, req, res, next) {
// Log error
console.error(`Error ${err.name}: ${err.message}`, {
code: err.code,
details: err.details,
stack: err.stack,
requestId: req.id,
userId: req.user?.id,
timestamp: err.timestamp
});
// Determine response based on error type
if (err instanceof RateLimitError) {
return res.status(429).json({
error: {
code: 'RATE_LIMIT_EXCEEDED',
message: 'Too many requests',
retryAfter: err.details.retryAfter
}
});
}
if (err instanceof AuthenticationError) {
return res.status(401).json({
error: {
code: 'AUTHENTICATION_ERROR',
message: 'Invalid credentials'
}
});
}
if (err instanceof ValidationError) {
return res.status(400).json({
error: {
code: 'VALIDATION_ERROR',
message: err.message,
field: err.details.field
}
});
}
// Default error response
res.status(500).json({
error: {
code: 'INTERNAL_ERROR',
message: 'An unexpected error occurred'
}
});
}
Exponential backoff with jitter
class RetryHandler {
constructor(options = {}) {
this.maxRetries = options.maxRetries || 3;
this.baseDelay = options.baseDelay || 1000;
this.maxDelay = options.maxDelay || 30000;
this.jitterFactor = options.jitterFactor || 0.1;
}
async executeWithRetry(operation, context = {}) {
let lastError;
for (let attempt = 1; attempt <= this.maxRetries + 1; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
// Don't retry on certain errors
if (this.isNonRetryableError(error)) {
throw error;
}
// Don't retry on last attempt
if (attempt > this.maxRetries) {
break;
}
const delay = this.calculateDelay(attempt);
console.log(`Attempt ${attempt} failed, retrying in ${delay}ms:`, error.message);
await this.sleep(delay);
}
}
throw lastError;
}
isNonRetryableError(error) {
const nonRetryableCodes = [
'AUTHENTICATION_ERROR',
'VALIDATION_ERROR',
'PERMISSION_DENIED'
];
return nonRetryableCodes.includes(error.code) ||
error.status === 401 ||
error.status === 403 ||
error.status === 422;
}
calculateDelay(attempt) {
// Exponential backoff with jitter
const exponentialDelay = Math.min(
this.baseDelay * Math.pow(2, attempt - 1),
this.maxDelay
);
// Add jitter to prevent thundering herd
const jitter = exponentialDelay * this.jitterFactor * Math.random();
return Math.floor(exponentialDelay + jitter);
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const retryHandler = new RetryHandler({
maxRetries: 3,
baseDelay: 1000,
maxDelay: 10000
});
async function createSessionWithRetry(sessionData) {
return await retryHandler.executeWithRetry(async () => {
return await mindpeekerClient.sessions.create(sessionData);
});
}
Implement comprehensive logging
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
defaultMeta: {
service: 'mindpeeker-integration',
version: process.env.APP_VERSION || '1.0.0'
},
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
new winston.transports.Console({
format: winston.format.simple()
})
]
});
// Logging middleware
function requestLogger(req, res, next) {
const requestId = req.id || generateRequestId();
req.requestId = requestId;
logger.info('Request started', {
requestId,
method: req.method,
url: req.url,
userAgent: req.get('User-Agent'),
ip: req.ip,
userId: req.user?.id
});
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info('Request completed', {
requestId,
statusCode: res.statusCode,
duration,
userId: req.user?.id
});
});
next();
}
Track key performance indicators
class MetricsCollector {
constructor() {
this.metrics = {
requests: {
total: 0,
successful: 0,
failed: 0,
responseTime: []
},
sessions: {
created: 0,
completed: 0,
failed: 0,
averageCompletionTime: 0
},
errors: {
rateLimit: 0,
authentication: 0,
validation: 0,
server: 0
}
};
}
recordRequest(duration, success, statusCode) {
this.metrics.requests.total++;
this.metrics.requests.responseTime.push(duration);
if (success) {
this.metrics.requests.successful++;
} else {
this.metrics.requests.failed++;
this.categorizeError(statusCode);
}
}
categorizeError(statusCode) {
if (statusCode === 429) {
this.metrics.errors.rateLimit++;
} else if (statusCode === 401 || statusCode === 403) {
this.metrics.errors.authentication++;
} else if (statusCode >= 400 && statusCode < 500) {
this.metrics.errors.validation++;
} else if (statusCode >= 500) {
this.metrics.errors.server++;
}
}
recordSession(action, duration = null) {
switch (action) {
case 'created':
this.metrics.sessions.created++;
break;
case 'completed':
this.metrics.sessions.completed++;
if (duration) {
this.updateAverageCompletionTime(duration);
}
break;
case 'failed':
this.metrics.sessions.failed++;
break;
}
}
updateAverageCompletionTime(duration) {
const total = this.metrics.sessions.completed;
const current = this.metrics.sessions.averageCompletionTime;
this.metrics.sessions.averageCompletionTime = ((current * (total - 1)) + duration) / total;
}
getMetrics() {
return {
...this.metrics,
successRate: this.calculateSuccessRate(),
averageResponseTime: this.calculateAverageResponseTime(),
p95ResponseTime: this.calculateP95ResponseTime()
};
}
calculateSuccessRate() {
const total = this.metrics.requests.total;
return total > 0 ? (this.metrics.requests.successful / total) * 100 : 0;
}
calculateAverageResponseTime() {
const times = this.metrics.requests.responseTime;
return times.length > 0 ? times.reduce((a, b) => a + b, 0) / times.length : 0;
}
calculateP95ResponseTime() {
const times = [...this.metrics.requests.responseTime].sort((a, b) => a - b);
const index = Math.floor(times.length * 0.95);
return times[index] || 0;
}
}
Structure tests logically
// tests/unit/sessions.test.js
describe('Sessions API', () => {
let mockClient;
let sessionsAPI;
beforeEach(() => {
mockClient = new MockMindPeekerClient();
sessionsAPI = new SessionsAPI(mockClient);
});
describe('createSession', () => {
it('should create a session with valid parameters', async () => {
// Arrange
const sessionData = {
type: 'remote_viewing',
target: 'Test target',
modality: 'visual'
};
mockClient.setMockResponse('sessions.create', {
sessionId: 'test_123',
status: 'initiated'
});
// Act
const result = await sessionsAPI.createSession(sessionData);
// Assert
expect(result.sessionId).toBe('test_123');
expect(result.status).toBe('initiated');
expect(mockClient.requests).toHaveLength(1);
expect(mockClient.requests[0].params).toMatchObject(sessionData);
});
it('should throw validation error for invalid parameters', async () => {
// Arrange
const invalidData = {
type: 'invalid_type',
target: '',
modality: 'invalid_modality'
};
// Act & Assert
await expect(sessionsAPI.createSession(invalidData))
.rejects
.toThrow(ValidationError);
});
});
});
Use factories for test data
// tests/factories/session-factory.js
class SessionFactory {
static create(overrides = {}) {
return {
type: 'remote_viewing',
target: 'Test investigation target',
modality: 'visual',
duration_minutes: 30,
privacy_level: 'private',
...overrides
};
}
static createCompleted(overrides = {}) {
return {
sessionId: 'completed_session_123',
status: 'completed',
confidenceScore: 0.85,
completedAt: '2025-01-15T10:30:00Z',
results: {
coordinates: { latitude: 40.7128, longitude: -74.0060 },
descriptors: ['test location', 'urban environment']
},
...overrides
};
}
static createFailed(overrides = {}) {
return {
sessionId: 'failed_session_123',
status: 'failed',
error: 'Session timeout',
...overrides
};
}
}
// Usage in tests
const validSession = SessionFactory.create();
const completedSession = SessionFactory.createCompleted({
confidenceScore: 0.92
});
Maintain comprehensive API docs
/**
* Creates a new psychic investigation session
*
* @param {Object} sessionData - Session configuration
* @param {string} sessionData.type - Type of psychic investigation
* @param {'remote_viewing'|'dowsing'|'automatic_writing'} sessionData.type
* @param {string} sessionData.target - Target description (1-1000 chars)
* @param {string} [sessionData.modality] - Psychic modality
* @param {'visual'|'kinesthetic'|'auditory'} [sessionData.modality]
* @param {number} [sessionData.duration_minutes=30] - Session duration in minutes
* @param {string} [sessionData.privacy_level='private'] - Privacy level
* @param {'public'|'private'|'classified'} [sessionData.privacy_level]
*
* @returns {Promise<Session>} Created session object
* @throws {ValidationError} When input parameters are invalid
* @throws {AuthenticationError} When API credentials are invalid
* @throws {RateLimitError} When rate limit is exceeded
*
* @example
* const session = await createSession({
* type: 'remote_viewing',
* target: 'Missing person investigation',
* modality: 'visual',
* duration_minutes: 45
* });
*/
async function createSession(sessionData) {
// Implementation
}