chore(8.0)!: drop browser support, cloud SDKs, legacy pipeline, dead threading

Brainy 8.0 is server-only. This commit takes the consequences seriously and
removes everything that was only there to keep browser/cloud/threading
surfaces alive.

Browser support drop (per the @deprecated notes in environment.ts):
  - isBrowser, isWebWorker, areWebWorkersAvailable, navigator.deviceMemory
    paths, window/document/self.onmessage code.
  - browser console.log in unified.ts, the 'browser' branch in
    autoConfiguration.ts (env enum + scaleUp cases), 'browser-cache' model
    path, MCP service environment value.
  - package.json browser field.
  - src/worker.ts (Web Worker entrypoint) deleted.

Cloud SDK removal (the four adapters were dropped in Phase 7; the SDKs
were the lingering tax):
  - @aws-sdk/client-s3, @azure/identity, @azure/storage-blob, and
    @google-cloud/storage removed from package.json. Lockfile drops the
    entire @aws/@azure/@google-cloud/@smithy transitive tree.
  - EnhancedS3Clear class deleted from enhancedClearOperations.ts (the
    only @aws-sdk/client-s3 consumer; the dynamic import sites went with
    it). EnhancedFileSystemClear stays.
  - src/utils/adaptiveSocketManager.ts deleted entirely (474 LOC of HTTPS
    socket-pool management for the dropped cloud HTTP handler).
    performanceMonitor.ts no longer reports a socketConfig; socket
    utilization is fixed at 0.

Dead threading subsystem:
  - executeInThread was imported by distance.ts and hnswIndex.ts but
    never called. It was scaffolding for a future "off-main-thread
    distance batch" optimization that never shipped.
  - src/utils/workerUtils.ts deleted (Web Worker code path + an
    unreachable Node Worker Threads code path).
  - environment.ts loses isThreadingAvailable, isThreadingAvailableAsync,
    areWorkerThreadsAvailable, areWorkerThreadsAvailableSync. All exports
    purged from index.ts and unified.ts.
  - autoConfiguration.ts drops AutoConfigResult.threadingAvailable.

Legacy plugin/augmentation pipeline:
  - src/pipeline.ts deleted. The whole file was a no-op stub for
    backwards compat — Pipeline class had no methods, no lifecycle hooks,
    no before/after callbacks. AugmentationPipeline, augmentationPipeline,
    createPipeline, createStreamingPipeline, StreamlinedPipelineOptions,
    StreamlinedPipelineResult, StreamlinedExecutionMode were all aliases
    for the same stub.
  - src/mcp/mcpAugmentationToolset.ts deleted. executePipeline always
    threw "deprecated", isValidAugmentationType always returned false,
    getAvailableTools always returned []. Dead surface.
  - BrainyMCPService no longer instantiates a toolset. TOOL_EXECUTION
    requests now return the standard UNSUPPORTED_REQUEST_TYPE error.
    'availableTools' system-info returns [] (was the same in practice).

Net: 22 files changed, ~6400 LOC deleted (including legacy code +
mechanical lockfile churn). Build clean, 1409/1409 tests pass.
This commit is contained in:
David Snelling 2026-06-09 16:38:30 -07:00
parent adda1570f3
commit 266715aeee
22 changed files with 134 additions and 4648 deletions

View file

@ -287,207 +287,3 @@ export class EnhancedFileSystemClear {
return result
}
}
/**
* Enhanced S3 bulk delete operations
*/
export class EnhancedS3Clear {
constructor(
private s3Client: any,
private bucketName: string
) {}
/**
* Optimized bulk delete for S3 storage
* Uses batch delete operations for maximum efficiency
*/
async clear(options: ClearOptions = {}): Promise<ClearResult> {
const startTime = Date.now()
const result: ClearResult = {
success: false,
itemsDeleted: { nouns: 0, verbs: 0, metadata: 0, system: 0 },
duration: 0,
errors: []
}
try {
// Safety checks
if (options.confirmInstanceName) {
// Extract instance name from bucket structure or prefix
const bucketInfo = await this.getBucketInfo()
if (bucketInfo.instanceName !== options.confirmInstanceName) {
throw new Error(
`Instance name mismatch: expected '${options.confirmInstanceName}', got '${bucketInfo.instanceName}'`
)
}
}
// Dry run - just count objects
if (options.dryRun) {
return await this.performDryRun(options)
}
// AWS S3 batch delete supports up to 1000 objects per request
const batchSize = Math.min(options.batchSize || 1000, 1000)
// Delete with optimized batching
const prefixes = [
{ prefix: 'nouns/', key: 'nouns' as keyof typeof result.itemsDeleted },
{ prefix: 'verbs/', key: 'verbs' as keyof typeof result.itemsDeleted },
{ prefix: 'metadata/', key: 'metadata' as keyof typeof result.itemsDeleted },
{ prefix: 'noun-metadata/', key: 'metadata' as keyof typeof result.itemsDeleted },
{ prefix: 'verb-metadata/', key: 'metadata' as keyof typeof result.itemsDeleted },
{ prefix: 'system/', key: 'system' as keyof typeof result.itemsDeleted },
{ prefix: 'index/', key: 'system' as keyof typeof result.itemsDeleted }
]
for (const { prefix, key } of prefixes) {
const deleted = await this.clearPrefixOptimized(
prefix,
batchSize,
(progress) => options.onProgress?.({
...progress,
stage: key === 'nouns' ? 'nouns' :
key === 'verbs' ? 'verbs' :
key === 'metadata' ? 'metadata' : 'system'
})
)
result.itemsDeleted[key] += deleted
}
result.success = true
result.duration = Date.now() - startTime
} catch (error) {
result.errors.push(error as Error)
result.duration = Date.now() - startTime
}
return result
}
/**
* High-performance prefix clearing using S3 batch delete
*/
private async clearPrefixOptimized(
prefix: string,
batchSize: number,
onProgress?: (progress: Omit<ClearProgress, 'stage'>) => void
): Promise<number> {
const { ListObjectsV2Command, DeleteObjectsCommand } = await import('@aws-sdk/client-s3')
let totalDeleted = 0
let continuationToken: string | undefined
do {
// List objects with the prefix
const listResponse = await this.s3Client.send(
new ListObjectsV2Command({
Bucket: this.bucketName,
Prefix: prefix,
MaxKeys: batchSize,
ContinuationToken: continuationToken
})
)
if (!listResponse.Contents || listResponse.Contents.length === 0) {
break
}
// Prepare batch delete request
const objectsToDelete = listResponse.Contents
.filter((obj: any) => obj.Key)
.map((obj: any) => ({ Key: obj.Key! }))
if (objectsToDelete.length > 0) {
// Perform batch delete
const deleteResponse = await this.s3Client.send(
new DeleteObjectsCommand({
Bucket: this.bucketName,
Delete: {
Objects: objectsToDelete,
Quiet: false // Get detailed response
}
})
)
const deletedCount = deleteResponse.Deleted?.length || 0
totalDeleted += deletedCount
// Report any errors
if (deleteResponse.Errors && deleteResponse.Errors.length > 0) {
for (const error of deleteResponse.Errors) {
console.warn(`Failed to delete ${error.Key}: ${error.Message}`)
}
}
// Report progress
onProgress?.({
totalItems: totalDeleted + (listResponse.IsTruncated ? 1000 : 0), // Estimate
processedItems: totalDeleted,
errors: deleteResponse.Errors?.length || 0
})
}
continuationToken = listResponse.NextContinuationToken
// Small delay to respect AWS rate limits
await new Promise(resolve => setTimeout(resolve, 10))
} while (continuationToken)
return totalDeleted
}
private async getBucketInfo(): Promise<{ instanceName: string }> {
// Each Brainy instance has its own bucket with the same name as the instance
// The bucket name IS the instance name
return { instanceName: this.bucketName }
}
private async performDryRun(options: ClearOptions): Promise<ClearResult> {
const startTime = Date.now()
const { ListObjectsV2Command } = await import('@aws-sdk/client-s3')
const result: ClearResult = {
success: true,
itemsDeleted: { nouns: 0, verbs: 0, metadata: 0, system: 0 },
duration: 0,
errors: []
}
const countObjects = async (prefix: string): Promise<number> => {
let count = 0
let continuationToken: string | undefined
do {
const response = await this.s3Client.send(
new ListObjectsV2Command({
Bucket: this.bucketName,
Prefix: prefix,
MaxKeys: 1000,
ContinuationToken: continuationToken
})
)
count += response.KeyCount || 0
continuationToken = response.NextContinuationToken
} while (continuationToken)
return count
}
result.itemsDeleted.nouns = await countObjects('nouns/')
result.itemsDeleted.verbs = await countObjects('verbs/')
result.itemsDeleted.metadata =
await countObjects('metadata/') +
await countObjects('noun-metadata/') +
await countObjects('verb-metadata/')
result.itemsDeleted.system =
await countObjects('system/') +
await countObjects('index/')
result.duration = Date.now() - startTime
return result
}
}

View file

@ -18,7 +18,6 @@
import type { StorageAdapter } from '../coreTypes.js'
import { MemoryStorage } from './adapters/memoryStorage.js'
import { isBrowser } from '../utils/environment.js'
import type { OperationConfig } from '../utils/operationUtils.js'
/**
@ -80,11 +79,10 @@ function configureCOW(storage: any, options?: StorageOptions): void {
/**
* Resolve `StorageOptions` to a concrete storage adapter.
*
* - `'auto'` (default) picks `FileSystemStorage` when the runtime exposes
* the Node `fs` API, otherwise falls back to `MemoryStorage`.
* - `'auto'` (default) picks `FileSystemStorage`, falling back to
* `MemoryStorage` only if filesystem init fails (e.g. no write permission).
* - `forceMemoryStorage: true` returns `MemoryStorage` regardless.
* - `forceFileSystemStorage: true` returns `FileSystemStorage` and throws in
* the browser.
* - `forceFileSystemStorage: true` returns `FileSystemStorage`.
*/
export async function createStorage(options: StorageOptions = {}): Promise<StorageAdapter> {
const storage = await pickAdapter(options)
@ -104,27 +102,15 @@ async function pickAdapter(options: StorageOptions): Promise<StorageAdapter> {
}
if (requestedType === 'filesystem' || options.forceFileSystemStorage) {
if (isBrowser()) {
throw new Error(
"Brainy: 'filesystem' storage is not available in browser environments. " +
"Use `type: 'memory'` for in-browser brains, or run on a Node-like runtime."
)
}
return await createFilesystemStorage(options)
}
// 'auto': filesystem if we have Node-like fs, otherwise memory.
if (!isBrowser()) {
try {
return await createFilesystemStorage(options)
} catch (err) {
// Fall back to memory if filesystem init fails for any reason
// (e.g. no write permission on rootDirectory).
return new MemoryStorage()
}
// 'auto': prefer filesystem, fall back to memory if init fails.
try {
return await createFilesystemStorage(options)
} catch {
return new MemoryStorage()
}
return new MemoryStorage()
}
async function createFilesystemStorage(options: StorageOptions): Promise<StorageAdapter> {