Best Practices
Tips and patterns for getting the most out of Hypersave.
Content Management
Optimize What You Save
Save meaningful content, not everything:
// Good: Focused, meaningful content
await save({
content: "The Q4 budget was approved at $2.5M with 60% allocated to engineering",
title: "Q4 Budget Decision",
tags: ["budget", "finance", "q4"]
});
// Avoid: Raw, unstructured data
await save({
content: "[10:23] user joined\n[10:24] user: hi\n[10:24] bot: hello..."
});Use Structured Metadata
await save({
content: "...",
metadata: {
source: "meeting-notes",
participants: ["john", "jane"],
date: "2024-01-15",
project: "website-redesign",
actionItems: 3
}
});Consistent Tagging
Establish a tagging convention:
const TAGS = {
type: ['meeting', 'research', 'decision', 'idea'],
status: ['active', 'archived', 'pending'],
priority: ['high', 'medium', 'low'],
team: ['engineering', 'product', 'design', 'sales']
};
// Apply consistently
await save({
content: "...",
tags: ['type:meeting', 'team:engineering', 'priority:high']
});Search Optimization
Use Hybrid Search
For most queries, hybrid search (semantic + keyword) gives best results:
const results = await search({
query: "TypeScript configuration",
hybrid: true, // Combine semantic and keyword
threshold: 0.6
});Filter Strategically
Narrow down results with filters:
// Search only recent, high-priority items
const results = await search({
query: "deployment issues",
tags: ["priority:high"],
after: "2024-01-01"
});Set Appropriate Thresholds
// High precision (fewer but more relevant results)
const preciseResults = await search({
query: "exact technical spec",
threshold: 0.85
});
// High recall (more results, some less relevant)
const broadResults = await search({
query: "general topic exploration",
threshold: 0.5
});Performance
Use Turbo Mode for Speed
When you need fast responses and don't need full processing:
// Real-time chat: use turbo
await turboSave({ content: quickNote });
// Important document: use standard
await save({ content: importantDoc });Batch Operations
Use bulk endpoints for multiple items:
// Good: Single batch request
await ingest({
items: documents,
async: true
});
// Avoid: Multiple individual requests
for (const doc of documents) {
await save(doc); // Slower, uses more quota
}Implement Caching
Cache frequent queries:
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function cachedSearch(query) {
const cacheKey = JSON.stringify(query);
if (cache.has(cacheKey)) {
const { data, timestamp } = cache.get(cacheKey);
if (Date.now() - timestamp < CACHE_TTL) {
return data;
}
}
const results = await search(query);
cache.set(cacheKey, { data: results, timestamp: Date.now() });
return results;
}Security
Protect API Keys
⚠️
Never expose API keys in client-side code or version control.
// Server-side only
const API_KEY = process.env.HYPERSAVE_API_KEY;
// Create a backend proxy for client requests
app.post('/api/search', async (req, res) => {
const results = await hypersave.search(req.body);
res.json(results);
});User Data Isolation
Use tags or spaces to isolate user data:
// Tag-based isolation
async function searchUserContent(query, userId) {
return search({
query,
tags: [`user:${userId}`] // Only returns user's content
});
}
// Space-based isolation
async function saveUserContent(content, userId) {
return save({
content,
spaceId: `user_${userId}_space`
});
}Rate Limiting
Implement rate limiting to prevent abuse:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 60, // 60 requests per minute
message: { error: 'Too many requests' }
});
app.use('/api', limiter);Error Handling
Graceful Degradation
Handle API errors gracefully:
async function searchWithFallback(query) {
try {
const results = await search({ query });
return results;
} catch (error) {
if (error.status === 429) {
// Rate limited: return cached results or wait
console.warn('Rate limited, using cache');
return getCachedResults(query);
}
if (error.status >= 500) {
// Server error: use fallback
console.error('Hypersave unavailable');
return { results: [], error: 'Search temporarily unavailable' };
}
throw error;
}
}Retry Logic
Implement exponential backoff:
async function withRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Usage
const results = await withRetry(() => search({ query: 'test' }));Monitoring
Track Usage
Monitor your API usage:
async function trackUsage() {
const usage = await fetch(`${API}/v1/usage`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
}).then(r => r.json());
if (usage.limits.usedPercentage > 80) {
alert('Approaching usage limit');
}
return usage;
}Log Requests
Log API calls for debugging:
async function loggedRequest(endpoint, options) {
const start = Date.now();
try {
const response = await fetch(endpoint, options);
const duration = Date.now() - start;
console.log({
endpoint,
status: response.status,
duration,
timestamp: new Date().toISOString()
});
return response;
} catch (error) {
console.error({ endpoint, error: error.message });
throw error;
}
}