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.
This commit is contained in:
David Snelling 2025-10-09 10:39:54 -07:00
parent d693adcbc6
commit 1e77ecd145
2 changed files with 32 additions and 8 deletions

View file

@ -2666,8 +2666,31 @@ export class Brainy<T = any> implements BrainyInterface<T> {
*/ */
private normalizeConfig(config?: BrainyConfig): Required<BrainyConfig> { private normalizeConfig(config?: BrainyConfig): Required<BrainyConfig> {
// Validate storage configuration // Validate storage configuration
if (config?.storage?.type && !['auto', 'memory', 'filesystem', 'opfs', 'remote', 's3', 'r2', 'gcs'].includes(config.storage.type)) { 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`) 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 // Validate model configuration

View file

@ -14,6 +14,7 @@ export enum StorageType {
OPFS = 'opfs', OPFS = 'opfs',
S3 = 's3', S3 = 's3',
GCS = 'gcs', GCS = 'gcs',
GCS_NATIVE = 'gcs-native',
R2 = 'r2' R2 = 'r2'
} }
@ -28,7 +29,7 @@ export enum StoragePreset {
} }
// Backward compatibility type aliases // 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 type StoragePresetString = 'auto' | 'memory' | 'disk' | 'cloud'
export interface StorageConfigResult { 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()) { if (hasGCPConfig()) {
return { return {
type: StorageType.GCS, type: StorageType.GCS_NATIVE,
config: { config: {
gcsStorage: { gcsNativeStorage: {
bucketName: process.env.GCS_BUCKET || process.env.GOOGLE_STORAGE_BUCKET || 'brainy-data', 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
} }
} }
} }