From 1e77ecd145d3dea46e04ca5ecc6692b41e569c1e Mon Sep 17 00:00:00 2001 From: David Snelling Date: Thu, 9 Oct 2025 10:39:54 -0700 Subject: [PATCH] fix: enable GCS native storage with Application Default Credentials This fixes critical bugs that completely blocked GCS native storage from working: 1. Type validation rejected 'gcs-native' as invalid storage type 2. TypeScript type definition didn't include 'gcs-native' 3. Auto-detection returned S3-compatible GCS instead of native SDK 4. No validation for type/config mismatches (gcs vs gcs-native) Changes: - Add 'gcs-native' to storage type validation array (src/brainy.ts) - Add GCS_NATIVE enum value to StorageType (src/config/storageAutoConfig.ts) - Add 'gcs-native' to StorageTypeString type union (src/config/storageAutoConfig.ts) - Change auto-detection to use native GCS SDK with ADC instead of S3-compatible (src/config/storageAutoConfig.ts) - Add helpful validation to catch type/config mismatches (src/brainy.ts) Impact: - GCS native storage now works as documented - Cloud Run deployments can use Application Default Credentials - Auto-detection correctly selects native adapter in GCP environments - Clear error messages guide users when they mix up gcs vs gcs-native Fixes production blocker for teams deploying on Google Cloud Platform. --- src/brainy.ts | 27 +++++++++++++++++++++++++-- src/config/storageAutoConfig.ts | 13 +++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/brainy.ts b/src/brainy.ts index c746912c..32665296 100644 --- a/src/brainy.ts +++ b/src/brainy.ts @@ -2666,8 +2666,31 @@ export class Brainy implements BrainyInterface { */ private normalizeConfig(config?: BrainyConfig): Required { // Validate storage configuration - if (config?.storage?.type && !['auto', 'memory', 'filesystem', 'opfs', 'remote', 's3', 'r2', 'gcs'].includes(config.storage.type)) { - throw new Error(`Invalid storage type: ${config.storage.type}. Must be one of: auto, memory, filesystem, opfs, remote, s3, r2, gcs`) + if (config?.storage?.type && !['auto', 'memory', 'filesystem', 'opfs', 'remote', 's3', 'r2', 'gcs', 'gcs-native'].includes(config.storage.type)) { + throw new Error(`Invalid storage type: ${config.storage.type}. Must be one of: auto, memory, filesystem, opfs, remote, s3, r2, gcs, gcs-native`) + } + + // Validate storage type/config pairing (catch common mismatches) + if (config?.storage) { + const storage = config.storage as any + + // Check for gcs/gcsNativeStorage mismatch + if (storage.type === 'gcs' && storage.gcsNativeStorage) { + throw new Error( + `Storage type/config mismatch: type 'gcs' requires 'gcsStorage' config object (S3-compatible). ` + + `You provided 'gcsNativeStorage' which requires type 'gcs-native'. ` + + `Either change type to 'gcs-native' or use 'gcsStorage' instead of 'gcsNativeStorage'.` + ) + } + + // Check for gcs-native/gcsStorage mismatch + if (storage.type === 'gcs-native' && storage.gcsStorage) { + throw new Error( + `Storage type/config mismatch: type 'gcs-native' requires 'gcsNativeStorage' config object. ` + + `You provided 'gcsStorage' which requires type 'gcs' (S3-compatible). ` + + `Either change type to 'gcs' or use 'gcsNativeStorage' instead of 'gcsStorage'.` + ) + } } // Validate model configuration diff --git a/src/config/storageAutoConfig.ts b/src/config/storageAutoConfig.ts index a375ca6c..17d1e701 100644 --- a/src/config/storageAutoConfig.ts +++ b/src/config/storageAutoConfig.ts @@ -10,10 +10,11 @@ import { isBrowser, isNode } from '../utils/environment.js' */ export enum StorageType { MEMORY = 'memory', - FILESYSTEM = 'filesystem', + FILESYSTEM = 'filesystem', OPFS = 'opfs', S3 = 's3', GCS = 'gcs', + GCS_NATIVE = 'gcs-native', R2 = 'r2' } @@ -28,7 +29,7 @@ export enum StoragePreset { } // Backward compatibility type aliases -export type StorageTypeString = 'memory' | 'filesystem' | 'opfs' | 's3' | 'gcs' | 'r2' +export type StorageTypeString = 'memory' | 'filesystem' | 'opfs' | 's3' | 'gcs' | 'r2' | 'gcs-native' export type StoragePresetString = 'auto' | 'memory' | 'disk' | 'cloud' export interface StorageConfigResult { @@ -197,14 +198,14 @@ async function detectCloudStorage(): Promise<{ type: StorageType; config: any } } } - // Google Cloud Storage Detection + // Google Cloud Storage Detection (Native SDK with ADC) if (hasGCPConfig()) { return { - type: StorageType.GCS, + type: StorageType.GCS_NATIVE, config: { - gcsStorage: { + gcsNativeStorage: { bucketName: process.env.GCS_BUCKET || process.env.GOOGLE_STORAGE_BUCKET || 'brainy-data', - // Credentials will be picked up by GCP SDK automatically + // Application Default Credentials will be picked up automatically } } }