chore: recovery checkpoint - v3.0 API successfully recovered
CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB Recovery Status: - Successfully recovered brainy.ts from compiled JavaScript - All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.) - Neural subsystem intact (562KB embedded patterns, NLP working) - Augmentation pipeline operational (20+ augmentations) - HNSW clustering system complete - Triple Intelligence compiled (needs constructor fix) - Test suite validates functionality Changes preserved: - 898 files with changes from last 3 days - 144,475 insertions - All augmentation improvements - All test coverage enhancements - Complete v3.0 feature set This is a LOCAL checkpoint only - contains recovered work after corruption incident. Created backup in .backups/brainy-full-20250910-151314.tar.gz Branch: recovery-checkpoint-20250910-151433 Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
parent
f65455fb22
commit
8ff382ca3b
895 changed files with 143654 additions and 28268 deletions
|
|
@ -0,0 +1,328 @@
|
|||
/**
|
||||
* Storage Configuration Auto-Detection
|
||||
* Intelligently selects storage based on environment and available services
|
||||
*/
|
||||
import { isBrowser, isNode } from '../utils/environment.js';
|
||||
/**
|
||||
* Low-level storage implementation types
|
||||
*/
|
||||
export var StorageType;
|
||||
(function (StorageType) {
|
||||
StorageType["MEMORY"] = "memory";
|
||||
StorageType["FILESYSTEM"] = "filesystem";
|
||||
StorageType["OPFS"] = "opfs";
|
||||
StorageType["S3"] = "s3";
|
||||
StorageType["GCS"] = "gcs";
|
||||
StorageType["R2"] = "r2";
|
||||
})(StorageType || (StorageType = {}));
|
||||
/**
|
||||
* High-level storage presets (maps to StorageType)
|
||||
*/
|
||||
export var StoragePreset;
|
||||
(function (StoragePreset) {
|
||||
StoragePreset["AUTO"] = "auto";
|
||||
StoragePreset["MEMORY"] = "memory";
|
||||
StoragePreset["DISK"] = "disk";
|
||||
StoragePreset["CLOUD"] = "cloud";
|
||||
})(StoragePreset || (StoragePreset = {}));
|
||||
/**
|
||||
* Auto-detect the best storage configuration
|
||||
* @param override - Manual override: specific type or preset
|
||||
*/
|
||||
export async function autoDetectStorage(override) {
|
||||
// Handle direct storage config object
|
||||
if (override && typeof override === 'object') {
|
||||
return {
|
||||
type: override.type || 'memory',
|
||||
config: override,
|
||||
reason: 'Manually configured storage',
|
||||
autoSelected: false
|
||||
};
|
||||
}
|
||||
// Handle storage type override (enum values or strings)
|
||||
if (override && Object.values(StorageType).includes(override)) {
|
||||
return {
|
||||
type: override,
|
||||
config: override,
|
||||
reason: `Manually specified: ${override}`,
|
||||
autoSelected: false
|
||||
};
|
||||
}
|
||||
// Handle presets (both enum and string values)
|
||||
if (override === StoragePreset.MEMORY || override === 'memory') {
|
||||
return {
|
||||
type: StorageType.MEMORY,
|
||||
config: StorageType.MEMORY,
|
||||
reason: 'Preset: memory storage',
|
||||
autoSelected: false
|
||||
};
|
||||
}
|
||||
if (override === StoragePreset.DISK || override === 'disk') {
|
||||
const diskType = isBrowser() ? StorageType.OPFS : StorageType.FILESYSTEM;
|
||||
return {
|
||||
type: diskType,
|
||||
config: diskType,
|
||||
reason: `Preset: disk storage (${diskType})`,
|
||||
autoSelected: false
|
||||
};
|
||||
}
|
||||
if (override === StoragePreset.CLOUD || override === 'cloud') {
|
||||
const cloudStorage = await detectCloudStorage();
|
||||
if (cloudStorage) {
|
||||
return {
|
||||
...cloudStorage,
|
||||
reason: `Preset: cloud storage (${cloudStorage.type})`,
|
||||
autoSelected: false
|
||||
};
|
||||
}
|
||||
// Fallback to disk if no cloud storage detected
|
||||
const diskType = isBrowser() ? StorageType.OPFS : StorageType.FILESYSTEM;
|
||||
return {
|
||||
type: diskType,
|
||||
config: diskType,
|
||||
reason: 'Preset: cloud (none detected, using disk)',
|
||||
autoSelected: false
|
||||
};
|
||||
}
|
||||
// Auto-detection logic
|
||||
return await autoDetectBestStorage();
|
||||
}
|
||||
/**
|
||||
* Automatically detect the best storage option
|
||||
*/
|
||||
async function autoDetectBestStorage() {
|
||||
// Check for cloud storage first (highest priority in production)
|
||||
const cloudStorage = await detectCloudStorage();
|
||||
if (cloudStorage && process.env.NODE_ENV === 'production') {
|
||||
return {
|
||||
...cloudStorage,
|
||||
reason: `Auto-detected ${cloudStorage.type} in production`,
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
// Browser environment
|
||||
if (isBrowser()) {
|
||||
// Check for OPFS support
|
||||
if (await hasOPFSSupport()) {
|
||||
return {
|
||||
type: StorageType.OPFS,
|
||||
config: { requestPersistentStorage: true },
|
||||
reason: 'Browser with OPFS support detected',
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
// Fallback to memory for browsers without OPFS
|
||||
return {
|
||||
type: StorageType.MEMORY,
|
||||
config: StorageType.MEMORY,
|
||||
reason: 'Browser without OPFS - using memory',
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
// Serverless environment - prefer memory or cloud
|
||||
if (isServerlessEnvironment()) {
|
||||
if (cloudStorage) {
|
||||
return {
|
||||
...cloudStorage,
|
||||
reason: `Serverless with ${cloudStorage.type} detected`,
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: StorageType.MEMORY,
|
||||
config: StorageType.MEMORY,
|
||||
reason: 'Serverless environment - using memory',
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
// Node.js environment - use filesystem
|
||||
if (isNode()) {
|
||||
const dataPath = await findBestDataPath();
|
||||
return {
|
||||
type: StorageType.FILESYSTEM,
|
||||
config: StorageType.FILESYSTEM,
|
||||
reason: `Node.js environment - using filesystem at ${dataPath}`,
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
// Fallback to memory
|
||||
return {
|
||||
type: StorageType.MEMORY,
|
||||
config: StorageType.MEMORY,
|
||||
reason: 'Default fallback - using memory',
|
||||
autoSelected: true
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Detect cloud storage from environment variables
|
||||
*/
|
||||
async function detectCloudStorage() {
|
||||
// AWS S3 Detection
|
||||
if (hasAWSConfig()) {
|
||||
return {
|
||||
type: StorageType.S3,
|
||||
config: {
|
||||
s3Storage: {
|
||||
bucketName: process.env.AWS_BUCKET || process.env.S3_BUCKET_NAME || 'brainy-data',
|
||||
region: process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1',
|
||||
// Credentials will be picked up by AWS SDK automatically
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
// Google Cloud Storage Detection
|
||||
if (hasGCPConfig()) {
|
||||
return {
|
||||
type: StorageType.GCS,
|
||||
config: {
|
||||
gcsStorage: {
|
||||
bucketName: process.env.GCS_BUCKET || process.env.GOOGLE_STORAGE_BUCKET || 'brainy-data',
|
||||
// Credentials will be picked up by GCP SDK automatically
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
// Cloudflare R2 Detection
|
||||
if (hasR2Config()) {
|
||||
return {
|
||||
type: StorageType.R2,
|
||||
config: {
|
||||
r2Storage: {
|
||||
bucketName: process.env.R2_BUCKET || 'brainy-data',
|
||||
accountId: process.env.CLOUDFLARE_ACCOUNT_ID,
|
||||
accessKeyId: process.env.R2_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Check if AWS S3 is configured
|
||||
*/
|
||||
function hasAWSConfig() {
|
||||
return !!(
|
||||
// Explicit S3 bucket
|
||||
process.env.AWS_BUCKET ||
|
||||
process.env.S3_BUCKET_NAME ||
|
||||
// AWS credentials (SDK will find them)
|
||||
process.env.AWS_ACCESS_KEY_ID ||
|
||||
process.env.AWS_PROFILE ||
|
||||
// AWS environment indicators
|
||||
process.env.AWS_EXECUTION_ENV ||
|
||||
process.env.AWS_LAMBDA_FUNCTION_NAME ||
|
||||
process.env.ECS_CONTAINER_METADATA_URI);
|
||||
}
|
||||
/**
|
||||
* Check if Google Cloud Storage is configured
|
||||
*/
|
||||
function hasGCPConfig() {
|
||||
return !!(
|
||||
// Explicit GCS bucket
|
||||
process.env.GCS_BUCKET ||
|
||||
process.env.GOOGLE_STORAGE_BUCKET ||
|
||||
// GCP credentials
|
||||
process.env.GOOGLE_APPLICATION_CREDENTIALS ||
|
||||
// GCP environment indicators
|
||||
process.env.GOOGLE_CLOUD_PROJECT ||
|
||||
process.env.K_SERVICE ||
|
||||
process.env.GAE_SERVICE);
|
||||
}
|
||||
/**
|
||||
* Check if Cloudflare R2 is configured
|
||||
*/
|
||||
function hasR2Config() {
|
||||
return !!(process.env.R2_BUCKET ||
|
||||
(process.env.CLOUDFLARE_ACCOUNT_ID && process.env.R2_ACCESS_KEY_ID));
|
||||
}
|
||||
/**
|
||||
* Check if running in serverless environment
|
||||
*/
|
||||
function isServerlessEnvironment() {
|
||||
if (!isNode())
|
||||
return false;
|
||||
return !!(process.env.AWS_LAMBDA_FUNCTION_NAME ||
|
||||
process.env.VERCEL ||
|
||||
process.env.NETLIFY ||
|
||||
process.env.CLOUDFLARE_WORKERS ||
|
||||
process.env.FUNCTIONS_WORKER_RUNTIME ||
|
||||
process.env.K_SERVICE ||
|
||||
process.env.RAILWAY_ENVIRONMENT ||
|
||||
process.env.FLY_APP_NAME);
|
||||
}
|
||||
/**
|
||||
* Check for OPFS support in browser
|
||||
*/
|
||||
async function hasOPFSSupport() {
|
||||
if (!isBrowser())
|
||||
return false;
|
||||
try {
|
||||
return 'storage' in navigator &&
|
||||
'getDirectory' in navigator.storage;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Find the best path for filesystem storage
|
||||
*/
|
||||
async function findBestDataPath() {
|
||||
if (!isNode())
|
||||
return './brainy-data';
|
||||
const homeDir = process.env.HOME || process.env.USERPROFILE || '~';
|
||||
const tempDir = process.env.TMPDIR || process.env.TEMP || '/tmp';
|
||||
const candidates = [
|
||||
// User-specified path
|
||||
process.env.BRAINY_DATA_PATH,
|
||||
// Current directory
|
||||
'./brainy-data',
|
||||
// Home directory
|
||||
`${homeDir}/.brainy/data`,
|
||||
// Temp directory (last resort)
|
||||
`${tempDir}/brainy-data`
|
||||
].filter(Boolean);
|
||||
// Find first writable directory
|
||||
for (const candidate of candidates) {
|
||||
if (await isWritable(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
// Default fallback
|
||||
return candidates[1]; // ./brainy-data
|
||||
}
|
||||
/**
|
||||
* Check if a directory is writable
|
||||
*/
|
||||
async function isWritable(dirPath) {
|
||||
if (!isNode())
|
||||
return false;
|
||||
try {
|
||||
// Dynamic import fs for Node.js
|
||||
const { promises: fs } = await import('fs');
|
||||
const path = await import('path');
|
||||
// Try to create directory if it doesn't exist
|
||||
await fs.mkdir(dirPath, { recursive: true });
|
||||
// Try to write a test file
|
||||
const testFile = path.join(dirPath, '.write-test');
|
||||
await fs.writeFile(testFile, 'test');
|
||||
await fs.unlink(testFile);
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Legacy getStorageConfig function removed - now using simple string types
|
||||
/**
|
||||
* Log storage configuration decision
|
||||
*/
|
||||
export function logStorageConfig(config, verbose = false) {
|
||||
if (!verbose && process.env.NODE_ENV === 'production') {
|
||||
return; // Silent in production unless verbose
|
||||
}
|
||||
const icon = config.autoSelected ? '🤖' : '👤';
|
||||
console.log(`${icon} Storage: ${config.type.toUpperCase()} - ${config.reason}`);
|
||||
}
|
||||
//# sourceMappingURL=storageAutoConfig.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue