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:
parent
adda1570f3
commit
266715aeee
22 changed files with 134 additions and 4648 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue