refactor(8.0)!: remove orphaned zero-config subsystem + dead cloud/progressive-init storage vestige

The old config-generation subsystem (src/config/ + autoConfiguration.ts) was
superseded during the 8.0 rework and never wired into init(): it emitted settings
for a partitioning subsystem that no longer exists and probed deleted cloud env
vars. The live zero-config path is inline — recall preset → HNSW knobs, storage
auto-detect, auto persistMode, container-memory-aware cache sizing.

The storage progressive-init / cloud-detection cluster was equally dead after the
cloud adapters were dropped: isCloudStorage() is permanently false (no overriders),
scheduleBackgroundInit/runBackgroundInit were never called (the latter an empty
body), initMode was never assigned, and Brainy.isFullyInitialized()/
awaitBackgroundInit() were always-trivial with zero callers. scheduleCountPersist()
collapses to its only-ever-taken immediate write-through path.

Removed:
- src/config/{index,zeroConfig,storageAutoConfig,modelAutoConfig,sharedConfigManager}.ts
- src/utils/autoConfiguration.ts + the inert BrainyZeroConfig export
- Brainy.isFullyInitialized()/awaitBackgroundInit() (+ BrainyInterface decls)
- InitMode type, isCloudStorage/detectCloudEnvironment/resolveInitMode,
  scheduleBackgroundInit/runBackgroundInit/ensureValidatedForWrite and their state
- Dead cloud env-var probes (K_SERVICE/K_REVISION/AWS_LAMBDA_FUNCTION_NAME/
  FUNCTIONS_TARGET/AZURE_FUNCTIONS_ENVIRONMENT)

Kept (verified live): production-detection logging (environment.ts), container-
memory cache sizing (memoryDetection/paramValidation), on-disk hash bucketing
(sharding.ts).

Docs: scrubbed deleted-subsystem references (JS quantization knobs, cloud/OPFS
adapters, partitioning, old zero-config API) across 14 files; deleted two wholly-
obsolete feature docs (complete-feature-list, v3-features); rewrote
architecture/zero-config for 8.0.

~3,700 LOC removed. Build clean; 1392 unit + 24 db-mvcc green.
This commit is contained in:
David Snelling 2026-06-15 11:11:21 -07:00
parent 00d3203d68
commit 35b9d7ef43
28 changed files with 596 additions and 3752 deletions

View file

@ -2,6 +2,8 @@
Complete guide to integrating Brainy with Vue.js applications, covering Vue 3, Nuxt.js, Composition API, Options API, and advanced patterns.
> **Runtime**: Brainy 8.0 runs on Node.js 22+ and Bun, server-side only — it is not a browser library. In Vue apps, Brainy lives behind an HTTP endpoint (a Nuxt server route, or any Node/Bun backend), and your components call that endpoint. The composables, plugin, and store below are wrappers around `fetch`; the single Brainy instance is created once on the server (see [Nuxt Server Route](#nuxt-server-route)).
## 🚀 Quick Start
### Installation
@ -15,34 +17,47 @@ npm install @soulcraft/brainy
### Basic Setup
The composable talks to a Brainy-backed endpoint (see [Nuxt Server Route](#nuxt-server-route)). It is always "ready" because there is no client-side initialization — the server owns the Brainy instance.
```javascript
// src/composables/useBrainy.js
import { ref, onMounted } from 'vue'
import { Brainy } from '@soulcraft/brainy'
import { ref } from 'vue'
const brain = ref(null)
const isReady = ref(false)
const error = ref(null)
export function useBrainy(endpoint = '/api/brain') {
const error = ref(null)
export function useBrainy() {
onMounted(async () => {
const search = async (query, options = {}) => {
error.value = null
try {
brain.value = new Brainy({
storage: { type: 'opfs' } // Browser storage
const res = await fetch(`${endpoint}/search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, options })
})
await brain.value.init()
isReady.value = true
if (!res.ok) throw new Error(`Search failed: ${res.status}`)
return (await res.json()).results
} catch (err) {
error.value = err.message
console.error('Brainy initialization failed:', err)
console.error('Brainy search failed:', err)
return []
}
})
return {
brain: readonly(brain),
isReady: readonly(isReady),
error: readonly(error)
}
const add = async (data, type, metadata) => {
const res = await fetch(`${endpoint}/add`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data, type, metadata })
})
return (await res.json()).id
}
const stats = async () => {
const res = await fetch(`${endpoint}/stats`)
return await res.json()
}
return { search, add, stats, error: readonly(error) }
}
```
@ -54,43 +69,36 @@ export function useBrainy() {
<!-- src/components/Search.vue -->
<template>
<div class="search-container">
<div v-if="!isReady" class="loading">
<div class="spinner"></div>
<span>Initializing AI...</span>
<div class="search-input">
<input
v-model="query"
@input="handleSearch"
placeholder="Search..."
class="input"
/>
</div>
<div v-else>
<div class="search-input">
<input
v-model="query"
@input="handleSearch"
placeholder="Search with AI..."
class="input"
/>
<div v-if="loading" class="loading">
Searching...
</div>
<div v-else class="results">
<div
v-for="result in results"
:key="result.id"
class="result-item"
>
<h3>{{ result.data }}</h3>
<div class="result-meta">
<span>Score: {{ (result.score * 100).toFixed(1) }}%</span>
<span v-if="result.metadata?.type">
Type: {{ result.metadata.type }}
</span>
</div>
</div>
<div v-if="loading" class="loading">
Searching...
</div>
<div v-else class="results">
<div
v-for="result in results"
:key="result.id"
class="result-item"
>
<h3>{{ result.data }}</h3>
<div class="result-meta">
<span>Score: {{ (result.score * 100).toFixed(1) }}%</span>
<span v-if="result.metadata?.type">
Type: {{ result.metadata.type }}
</span>
</div>
</div>
<div v-if="query && !loading && results.length === 0" class="no-results">
No results found for "{{ query }}"
</div>
<div v-if="query && !loading && results.length === 0" class="no-results">
No results found for "{{ query }}"
</div>
</div>
</div>
@ -101,22 +109,21 @@ import { ref, watch } from 'vue'
import { useBrainy } from '../composables/useBrainy'
import { debounce } from '../utils/debounce'
const { brain, isReady } = useBrainy()
const { search: searchBrain } = useBrainy()
const query = ref('')
const results = ref([])
const loading = ref(false)
const search = async (searchQuery) => {
if (!isReady.value || !searchQuery.trim()) {
if (!searchQuery.trim()) {
results.value = []
return
}
loading.value = true
try {
const searchResults = await brain.value.find(searchQuery)
results.value = searchResults
results.value = await searchBrain(searchQuery)
} catch (error) {
console.error('Search error:', error)
results.value = []
@ -228,11 +235,7 @@ watch(query, (newQuery) => {
<div class="data-manager">
<h2>Data Management</h2>
<div v-if="!isReady" class="loading">
Initializing...
</div>
<div v-else>
<div>
<!-- Add Data Form -->
<form @submit.prevent="addData" class="add-form">
<h3>Add New Data</h3>
@ -289,7 +292,7 @@ watch(query, (newQuery) => {
import { ref, reactive, onMounted } from 'vue'
import { useBrainy } from '../composables/useBrainy'
const { brain, isReady } = useBrainy()
const { add, stats: fetchStats } = useBrainy()
const newItem = reactive({
data: '',
@ -299,18 +302,7 @@ const newItem = reactive({
const stats = ref(null)
onMounted(async () => {
if (isReady.value) {
await loadStats()
}
})
// Watch for brain readiness
watch(isReady, async (ready) => {
if (ready) {
await loadStats()
}
})
onMounted(loadStats)
const addData = async () => {
try {
@ -319,11 +311,7 @@ const addData = async () => {
tags: newItem.tags.split(',').map(tag => tag.trim()).filter(Boolean)
}
await brain.value.add({
data: newItem.data,
type: newItem.type,
metadata
})
await add(newItem.data, newItem.type, metadata)
// Reset form
newItem.data = ''
@ -339,7 +327,7 @@ const addData = async () => {
const loadStats = async () => {
try {
stats.value = await brain.value.stats()
stats.value = await fetchStats()
} catch (error) {
console.error('Failed to load stats:', error)
}
@ -435,73 +423,55 @@ button:disabled {
<!-- src/components/SearchOptions.vue -->
<template>
<div class="search-container">
<div v-if="!isReady" class="loading">
Initializing AI...
</div>
<input
v-model="query"
@input="handleSearch"
placeholder="Search..."
class="search-input"
/>
<div v-else>
<input
v-model="query"
@input="handleSearch"
placeholder="Search..."
class="search-input"
/>
<div v-if="loading" class="loading">Searching...</div>
<div v-if="loading" class="loading">Searching...</div>
<div class="results">
<div
v-for="result in results"
:key="result.id"
class="result-item"
>
<h3>{{ result.data }}</h3>
<p>Score: {{ (result.score * 100).toFixed(1) }}%</p>
</div>
<div class="results">
<div
v-for="result in results"
:key="result.id"
class="result-item"
>
<h3>{{ result.data }}</h3>
<p>Score: {{ (result.score * 100).toFixed(1) }}%</p>
</div>
</div>
</div>
</template>
<script>
import { Brainy } from '@soulcraft/brainy'
import { debounce } from '../utils/debounce'
export default {
name: 'SearchOptions',
data() {
return {
brain: null,
isReady: false,
query: '',
results: [],
loading: false
}
},
async mounted() {
await this.initBrain()
},
methods: {
async initBrain() {
try {
this.brain = new Brainy({
storage: { type: 'opfs' }
})
await this.brain.init()
this.isReady = true
} catch (error) {
console.error('Brain initialization failed:', error)
}
},
async search(query) {
if (!this.isReady || !query.trim()) {
if (!query.trim()) {
this.results = []
return
}
this.loading = true
try {
this.results = await this.brain.find(query)
const res = await fetch('/api/brain/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query })
})
this.results = (await res.json()).results
} catch (error) {
console.error('Search error:', error)
this.results = []
@ -520,10 +490,6 @@ export default {
this.loading = false
}
}
},
beforeUnmount() {
// Cleanup if needed
this.brain = null
}
}
</script>
@ -533,31 +499,22 @@ export default {
### Global Brainy Plugin
The plugin exposes a global `$searchBrain` helper that calls your Brainy-backed endpoint. Brainy itself runs on the server (see [Nuxt Server Route](#nuxt-server-route)).
```javascript
// src/plugins/brainy.js
import { Brainy } from '@soulcraft/brainy'
export default {
install(app, options = {}) {
const defaultOptions = {
storage: { type: 'opfs' },
...options
}
const endpoint = options.endpoint ?? '/api/brain'
const brain = new Brainy(defaultOptions)
// Make brain available globally
app.config.globalProperties.$brain = brain
app.provide('brain', brain)
// Auto-initialize
brain.init().catch(error => {
console.error('Brainy plugin initialization failed:', error)
})
// Add global method
app.config.globalProperties.$searchBrain = async (query, options) => {
return await brain.find(query, options)
// Add global search method (calls the server endpoint)
app.config.globalProperties.$searchBrain = async (query, searchOptions) => {
const res = await fetch(`${endpoint}/search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, options: searchOptions })
})
return (await res.json()).results
}
}
}
@ -574,7 +531,7 @@ import BrainyPlugin from './plugins/brainy'
const app = createApp(App)
app.use(BrainyPlugin, {
storage: { type: 'opfs' }
endpoint: '/api/brain'
})
app.mount('#app')
@ -611,24 +568,58 @@ export default {
## 🏰 Nuxt.js Integration
### Nuxt Plugin
Nuxt's server engine (Nitro) is the natural home for Brainy: it runs on Node/Bun, so the Brainy instance lives in `server/`, and pages/components call its routes.
### Nuxt Server Route
```javascript
// plugins/brainy.client.js
// server/utils/brain.js (server-only — Nitro never bundles this into the client)
import { Brainy } from '@soulcraft/brainy'
export default defineNuxtPlugin(async () => {
const brain = new Brainy({
storage: { type: 'opfs' }
})
let brainPromise
await brain.init()
return {
provide: {
brain
}
export function getBrain() {
if (!brainPromise) {
brainPromise = (async () => {
// new Brainy() auto-detects filesystem persistence on Node
const brain = new Brainy()
await brain.init()
return brain
})()
}
return brainPromise
}
```
```javascript
// server/api/brain/search.post.js
import { getBrain } from '../../utils/brain'
export default defineEventHandler(async (event) => {
const { query, options } = await readBody(event)
const brain = await getBrain()
return { results: await brain.find(query, options) }
})
```
```javascript
// server/api/brain/add.post.js
import { getBrain } from '../../utils/brain'
export default defineEventHandler(async (event) => {
const { data, type, metadata } = await readBody(event)
const brain = await getBrain()
return { id: await brain.add({ data, type, metadata }) }
})
```
```javascript
// server/api/brain/stats.get.js
import { getBrain } from '../../utils/brain'
export default defineEventHandler(async () => {
const brain = await getBrain()
return await brain.stats()
})
```
@ -637,26 +628,25 @@ export default defineNuxtPlugin(async () => {
```javascript
// composables/useBrainy.js
export const useBrainy = () => {
const { $brain } = useNuxtApp()
const search = async (query, options = {}) => {
return await $brain.find(query, options)
return (await $fetch('/api/brain/search', {
method: 'POST',
body: { query, options }
})).results
}
const add = async (data, type, metadata) => {
return await $brain.add({ data, type, metadata })
return (await $fetch('/api/brain/add', {
method: 'POST',
body: { data, type, metadata }
})).id
}
const stats = async () => {
return await $brain.stats()
return await $fetch('/api/brain/stats')
}
return {
brain: $brain,
search,
add,
stats
}
return { search, add, stats }
}
```
@ -666,26 +656,20 @@ export const useBrainy = () => {
<!-- pages/search.vue -->
<template>
<div>
<h1>AI Search</h1>
<h1>Search</h1>
<div v-if="pending" class="loading">
Initializing AI...
</div>
<input
v-model="query"
@input="handleSearch"
placeholder="Search..."
/>
<div v-else>
<input
v-model="query"
@input="handleSearch"
placeholder="Search..."
/>
<div v-if="searching" class="loading">Searching...</div>
<div v-if="searching" class="loading">Searching...</div>
<div class="results">
<div v-for="result in results" :key="result.id" class="result">
<h3>{{ result.data }}</h3>
<p>Score: {{ (result.score * 100).toFixed(1) }}%</p>
</div>
<div class="results">
<div v-for="result in results" :key="result.id" class="result">
<h3>{{ result.data }}</h3>
<p>Score: {{ (result.score * 100).toFixed(1) }}%</p>
</div>
</div>
</div>
@ -697,12 +681,6 @@ const { search } = useBrainy()
const query = ref('')
const results = ref([])
const searching = ref(false)
const pending = ref(true)
// Initialize
onMounted(() => {
pending.value = false
})
const handleSearch = debounce(async () => {
if (!query.value.trim()) {
@ -722,82 +700,58 @@ const handleSearch = debounce(async () => {
</script>
```
### Nuxt Configuration
```javascript
// nuxt.config.ts
export default defineNuxtConfig({
ssr: false, // Disable SSR for browser-only features
// Or use client-side hydration
nitro: {
experimental: {
wasm: true
}
},
vite: {
define: {
global: 'globalThis'
}
}
})
```
## 🛠️ Advanced Patterns
### Global State Management with Pinia
The store caches results and stats client-side; all Brainy work happens behind the server endpoints.
```javascript
// stores/brainy.js
import { defineStore } from 'pinia'
import { Brainy } from '@soulcraft/brainy'
export const useBrainyStore = defineStore('brainy', () => {
const brain = ref(null)
const isReady = ref(false)
const error = ref(null)
const stats = ref(null)
const init = async (options = {}) => {
const search = async (query, options = {}) => {
error.value = null
try {
brain.value = new Brainy(options)
await brain.value.init()
isReady.value = true
await loadStats()
const res = await fetch('/api/brain/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, options })
})
return (await res.json()).results
} catch (err) {
error.value = err.message
console.error('Brainy initialization failed:', err)
throw err
}
}
const search = async (query, options = {}) => {
if (!isReady.value) throw new Error('Brain not ready')
return await brain.value.find(query, options)
}
const add = async (data, type, metadata) => {
if (!isReady.value) throw new Error('Brain not ready')
const id = await brain.value.add({ data, type, metadata })
const res = await fetch('/api/brain/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data, type, metadata })
})
const { id } = await res.json()
await loadStats() // Refresh stats
return id
}
const loadStats = async () => {
if (!isReady.value) return
try {
stats.value = await brain.value.stats()
const res = await fetch('/api/brain/stats')
stats.value = await res.json()
} catch (err) {
console.error('Failed to load stats:', err)
}
}
return {
brain: readonly(brain),
isReady: readonly(isReady),
error: readonly(error),
stats: readonly(stats),
init,
search,
add,
loadStats
@ -867,7 +821,7 @@ const showResults = ref(false)
const selectedIndex = ref(-1)
const search = async (searchQuery) => {
if (!brainyStore.isReady || !searchQuery.trim()) {
if (!searchQuery.trim()) {
results.value = []
return
}
@ -1166,21 +1120,23 @@ onMounted(() => {
### Component Testing with Vitest
The component talks to the server over `fetch`, so mock the endpoint, not Brainy itself.
```javascript
// tests/components/Search.test.js
import { mount } from '@vue/test-utils'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import Search from '../src/components/Search.vue'
// Mock Brainy
vi.mock('@soulcraft/brainy', () => ({
Brainy: vi.fn().mockImplementation(() => ({
init: vi.fn().mockResolvedValue(undefined),
find: vi.fn().mockResolvedValue([
{ id: '1', data: 'Test result', score: 0.9 }
])
}))
}))
// Mock the server endpoint
beforeEach(() => {
global.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
results: [{ id: '1', data: 'Test result', score: 0.9 }]
})
})
})
describe('Search Component', () => {
let wrapper
@ -1193,14 +1149,7 @@ describe('Search Component', () => {
expect(wrapper.find('input').exists()).toBe(true)
})
it('shows loading state initially', () => {
expect(wrapper.text()).toContain('Initializing AI')
})
it('performs search when input changes', async () => {
// Wait for brain to initialize
await wrapper.vm.$nextTick()
const input = wrapper.find('input')
await input.setValue('test query')
await input.trigger('input')
@ -1208,6 +1157,7 @@ describe('Search Component', () => {
// Wait for debounced search
await new Promise(resolve => setTimeout(resolve, 350))
expect(global.fetch).toHaveBeenCalled()
expect(wrapper.text()).toContain('Test result')
})
})
@ -1241,6 +1191,8 @@ test('search functionality works', async ({ page }) => {
### Bundle Optimization
Keep Brainy out of the client bundle — it belongs to the server build only. Mark it external for SSR so the bundler resolves it at runtime instead of inlining it.
```javascript
// vite.config.js
import { defineConfig } from 'vite'
@ -1248,63 +1200,46 @@ import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
define: {
global: 'globalThis'
},
optimizeDeps: {
include: ['@soulcraft/brainy']
},
build: {
rollupOptions: {
output: {
manualChunks: {
'brainy': ['@soulcraft/brainy']
}
}
}
ssr: {
external: ['@soulcraft/brainy']
}
})
```
### Error Handling
Wrap the endpoint call with retry/backoff so transient network failures don't surface to the user.
```javascript
// src/composables/useBrainyWithErrorHandling.js
import { ref, onMounted } from 'vue'
import { Brainy } from '@soulcraft/brainy'
import { ref } from 'vue'
export function useBrainyWithErrorHandling() {
const brain = ref(null)
const isReady = ref(false)
export function useBrainyWithErrorHandling(endpoint = '/api/brain') {
const error = ref(null)
const retryCount = ref(0)
const init = async () => {
try {
brain.value = new Brainy()
await brain.value.init()
isReady.value = true
error.value = null
retryCount.value = 0
} catch (err) {
error.value = err.message
console.error('Brainy initialization failed:', err)
// Retry logic
if (retryCount.value < 3) {
retryCount.value++
setTimeout(init, 2000 * retryCount.value)
const search = async (query, options = {}, maxRetries = 3) => {
error.value = null
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const res = await fetch(`${endpoint}/search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, options })
})
if (!res.ok) throw new Error(`Search failed: ${res.status}`)
return (await res.json()).results
} catch (err) {
error.value = err.message
if (attempt === maxRetries) throw err
// Exponential backoff before retrying
await new Promise(resolve => setTimeout(resolve, 2000 * (attempt + 1)))
}
}
}
onMounted(init)
return {
brain: readonly(brain),
isReady: readonly(isReady),
error: readonly(error),
retry: init
search
}
}
```
@ -1315,6 +1250,13 @@ Here's a complete Vue 3 application structure:
```
my-brainy-vue-app/
├── server/ # Server-side (Node/Bun) — hosts Brainy
│ ├── utils/
│ │ └── brain.js # Shared Brainy instance (getBrain)
│ └── api/brain/
│ ├── search.post.js
│ ├── add.post.js
│ └── stats.get.js
├── src/
│ ├── components/
│ │ ├── Search.vue
@ -1336,7 +1278,7 @@ my-brainy-vue-app/
└── package.json
```
This provides a complete, production-ready Vue.js application with comprehensive Brainy integration.
This provides a complete, production-ready Vue.js application: Brainy runs on the server, and the client talks to it over HTTP.
## 📚 Next Steps