chore(8.0): collapse dead defensive guards + redundant polyfills
Follow-up to the browser/cloud/threading sweep — everything that was guarding
against unreachable runtimes is now dead.
cacheManager.ts: Environment enum + this.environment field removed (only NODE
was reachable). StorageType narrowed to MEMORY + FILESYSTEM. navigator.deviceMemory
and performance.memory paths in detectOptimalCacheSize + detectAvailableMemory
deleted; node:os is the sole source. environmentConfig keeps the index signature
for future per-runtime tuning but only the node slot is wired.
Dead 'typeof window === undefined' guards (the check is always true on 8.0):
paramValidation, structuredLogger, mutex, brainy.ts stats block, and
networkTransport ws-dynamic-import all collapsed. IntegrationLoader's inverse
guard ('!== undefined' returning 'browser') deleted. mutex's createMutex default
type simplified from "(typeof window === 'undefined' ? 'file' : 'memory')" to
plain 'file'.
Redundant TextEncoder/TextDecoder polyfills: Node 22+ ships both as globals.
src/utils/textEncoding.ts deleted (applyTensorFlowPatch was named for a defunct
dep and only re-assigned globals already present). setup.ts collapsed to an
empty stable import target. unified.ts loses its applyTensorFlowPatch re-export.
modelAutoConfig.getModelPath() loses the unreachable trailing fallback now
that isNode() is effectively the only branch the function ever takes.
jsonProcessing.ts left unchanged — its 'typeof document' checks are value-shape
guards on the parsed JSON, not environment detection.
This commit is contained in:
parent
266715aeee
commit
42159f2bd7
11 changed files with 121 additions and 397 deletions
|
|
@ -5231,7 +5231,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
// Get system memory info
|
// Get system memory info
|
||||||
let freeMemory = 0
|
let freeMemory = 0
|
||||||
let totalMemory = 0
|
let totalMemory = 0
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
try {
|
try {
|
||||||
const os = require('node:os')
|
const os = require('node:os')
|
||||||
freeMemory = os.freemem()
|
freeMemory = os.freemem()
|
||||||
|
|
@ -5239,7 +5238,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// OS module not available
|
// OS module not available
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const stats = {
|
const stats = {
|
||||||
memory: {
|
memory: {
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,7 @@ export function getModelPath(): string {
|
||||||
return '/tmp/.brainy/models'
|
return '/tmp/.brainy/models'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node.js - use home directory for persistent storage
|
// Node-like runtime - use home directory for persistent storage
|
||||||
if (isNode()) {
|
|
||||||
const homeDir = process.env.HOME || process.env.USERPROFILE || '~'
|
const homeDir = process.env.HOME || process.env.USERPROFILE || '~'
|
||||||
return `${homeDir}/.brainy/models`
|
return `${homeDir}/.brainy/models`
|
||||||
}
|
|
||||||
|
|
||||||
return './.brainy/models'
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,8 @@ export class NetworkTransport extends EventEmitter {
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
if (this.isRunning) return
|
if (this.isRunning) return
|
||||||
|
|
||||||
// Dynamic import for Node.js environment
|
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
const ws = await import('ws')
|
const ws = await import('ws')
|
||||||
WebSocketServer = (ws as any).WebSocketServer || (ws as any).Server || ws.default
|
WebSocketServer = (ws as any).WebSocketServer || (ws as any).Server || ws.default
|
||||||
}
|
|
||||||
|
|
||||||
await this.startHTTPServer()
|
await this.startHTTPServer()
|
||||||
await this.startWebSocketServer()
|
await this.startWebSocketServer()
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,6 @@ export function detectEnvironment(): RuntimeEnvironment {
|
||||||
return 'node'
|
return 'node'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browser
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
return 'browser'
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'node'
|
return 'node'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
33
src/setup.ts
33
src/setup.ts
|
|
@ -1,31 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* Brainy Setup - Minimal Polyfills
|
* Brainy Setup
|
||||||
*
|
*
|
||||||
* ARCHITECTURE:
|
* ARCHITECTURE:
|
||||||
* Brainy uses Candle WASM (Rust-based) for embeddings.
|
* Brainy 8.0 runs only on Node-like runtimes (Node.js 22+, Bun, Deno). All
|
||||||
* No transformers.js or ONNX Runtime dependency, no hacks required.
|
* supported runtimes ship `TextEncoder` and `TextDecoder` as global built-ins,
|
||||||
|
* so no polyfills are required.
|
||||||
*
|
*
|
||||||
* This file provides minimal polyfills for cross-environment compatibility:
|
* This module is intentionally side-effect-only and currently empty. It is kept
|
||||||
* - TextEncoder/TextDecoder for older environments
|
* as a stable import target in case future runtime initialization is needed.
|
||||||
*
|
|
||||||
* BENEFITS:
|
|
||||||
* - Clean codebase with no workarounds
|
|
||||||
* - Works everywhere: Node.js, Bun, Bun --compile, browsers, Deno
|
|
||||||
* - No platform-specific binaries
|
|
||||||
* - Model bundled in package (no runtime downloads)
|
|
||||||
*/
|
*/
|
||||||
|
export {}
|
||||||
// ============================================================================
|
|
||||||
// TextEncoder/TextDecoder Polyfills
|
|
||||||
// ============================================================================
|
|
||||||
const globalObj = globalThis ?? global ?? self
|
|
||||||
|
|
||||||
if (globalObj) {
|
|
||||||
if (!globalObj.TextEncoder) globalObj.TextEncoder = TextEncoder
|
|
||||||
if (!globalObj.TextDecoder) globalObj.TextDecoder = TextDecoder
|
|
||||||
;(globalObj as any).__TextEncoder__ = TextEncoder
|
|
||||||
;(globalObj as any).__TextDecoder__ = TextDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
import { applyTensorFlowPatch } from './utils/textEncoding.js'
|
|
||||||
applyTensorFlowPatch()
|
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,6 @@
|
||||||
import { HNSWNoun, GraphVerb, HNSWVerb } from '../coreTypes.js'
|
import { HNSWNoun, GraphVerb, HNSWVerb } from '../coreTypes.js'
|
||||||
import { BrainyError } from '../errors/brainyError.js'
|
import { BrainyError } from '../errors/brainyError.js'
|
||||||
|
|
||||||
// Extend Navigator interface to include deviceMemory property
|
|
||||||
// and WorkerGlobalScope to include storage property
|
|
||||||
declare global {
|
|
||||||
interface Navigator {
|
|
||||||
deviceMemory?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WorkerGlobalScope {
|
|
||||||
storage?: {
|
|
||||||
getDirectory?: () => Promise<any>;
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type aliases for better readability
|
// Type aliases for better readability
|
||||||
type HNSWNode = HNSWNoun
|
type HNSWNode = HNSWNoun
|
||||||
type Edge = GraphVerb
|
type Edge = GraphVerb
|
||||||
|
|
@ -52,20 +37,11 @@ interface CacheStats {
|
||||||
warmCacheMisses: number
|
warmCacheMisses: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// Environment detection for storage selection
|
// Storage type for warm and cold caches. Brainy 8.0 only ships filesystem +
|
||||||
enum Environment {
|
// memory tiers, but the enum is retained for diagnostic/log output.
|
||||||
BROWSER,
|
|
||||||
NODE,
|
|
||||||
WORKER
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage type for warm and cold caches
|
|
||||||
enum StorageType {
|
enum StorageType {
|
||||||
MEMORY,
|
MEMORY,
|
||||||
OPFS,
|
FILESYSTEM
|
||||||
FILESYSTEM,
|
|
||||||
S3,
|
|
||||||
REMOTE_API
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -90,8 +66,7 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
warmCacheMisses: 0
|
warmCacheMisses: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Environment and storage configuration
|
// Storage configuration
|
||||||
private environment: Environment
|
|
||||||
private warmStorageType: StorageType
|
private warmStorageType: StorageType
|
||||||
private coldStorageType: StorageType
|
private coldStorageType: StorageType
|
||||||
|
|
||||||
|
|
@ -127,19 +102,7 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
hotCacheEvictionThreshold?: number
|
hotCacheEvictionThreshold?: number
|
||||||
warmCacheTTL?: number
|
warmCacheTTL?: number
|
||||||
batchSize?: number
|
batchSize?: number
|
||||||
},
|
}
|
||||||
browser?: {
|
|
||||||
hotCacheMaxSize?: number
|
|
||||||
hotCacheEvictionThreshold?: number
|
|
||||||
warmCacheTTL?: number
|
|
||||||
batchSize?: number
|
|
||||||
},
|
|
||||||
worker?: {
|
|
||||||
hotCacheMaxSize?: number
|
|
||||||
hotCacheEvictionThreshold?: number
|
|
||||||
warmCacheTTL?: number
|
|
||||||
batchSize?: number
|
|
||||||
},
|
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
hotCacheMaxSize?: number
|
hotCacheMaxSize?: number
|
||||||
hotCacheEvictionThreshold?: number
|
hotCacheEvictionThreshold?: number
|
||||||
|
|
@ -168,19 +131,7 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
hotCacheEvictionThreshold?: number
|
hotCacheEvictionThreshold?: number
|
||||||
warmCacheTTL?: number
|
warmCacheTTL?: number
|
||||||
batchSize?: number
|
batchSize?: number
|
||||||
},
|
}
|
||||||
browser?: {
|
|
||||||
hotCacheMaxSize?: number
|
|
||||||
hotCacheEvictionThreshold?: number
|
|
||||||
warmCacheTTL?: number
|
|
||||||
batchSize?: number
|
|
||||||
},
|
|
||||||
worker?: {
|
|
||||||
hotCacheMaxSize?: number
|
|
||||||
hotCacheEvictionThreshold?: number
|
|
||||||
warmCacheTTL?: number
|
|
||||||
batchSize?: number
|
|
||||||
},
|
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
hotCacheMaxSize?: number
|
hotCacheMaxSize?: number
|
||||||
hotCacheEvictionThreshold?: number
|
hotCacheEvictionThreshold?: number
|
||||||
|
|
@ -192,10 +143,7 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
// Store options for later reference
|
// Store options for later reference
|
||||||
this.options = options
|
this.options = options
|
||||||
|
|
||||||
// Detect environment
|
// Set storage types (Brainy 8.0 ships filesystem only)
|
||||||
this.environment = this.detectEnvironment()
|
|
||||||
|
|
||||||
// Set storage types based on environment
|
|
||||||
this.warmStorageType = this.detectWarmStorageType()
|
this.warmStorageType = this.detectWarmStorageType()
|
||||||
this.coldStorageType = this.detectColdStorageType()
|
this.coldStorageType = this.detectColdStorageType()
|
||||||
|
|
||||||
|
|
@ -206,8 +154,9 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
// Set auto-tuning flag
|
// Set auto-tuning flag
|
||||||
this.autoTune = options.autoTune !== undefined ? options.autoTune : true
|
this.autoTune = options.autoTune !== undefined ? options.autoTune : true
|
||||||
|
|
||||||
// Get environment-specific configuration if available
|
// Brainy 8.0 only runs on Node-like runtimes, so only the `node` slot of
|
||||||
const envConfig = options.environmentConfig?.[Environment[this.environment].toLowerCase()]
|
// environmentConfig is honored.
|
||||||
|
const envConfig = options.environmentConfig?.node
|
||||||
|
|
||||||
// Set default values or use environment-specific values or global values
|
// Set default values or use environment-specific values or global values
|
||||||
this.hotCacheMaxSize = envConfig?.hotCacheMaxSize || options.hotCacheMaxSize || this.detectOptimalCacheSize()
|
this.hotCacheMaxSize = envConfig?.hotCacheMaxSize || options.hotCacheMaxSize || this.detectOptimalCacheSize()
|
||||||
|
|
@ -223,7 +172,7 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
// Log configuration
|
// Log configuration
|
||||||
if (process.env.DEBUG) {
|
if (process.env.DEBUG) {
|
||||||
console.log('Cache Manager initialized with configuration:', {
|
console.log('Cache Manager initialized with configuration:', {
|
||||||
environment: Environment[this.environment],
|
environment: 'node',
|
||||||
hotCacheMaxSize: this.hotCacheMaxSize,
|
hotCacheMaxSize: this.hotCacheMaxSize,
|
||||||
hotCacheEvictionThreshold: this.hotCacheEvictionThreshold,
|
hotCacheEvictionThreshold: this.hotCacheEvictionThreshold,
|
||||||
warmCacheTTL: this.warmCacheTTL,
|
warmCacheTTL: this.warmCacheTTL,
|
||||||
|
|
@ -235,19 +184,6 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect the current environment
|
|
||||||
*/
|
|
||||||
private detectEnvironment(): Environment {
|
|
||||||
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
||||||
return Environment.BROWSER
|
|
||||||
} else if (typeof self !== 'undefined' && typeof window === 'undefined') {
|
|
||||||
// In a worker environment, self is defined but window is not
|
|
||||||
return Environment.WORKER
|
|
||||||
} else {
|
|
||||||
return Environment.NODE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect the optimal cache size based on available memory and operating mode
|
* Detect the optimal cache size based on available memory and operating mode
|
||||||
|
|
@ -273,15 +209,10 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
// Check if we're in read-only mode (from parent Brainy instance)
|
// Check if we're in read-only mode (from parent Brainy instance)
|
||||||
const isReadOnly = this.options?.readOnly || false
|
const isReadOnly = this.options?.readOnly || false
|
||||||
|
|
||||||
// In Node.js, use available system memory with enhanced allocation
|
|
||||||
if (this.environment === Environment.NODE) {
|
|
||||||
try {
|
try {
|
||||||
// For ES module compatibility, we'll use a fixed default value
|
// Synchronous path can't use dynamic imports, so we use conservative
|
||||||
// since we can't use dynamic imports in a synchronous function
|
// assumed defaults. The async variant (detectAvailableMemory) reads
|
||||||
|
// real values via `node:os` when possible.
|
||||||
// Use conservative defaults that don't require OS module
|
|
||||||
// These values are reasonable for most systems
|
|
||||||
const estimatedTotalMemory = 8 * 1024 * 1024 * 1024 // Assume 8GB total
|
|
||||||
const estimatedFreeMemory = 4 * 1024 * 1024 * 1024 // Assume 4GB free
|
const estimatedFreeMemory = 4 * 1024 * 1024 * 1024 // Assume 4GB free
|
||||||
|
|
||||||
// Estimate average entry size (in bytes)
|
// Estimate average entry size (in bytes)
|
||||||
|
|
@ -326,47 +257,6 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
console.warn('Failed to detect optimal cache size:', error)
|
console.warn('Failed to detect optimal cache size:', error)
|
||||||
return defaultSize
|
return defaultSize
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// In browser, use navigator.deviceMemory with enhanced allocation
|
|
||||||
if (this.environment === Environment.BROWSER && navigator.deviceMemory) {
|
|
||||||
// Base entries per GB
|
|
||||||
let entriesPerGB = 500
|
|
||||||
|
|
||||||
// Adjust based on operating mode and dataset size
|
|
||||||
if (isReadOnly) {
|
|
||||||
entriesPerGB = 800 // More aggressive caching in read-only mode
|
|
||||||
|
|
||||||
if (isLargeDataset) {
|
|
||||||
entriesPerGB = 1000 // Even more aggressive for large datasets
|
|
||||||
}
|
|
||||||
} else if (isLargeDataset) {
|
|
||||||
entriesPerGB = 600 // Slightly more aggressive for large datasets
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate based on device memory
|
|
||||||
const browserCacheSize = Math.max(navigator.deviceMemory * entriesPerGB, 1000)
|
|
||||||
|
|
||||||
// If we know the total dataset size, cap at a reasonable percentage
|
|
||||||
if (totalItems > 0) {
|
|
||||||
// In read-only mode, we can cache a larger percentage
|
|
||||||
const maxPercentage = isReadOnly ? 0.4 : 0.25
|
|
||||||
const maxItems = Math.ceil(totalItems * maxPercentage)
|
|
||||||
|
|
||||||
// Return the smaller of the two to avoid excessive memory usage
|
|
||||||
return Math.min(browserCacheSize, maxItems)
|
|
||||||
}
|
|
||||||
|
|
||||||
return browserCacheSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// For worker environments or when memory detection fails
|
|
||||||
if (this.environment === Environment.WORKER) {
|
|
||||||
// Workers typically have limited memory, be conservative
|
|
||||||
return isReadOnly ? 2000 : 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultSize
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Error detecting optimal cache size:', error)
|
console.warn('Error detecting optimal cache size:', error)
|
||||||
return 1000 // Conservative default
|
return 1000 // Conservative default
|
||||||
|
|
@ -448,19 +338,17 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detects available memory across different environments
|
* Detect available memory using Node-like runtime primitives.
|
||||||
*
|
*
|
||||||
* This method uses different techniques to detect memory in:
|
* Brainy 8.0 only runs on Node.js, Bun, and Deno, so this method reads real
|
||||||
* - Node.js: Uses the OS module with dynamic import
|
* values from `node:os` (`process.memoryUsage()` is not used here because we
|
||||||
* - Browser: Uses performance.memory or navigator.deviceMemory
|
* want system-wide free memory, not just the V8 heap). If the import fails,
|
||||||
* - Worker: Uses performance.memory if available
|
* we fall back to conservative defaults that match the synchronous path.
|
||||||
*
|
*
|
||||||
* @returns An object with totalMemory and freeMemory in bytes, or null if detection fails
|
* @returns An object with totalMemory and freeMemory in bytes, or null if detection fails
|
||||||
*/
|
*/
|
||||||
private async detectAvailableMemory(): Promise<{ totalMemory: number, freeMemory: number } | null> {
|
private async detectAvailableMemory(): Promise<{ totalMemory: number, freeMemory: number } | null> {
|
||||||
try {
|
try {
|
||||||
// Node.js environment
|
|
||||||
if (this.environment === Environment.NODE) {
|
|
||||||
try {
|
try {
|
||||||
// Use dynamic import for OS module
|
// Use dynamic import for OS module
|
||||||
const os = await import('node:os')
|
const os = await import('node:os')
|
||||||
|
|
@ -471,59 +359,10 @@ export class CacheManager<T extends HNSWNode | Edge | HNSWVerb> {
|
||||||
|
|
||||||
return { totalMemory, freeMemory }
|
return { totalMemory, freeMemory }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Failed to detect memory in Node.js environment:', error)
|
console.warn('Failed to detect memory via node:os:', error)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browser environment
|
// If detection failed, use conservative defaults
|
||||||
if (this.environment === Environment.BROWSER) {
|
|
||||||
// Try using performance.memory (Chrome only)
|
|
||||||
if (performance && (performance as any).memory) {
|
|
||||||
const memoryInfo = (performance as any).memory
|
|
||||||
|
|
||||||
// jsHeapSizeLimit is the maximum size of the heap
|
|
||||||
// totalJSHeapSize is the currently allocated heap size
|
|
||||||
// usedJSHeapSize is the amount of heap currently being used
|
|
||||||
const totalMemory = memoryInfo.jsHeapSizeLimit || 0
|
|
||||||
const usedMemory = memoryInfo.usedJSHeapSize || 0
|
|
||||||
const freeMemory = Math.max(totalMemory - usedMemory, 0)
|
|
||||||
|
|
||||||
return { totalMemory, freeMemory }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try using navigator.deviceMemory as fallback
|
|
||||||
if (navigator.deviceMemory) {
|
|
||||||
// deviceMemory is in GB, convert to bytes
|
|
||||||
const totalMemory = navigator.deviceMemory * 1024 * 1024 * 1024
|
|
||||||
// Assume 50% is free
|
|
||||||
const freeMemory = totalMemory * 0.5
|
|
||||||
|
|
||||||
return { totalMemory, freeMemory }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Worker environment
|
|
||||||
if (this.environment === Environment.WORKER) {
|
|
||||||
// Try using performance.memory if available (Chrome workers)
|
|
||||||
if (performance && (performance as any).memory) {
|
|
||||||
const memoryInfo = (performance as any).memory
|
|
||||||
|
|
||||||
const totalMemory = memoryInfo.jsHeapSizeLimit || 0
|
|
||||||
const usedMemory = memoryInfo.usedJSHeapSize || 0
|
|
||||||
const freeMemory = Math.max(totalMemory - usedMemory, 0)
|
|
||||||
|
|
||||||
return { totalMemory, freeMemory }
|
|
||||||
}
|
|
||||||
|
|
||||||
// For workers, use a conservative estimate
|
|
||||||
// Assume 2GB total memory with 1GB free
|
|
||||||
return {
|
|
||||||
totalMemory: 2 * 1024 * 1024 * 1024,
|
|
||||||
freeMemory: 1 * 1024 * 1024 * 1024
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all detection methods fail, use conservative defaults
|
|
||||||
return {
|
return {
|
||||||
totalMemory: 8 * 1024 * 1024 * 1024, // Assume 8GB total
|
totalMemory: 8 * 1024 * 1024 * 1024, // Assume 8GB total
|
||||||
freeMemory: 4 * 1024 * 1024 * 1024 // Assume 4GB free
|
freeMemory: 4 * 1024 * 1024 * 1024 // Assume 4GB free
|
||||||
|
|
|
||||||
|
|
@ -27,4 +27,3 @@ console.log(
|
||||||
)
|
)
|
||||||
|
|
||||||
export * from './index.js'
|
export * from './index.js'
|
||||||
export { applyTensorFlowPatch } from './utils/textEncoding.js'
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,6 @@ export class FileMutex implements MutexInterface {
|
||||||
private async loadNodeModules(): Promise<void> {
|
private async loadNodeModules(): Promise<void> {
|
||||||
if (this.modulesLoaded) return
|
if (this.modulesLoaded) return
|
||||||
|
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
// Modern ESM-compatible dynamic imports
|
// Modern ESM-compatible dynamic imports
|
||||||
const [fs, path] = await Promise.all([
|
const [fs, path] = await Promise.all([
|
||||||
import('fs'),
|
import('fs'),
|
||||||
|
|
@ -115,7 +114,6 @@ export class FileMutex implements MutexInterface {
|
||||||
this.path = path
|
this.path = path
|
||||||
this.modulesLoaded = true
|
this.modulesLoaded = true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async acquire(key: string, timeout: number = 30000): Promise<() => void> {
|
async acquire(key: string, timeout: number = 30000): Promise<() => void> {
|
||||||
await this.loadNodeModules()
|
await this.loadNodeModules()
|
||||||
|
|
@ -255,9 +253,9 @@ export function createMutex(options?: {
|
||||||
type?: 'memory' | 'file'
|
type?: 'memory' | 'file'
|
||||||
lockDir?: string
|
lockDir?: string
|
||||||
}): MutexInterface {
|
}): MutexInterface {
|
||||||
const type = options?.type || (typeof window === 'undefined' ? 'file' : 'memory')
|
const type = options?.type || 'file'
|
||||||
|
|
||||||
if (type === 'file' && typeof window === 'undefined') {
|
if (type === 'file') {
|
||||||
const lockDir = options?.lockDir || '.brainy/locks'
|
const lockDir = options?.lockDir || '.brainy/locks'
|
||||||
return new FileMutex(lockDir)
|
return new FileMutex(lockDir)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,21 +13,17 @@ import { findCallerLocation } from './callerLocation.js'
|
||||||
// Dynamic import for Node.js os and fs modules
|
// Dynamic import for Node.js os and fs modules
|
||||||
let os: any = null
|
let os: any = null
|
||||||
let fs: any = null
|
let fs: any = null
|
||||||
if (typeof window === 'undefined') {
|
try {
|
||||||
try {
|
|
||||||
os = await import('node:os')
|
os = await import('node:os')
|
||||||
fs = await import('node:fs')
|
fs = await import('node:fs')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// OS/FS modules not available
|
// OS/FS modules not available
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browser-safe memory detection
|
|
||||||
const getSystemMemory = (): number => {
|
const getSystemMemory = (): number => {
|
||||||
if (os) {
|
if (os) {
|
||||||
return os.totalmem()
|
return os.totalmem()
|
||||||
}
|
}
|
||||||
// Browser fallback: assume 4GB
|
|
||||||
return 4 * 1024 * 1024 * 1024
|
return 4 * 1024 * 1024 * 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,7 +31,6 @@ const getAvailableMemory = (): number => {
|
||||||
if (os) {
|
if (os) {
|
||||||
return os.freemem()
|
return os.freemem()
|
||||||
}
|
}
|
||||||
// Browser fallback: assume 2GB available
|
|
||||||
return 2 * 1024 * 1024 * 1024
|
return 2 * 1024 * 1024 * 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -311,17 +311,12 @@ export class StructuredLogger {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.includeHost) {
|
if (this.config.includeHost) {
|
||||||
// Use dynamic import for hostname (Node.js only)
|
|
||||||
if (typeof window === 'undefined') {
|
|
||||||
try {
|
try {
|
||||||
const os = require('node:os')
|
const os = require('node:os')
|
||||||
entry.host = os.hostname()
|
entry.host = os.hostname()
|
||||||
} catch {
|
} catch {
|
||||||
entry.host = 'unknown'
|
entry.host = 'unknown'
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
entry.host = window.location?.hostname || 'browser'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.config.includeMemory && typeof process !== 'undefined' && process.memoryUsage) {
|
if (this.config.includeMemory && typeof process !== 'undefined' && process.memoryUsage) {
|
||||||
|
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import { isNode } from './environment.js'
|
|
||||||
|
|
||||||
// Simplified TextEncoder/TextDecoder utilities for Node.js compatibility
|
|
||||||
// No longer needs complex TensorFlow.js patches - only basic TextEncoder/TextDecoder
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag to track if the patch has been applied
|
|
||||||
*/
|
|
||||||
let patchApplied = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply TextEncoder/TextDecoder patches for Node.js compatibility
|
|
||||||
* Simplified version for Transformers.js/ONNX Runtime
|
|
||||||
*/
|
|
||||||
export async function applyTensorFlowPatch(): Promise<void> {
|
|
||||||
if (patchApplied || !isNode()) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.log('Brainy: Applying TextEncoder/TextDecoder patch for Node.js')
|
|
||||||
|
|
||||||
// Get the appropriate global object
|
|
||||||
const globalObj = (() => {
|
|
||||||
if (typeof globalThis !== 'undefined') return globalThis
|
|
||||||
if (typeof global !== 'undefined') return global
|
|
||||||
throw new Error(
|
|
||||||
'Cannot apply TextEncoder/TextDecoder patches: No global object found. ' +
|
|
||||||
'This environment does not have globalThis or global defined.'
|
|
||||||
)
|
|
||||||
})()
|
|
||||||
|
|
||||||
// Make sure TextEncoder and TextDecoder are available globally
|
|
||||||
if (!globalObj.TextEncoder) {
|
|
||||||
globalObj.TextEncoder = TextEncoder
|
|
||||||
}
|
|
||||||
if (!globalObj.TextDecoder) {
|
|
||||||
globalObj.TextDecoder = TextDecoder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also set them on the global object for older code
|
|
||||||
if (typeof global !== 'undefined') {
|
|
||||||
if (!global.TextEncoder) {
|
|
||||||
global.TextEncoder = TextEncoder
|
|
||||||
}
|
|
||||||
if (!global.TextDecoder) {
|
|
||||||
global.TextDecoder = TextDecoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
patchApplied = true
|
|
||||||
console.log('Brainy: TextEncoder/TextDecoder patches applied successfully')
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Brainy: Failed to apply TextEncoder/TextDecoder patch:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTextEncoder(): TextEncoder {
|
|
||||||
return new TextEncoder()
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTextDecoder(): TextDecoder {
|
|
||||||
return new TextDecoder()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply patch immediately if in Node.js
|
|
||||||
if (isNode()) {
|
|
||||||
applyTensorFlowPatch().catch((error) => {
|
|
||||||
console.warn('Failed to apply TextEncoder/TextDecoder patch at module load:', error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue