chore(8.0): modernize toolchain + position Bun as a runtime
Consumer-invisible modernization pass — no public API or runtime-behavior
change; dist for the override-only files is byte-identical.
Toolchain:
- CI: GitHub Actions matrix — Node 22/24 (test:unit) + Bun latest (test:bun).
- engines: node ">=22" (was "22.x"), bun ">=1.1.0".
- tsconfig: isolatedModules + noImplicitOverride; add the 33 `override`
modifiers the flag requires across storage/integrations/vfs/transaction.
- deps: @types/node ^22; add prettier; drop dead standard-version,
@rollup/plugin-* and the redundant embedded eslintConfig (flat
eslint.config.js is the active config — verified identical lint output).
paramValidation: replace the top-level `await import('node:os'/'node:fs')`
with static ESM imports. The top-level-await form poisoned the module graph;
static imports also drop the browser/edge fallback branches no supported
runtime reaches (8.0 is Node/Bun/Deno-only).
Bun positioning: recommend Bun as a runtime (`bun add` / `bun run`), which is
green (test:bun 8/8). Drop single-binary `bun build --compile` as a target —
native addons cannot embed into it, and Bun 1.3.10 has a `--compile` codegen
regression around top-level await. Rename the Bun test to bun-runtime-test.ts
and correct docs that overclaimed single-binary support.
Gates: typecheck 0, build 0, test:unit 1743/1743, test:bun 8/8.
This commit is contained in:
parent
ae55d54cb5
commit
ca9129a924
20 changed files with 159 additions and 2330 deletions
38
.github/workflows/ci.yml
vendored
Normal file
38
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
node:
|
||||||
|
name: Node ${{ matrix.node-version }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
node-version: ['22', '24']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: npm
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run test:unit
|
||||||
|
|
||||||
|
bun:
|
||||||
|
name: Bun (latest)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '22'
|
||||||
|
cache: npm
|
||||||
|
- uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
- run: npm ci
|
||||||
|
# Bun as a runtime is the supported Bun story (`bun add` / `bun run`).
|
||||||
|
- run: npm run test:bun
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
"types": [
|
|
||||||
{"type": "feat", "section": "✨ Features"},
|
|
||||||
{"type": "fix", "section": "🐛 Bug Fixes"},
|
|
||||||
{"type": "docs", "section": "📚 Documentation"},
|
|
||||||
{"type": "refactor", "section": "♻️ Code Refactoring"},
|
|
||||||
{"type": "perf", "section": "⚡ Performance Improvements"},
|
|
||||||
{"type": "test", "section": "✅ Tests"},
|
|
||||||
{"type": "build", "section": "🔧 Build System"},
|
|
||||||
{"type": "ci", "section": "🔄 CI/CD"},
|
|
||||||
{"type": "style", "hidden": true},
|
|
||||||
{"type": "chore", "hidden": true}
|
|
||||||
],
|
|
||||||
"compareUrlFormat": "https://github.com/soulcraftlabs/brainy/compare/{{previousTag}}...{{currentTag}}",
|
|
||||||
"commitUrlFormat": "https://github.com/soulcraftlabs/brainy/commit/{{hash}}",
|
|
||||||
"issueUrlFormat": "https://github.com/soulcraftlabs/brainy/issues/{{id}}",
|
|
||||||
"userUrlFormat": "https://github.com/{{user}}",
|
|
||||||
"releaseCommitMessageFormat": "chore(release): {{currentTag}}",
|
|
||||||
"issuePrefixes": ["#"],
|
|
||||||
"header": "# Changelog\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.\n",
|
|
||||||
"scripts": {
|
|
||||||
"postbump": "echo '✅ Version bumped to' $(node -p \"require('./package.json').version\")"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -21,7 +21,8 @@ Built because we were tired of stitching together Pinecone + Neo4j + MongoDB and
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install @soulcraft/brainy
|
bun add @soulcraft/brainy # fastest — recommended
|
||||||
|
npm install @soulcraft/brainy # Node.js — fully supported
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
@ -387,10 +388,10 @@ Performance benchmarks and capacity planning in **[docs/PERFORMANCE.md](docs/PER
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
**Bun 1.0+** (recommended) or **Node.js 22 LTS**
|
**Bun 1.1+** (recommended) or **Node.js 22 LTS**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bun install @soulcraft/brainy # Bun — best performance
|
bun add @soulcraft/brainy # Bun — best performance
|
||||||
npm install @soulcraft/brainy # Node.js — fully supported
|
npm install @soulcraft/brainy # Node.js — fully supported
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,9 +215,9 @@ console.log('Server running on http://localhost:3000')
|
||||||
```
|
```
|
||||||
|
|
||||||
**Benefits:**
|
**Benefits:**
|
||||||
- ✅ Native Bun performance (~2x faster than Node.js)
|
- ✅ Native Bun runtime performance
|
||||||
- ✅ No framework dependencies
|
- ✅ No framework dependencies
|
||||||
- ✅ Works with `bun --compile` for single-binary deployment
|
- ✅ Pure WASM — no native binaries, bundler-friendly
|
||||||
- ✅ Built-in TypeScript support
|
- ✅ Built-in TypeScript support
|
||||||
|
|
||||||
### Pattern 4: Express/Node.js Middleware (Legacy)
|
### Pattern 4: Express/Node.js Middleware (Legacy)
|
||||||
|
|
|
||||||
|
|
@ -35,15 +35,18 @@ This single WASM file contains everything needed for sentence embeddings.
|
||||||
|
|
||||||
### Bun (Recommended)
|
### Bun (Recommended)
|
||||||
|
|
||||||
```typescript
|
```bash
|
||||||
// Works with Bun runtime
|
# Bun as a runtime — supported and recommended
|
||||||
|
bun add @soulcraft/brainy
|
||||||
bun run server.ts
|
bun run server.ts
|
||||||
|
|
||||||
// Works with bun --compile (single binary deployment!)
|
|
||||||
bun build --compile --target=bun server.ts
|
|
||||||
./server // Self-contained binary with embedded model
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Brainy is pure WebAssembly with no native binaries, so the module graph stays
|
||||||
|
bundler-friendly. Single-binary `bun build --compile` is **not a supported
|
||||||
|
target** at present: Bun 1.3.10 has a `--compile` codegen regression
|
||||||
|
(`__promiseAll is not defined`) triggered by top-level `await` in the bundled
|
||||||
|
graph. Run Brainy under the Bun runtime (above) instead.
|
||||||
|
|
||||||
### Node.js
|
### Node.js
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|
@ -164,7 +167,7 @@ await brain.init()
|
||||||
|
|
||||||
**What's new:**
|
**What's new:**
|
||||||
- Faster initialization
|
- Faster initialization
|
||||||
- Works with `bun --compile`
|
- Bundler-friendly (pure WASM, no native binaries)
|
||||||
- No network requirements
|
- No network requirements
|
||||||
|
|
||||||
### From Custom Embedding Functions
|
### From Custom Embedding Functions
|
||||||
|
|
@ -216,9 +219,8 @@ export { brain }
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
```bash
|
```bash
|
||||||
# Option 1: Bun compile (single binary)
|
# Option 1: Bun runtime
|
||||||
bun build --compile server.ts
|
bun run server.ts
|
||||||
./server # Contains everything
|
|
||||||
|
|
||||||
# Option 2: Docker
|
# Option 2: Docker
|
||||||
docker build -t my-app .
|
docker build -t my-app .
|
||||||
|
|
|
||||||
2240
package-lock.json
generated
2240
package-lock.json
generated
File diff suppressed because it is too large
Load diff
49
package.json
49
package.json
|
|
@ -66,8 +66,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "22.x",
|
"node": ">=22",
|
||||||
"bun": ">=1.0.0"
|
"bun": ">=1.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
||||||
|
|
@ -94,8 +94,7 @@
|
||||||
"test:ci-unit": "CI=true vitest run --config tests/configs/vitest.unit.config.ts",
|
"test:ci-unit": "CI=true vitest run --config tests/configs/vitest.unit.config.ts",
|
||||||
"test:ci-integration": "NODE_OPTIONS='--max-old-space-size=16384' CI=true vitest run --config tests/configs/vitest.integration.config.ts",
|
"test:ci-integration": "NODE_OPTIONS='--max-old-space-size=16384' CI=true vitest run --config tests/configs/vitest.integration.config.ts",
|
||||||
"test:ci": "npm run test:ci-unit && npm run test:ci-integration",
|
"test:ci": "npm run test:ci-unit && npm run test:ci-integration",
|
||||||
"test:bun": "bun tests/integration/bun-compile-test.ts",
|
"test:bun": "bun tests/integration/bun-runtime-test.ts",
|
||||||
"test:bun:compile": "bun build tests/integration/bun-compile-test.ts --compile --outfile /tmp/brainy-bun-test && /tmp/brainy-bun-test",
|
|
||||||
"test:wasm": "npx vitest run tests/integration/wasm-embeddings.test.ts",
|
"test:wasm": "npx vitest run tests/integration/wasm-embeddings.test.ts",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"lint": "eslint --ext .ts,.js src/",
|
"lint": "eslint --ext .ts,.js src/",
|
||||||
|
|
@ -106,11 +105,7 @@
|
||||||
"release:patch": "./scripts/release.sh patch",
|
"release:patch": "./scripts/release.sh patch",
|
||||||
"release:minor": "./scripts/release.sh minor",
|
"release:minor": "./scripts/release.sh minor",
|
||||||
"release:major": "./scripts/release.sh major",
|
"release:major": "./scripts/release.sh major",
|
||||||
"release:dry": "./scripts/release.sh patch --dry-run",
|
"release:dry": "./scripts/release.sh patch --dry-run"
|
||||||
"release:standard-version": "standard-version",
|
|
||||||
"release:standard-version:patch": "standard-version --release-as patch",
|
|
||||||
"release:standard-version:minor": "standard-version --release-as minor",
|
|
||||||
"release:standard-version:major": "standard-version --release-as major"
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ai-database",
|
"ai-database",
|
||||||
|
|
@ -157,14 +152,10 @@
|
||||||
"boolean": "3.2.0"
|
"boolean": "3.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^28.0.6",
|
|
||||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
||||||
"@rollup/plugin-replace": "^6.0.2",
|
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
|
||||||
"@testcontainers/redis": "^11.5.1",
|
"@testcontainers/redis": "^11.5.1",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/mime": "^3.0.4",
|
"@types/mime": "^3.0.4",
|
||||||
"@types/node": "^20.11.30",
|
"@types/node": "^22",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||||
|
|
@ -172,7 +163,7 @@
|
||||||
"@vitest/coverage-v8": "^3.2.4",
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
"jspdf": "^3.0.3",
|
"jspdf": "^3.0.3",
|
||||||
"minio": "^8.0.5",
|
"minio": "^8.0.5",
|
||||||
"standard-version": "^9.5.0",
|
"prettier": "^3.9.4",
|
||||||
"testcontainers": "^11.5.1",
|
"testcontainers": "^11.5.1",
|
||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
|
|
@ -210,33 +201,5 @@
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"useTabs": false
|
"useTabs": false
|
||||||
},
|
|
||||||
"eslintConfig": {
|
|
||||||
"root": true,
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"plugins": [
|
|
||||||
"@typescript-eslint"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"args": "after-used",
|
|
||||||
"argsIgnorePattern": "^_"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"semi": "off",
|
|
||||||
"@typescript-eslint/semi": [
|
|
||||||
"error",
|
|
||||||
"never"
|
|
||||||
],
|
|
||||||
"no-extra-semi": "off"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ export class ODataIntegration extends IntegrationBase implements HTTPIntegration
|
||||||
/**
|
/**
|
||||||
* Get augmentation manifest
|
* Get augmentation manifest
|
||||||
*/
|
*/
|
||||||
getManifest(): Record<string, any> {
|
override getManifest(): Record<string, any> {
|
||||||
return {
|
return {
|
||||||
id: 'odata',
|
id: 'odata',
|
||||||
name: 'OData Integration',
|
name: 'OData Integration',
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ export class GoogleSheetsIntegration
|
||||||
/**
|
/**
|
||||||
* Get manifest
|
* Get manifest
|
||||||
*/
|
*/
|
||||||
getManifest(): Record<string, any> {
|
override getManifest(): Record<string, any> {
|
||||||
return {
|
return {
|
||||||
id: 'sheets',
|
id: 'sheets',
|
||||||
name: 'Google Sheets Integration',
|
name: 'Google Sheets Integration',
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ export class SSEIntegration
|
||||||
/**
|
/**
|
||||||
* Get manifest
|
* Get manifest
|
||||||
*/
|
*/
|
||||||
getManifest(): Record<string, any> {
|
override getManifest(): Record<string, any> {
|
||||||
return {
|
return {
|
||||||
id: 'sse',
|
id: 'sse',
|
||||||
name: 'SSE Streaming',
|
name: 'SSE Streaming',
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ export class WebhookIntegration extends IntegrationBase {
|
||||||
/**
|
/**
|
||||||
* Get manifest
|
* Get manifest
|
||||||
*/
|
*/
|
||||||
getManifest(): Record<string, any> {
|
override getManifest(): Record<string, any> {
|
||||||
return {
|
return {
|
||||||
id: 'webhooks',
|
id: 'webhooks',
|
||||||
name: 'Webhooks',
|
name: 'Webhooks',
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
*
|
*
|
||||||
* @returns FileSystem-optimized batch configuration
|
* @returns FileSystem-optimized batch configuration
|
||||||
*/
|
*/
|
||||||
public getBatchConfig(): StorageBatchConfig {
|
public override getBatchConfig(): StorageBatchConfig {
|
||||||
return {
|
return {
|
||||||
maxBatchSize: 500,
|
maxBatchSize: 500,
|
||||||
batchDelayMs: 0,
|
batchDelayMs: 0,
|
||||||
|
|
@ -180,7 +180,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
/**
|
/**
|
||||||
* Initialize the storage adapter
|
* Initialize the storage adapter
|
||||||
*/
|
*/
|
||||||
public async init(): Promise<void> {
|
public override async init(): Promise<void> {
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -952,7 +952,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
*
|
*
|
||||||
* @param prefix - Storage-root-relative directory prefix to remove.
|
* @param prefix - Storage-root-relative directory prefix to remove.
|
||||||
*/
|
*/
|
||||||
public async removeRawPrefix(prefix: string): Promise<void> {
|
public override async removeRawPrefix(prefix: string): Promise<void> {
|
||||||
await this.ensureInitialized()
|
await this.ensureInitialized()
|
||||||
await fs.promises.rm(path.join(this.rootDir, prefix), { recursive: true, force: true })
|
await fs.promises.rm(path.join(this.rootDir, prefix), { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
|
|
@ -966,7 +966,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
*
|
*
|
||||||
* @param paths - Storage-root-relative object paths previously written.
|
* @param paths - Storage-root-relative object paths previously written.
|
||||||
*/
|
*/
|
||||||
public async syncRawObjects(paths: string[]): Promise<void> {
|
public override async syncRawObjects(paths: string[]): Promise<void> {
|
||||||
await this.ensureInitialized()
|
await this.ensureInitialized()
|
||||||
const parentDirs = new Set<string>()
|
const parentDirs = new Set<string>()
|
||||||
|
|
||||||
|
|
@ -1539,7 +1539,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
// Removed 10 *_internal method overrides - now inherit from BaseStorage's type-first implementation
|
// Removed 10 *_internal method overrides - now inherit from BaseStorage's type-first implementation
|
||||||
// Removed 2 pagination methods (getNounsWithPagination, getVerbsWithPagination) - use BaseStorage's implementation
|
// Removed 2 pagination methods (getNounsWithPagination, getVerbsWithPagination) - use BaseStorage's implementation
|
||||||
|
|
||||||
public supportsMultiProcessLocking(): boolean {
|
public override supportsMultiProcessLocking(): boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1557,7 +1557,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
* `lastHeartbeat` is older than `WRITER_STALE_THRESHOLD_MS` (60s).
|
* `lastHeartbeat` is older than `WRITER_STALE_THRESHOLD_MS` (60s).
|
||||||
* Stale locks are overwritten with a warning. `force: true` overrides even live locks.
|
* Stale locks are overwritten with a warning. `force: true` overrides even live locks.
|
||||||
*/
|
*/
|
||||||
public async acquireWriterLock(options?: { force?: boolean }): Promise<WriterLockInfo | null> {
|
public override async acquireWriterLock(options?: { force?: boolean }): Promise<WriterLockInfo | null> {
|
||||||
await this.ensureInitialized()
|
await this.ensureInitialized()
|
||||||
await this.ensureDirectoryExists(this.lockDir)
|
await this.ensureDirectoryExists(this.lockDir)
|
||||||
|
|
||||||
|
|
@ -1639,7 +1639,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
public async releaseWriterLock(): Promise<void> {
|
public override async releaseWriterLock(): Promise<void> {
|
||||||
if (this.writerLockHeartbeat) {
|
if (this.writerLockHeartbeat) {
|
||||||
clearInterval(this.writerLockHeartbeat)
|
clearInterval(this.writerLockHeartbeat)
|
||||||
this.writerLockHeartbeat = undefined
|
this.writerLockHeartbeat = undefined
|
||||||
|
|
@ -1664,7 +1664,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async readWriterLock(): Promise<WriterLockInfo | null> {
|
public override async readWriterLock(): Promise<WriterLockInfo | null> {
|
||||||
await this.ensureInitialized()
|
await this.ensureInitialized()
|
||||||
const lockFile = path.join(this.lockDir, FileSystemStorage.WRITER_LOCK_FILE)
|
const lockFile = path.join(this.lockDir, FileSystemStorage.WRITER_LOCK_FILE)
|
||||||
try {
|
try {
|
||||||
|
|
@ -1749,7 +1749,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
* `locks/_flush_responses/` with the same request ID. Stale `.req` files
|
* `locks/_flush_responses/` with the same request ID. Stale `.req` files
|
||||||
* (>FLUSH_REQUEST_TTL_MS) are garbage-collected on every tick.
|
* (>FLUSH_REQUEST_TTL_MS) are garbage-collected on every tick.
|
||||||
*/
|
*/
|
||||||
public startFlushRequestWatcher(onRequest: () => Promise<void>): void {
|
public override startFlushRequestWatcher(onRequest: () => Promise<void>): void {
|
||||||
if (this.flushWatcherInterval) return // already watching
|
if (this.flushWatcherInterval) return // already watching
|
||||||
this.flushWatcherOnRequest = onRequest
|
this.flushWatcherOnRequest = onRequest
|
||||||
|
|
||||||
|
|
@ -1772,7 +1772,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopFlushRequestWatcher(): void {
|
public override stopFlushRequestWatcher(): void {
|
||||||
if (this.flushWatcherInterval) {
|
if (this.flushWatcherInterval) {
|
||||||
clearInterval(this.flushWatcherInterval)
|
clearInterval(this.flushWatcherInterval)
|
||||||
this.flushWatcherInterval = undefined
|
this.flushWatcherInterval = undefined
|
||||||
|
|
@ -1851,7 +1851,7 @@ export class FileSystemStorage extends BaseStorage {
|
||||||
* Inspector side: drop a `.req` file and poll for the corresponding `.ack`.
|
* Inspector side: drop a `.req` file and poll for the corresponding `.ack`.
|
||||||
* Returns true if the writer acknowledged in time, false on timeout.
|
* Returns true if the writer acknowledged in time, false on timeout.
|
||||||
*/
|
*/
|
||||||
public async requestFlushOverFilesystem(timeoutMs: number): Promise<boolean> {
|
public override async requestFlushOverFilesystem(timeoutMs: number): Promise<boolean> {
|
||||||
await this.ensureInitialized()
|
await this.ensureInitialized()
|
||||||
const reqDir = path.join(this.lockDir, FileSystemStorage.FLUSH_REQUEST_DIR)
|
const reqDir = path.join(this.lockDir, FileSystemStorage.FLUSH_REQUEST_DIR)
|
||||||
const ackDir = path.join(this.lockDir, FileSystemStorage.FLUSH_RESPONSE_DIR)
|
const ackDir = path.join(this.lockDir, FileSystemStorage.FLUSH_RESPONSE_DIR)
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export class MemoryStorage extends BaseStorage {
|
||||||
*
|
*
|
||||||
* @returns Memory-optimized batch configuration
|
* @returns Memory-optimized batch configuration
|
||||||
*/
|
*/
|
||||||
public getBatchConfig(): StorageBatchConfig {
|
public override getBatchConfig(): StorageBatchConfig {
|
||||||
return {
|
return {
|
||||||
maxBatchSize: 1000,
|
maxBatchSize: 1000,
|
||||||
batchDelayMs: 0,
|
batchDelayMs: 0,
|
||||||
|
|
@ -86,7 +86,7 @@ export class MemoryStorage extends BaseStorage {
|
||||||
* Initialize the storage adapter
|
* Initialize the storage adapter
|
||||||
* Calls super.init() to initialize GraphAdjacencyIndex and type statistics
|
* Calls super.init() to initialize GraphAdjacencyIndex and type statistics
|
||||||
*/
|
*/
|
||||||
public async init(): Promise<void> {
|
public override async init(): Promise<void> {
|
||||||
await super.init()
|
await super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1551,7 +1551,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* - Early termination when offset + limit entities collected
|
* - Early termination when offset + limit entities collected
|
||||||
* - Memory efficient: Never loads full dataset
|
* - Memory efficient: Never loads full dataset
|
||||||
*/
|
*/
|
||||||
public async getNounsWithPagination(options: {
|
public override async getNounsWithPagination(options: {
|
||||||
limit: number
|
limit: number
|
||||||
offset: number
|
offset: number
|
||||||
cursor?: string // Opaque resume token from a prior page's nextCursor; when set it supersedes offset (O(N) walk, no re-scan)
|
cursor?: string // Opaque resume token from a prior page's nextCursor; when set it supersedes offset (O(N) walk, no re-scan)
|
||||||
|
|
@ -1717,7 +1717,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* - Memory efficient: Never loads full dataset
|
* - Memory efficient: Never loads full dataset
|
||||||
* - Inline filtering for sourceId, targetId, verbType
|
* - Inline filtering for sourceId, targetId, verbType
|
||||||
*/
|
*/
|
||||||
public async getVerbsWithPagination(options: {
|
public override async getVerbsWithPagination(options: {
|
||||||
limit: number
|
limit: number
|
||||||
offset: number
|
offset: number
|
||||||
cursor?: string // Opaque resume token from a prior page's nextCursor; when set it supersedes offset (O(N) walk, no re-scan)
|
cursor?: string // Opaque resume token from a prior page's nextCursor; when set it supersedes offset (O(N) walk, no re-scan)
|
||||||
|
|
@ -2442,13 +2442,13 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* Clear all data from storage
|
* Clear all data from storage
|
||||||
* This method should be implemented by each specific adapter
|
* This method should be implemented by each specific adapter
|
||||||
*/
|
*/
|
||||||
public abstract clear(): Promise<void>
|
public abstract override clear(): Promise<void>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about storage usage and capacity
|
* Get information about storage usage and capacity
|
||||||
* This method should be implemented by each specific adapter
|
* This method should be implemented by each specific adapter
|
||||||
*/
|
*/
|
||||||
public abstract getStorageStatus(): Promise<{
|
public abstract override getStorageStatus(): Promise<{
|
||||||
type: string
|
type: string
|
||||||
used: number
|
used: number
|
||||||
quota: number | null
|
quota: number | null
|
||||||
|
|
@ -2957,7 +2957,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
*
|
*
|
||||||
* @public - Inherited from BaseStorageAdapter
|
* @public - Inherited from BaseStorageAdapter
|
||||||
*/
|
*/
|
||||||
public getBatchConfig(): StorageBatchConfig {
|
public override getBatchConfig(): StorageBatchConfig {
|
||||||
// Conservative defaults - adapters should override with their actual limits
|
// Conservative defaults - adapters should override with their actual limits
|
||||||
return {
|
return {
|
||||||
maxBatchSize: 100,
|
maxBatchSize: 100,
|
||||||
|
|
@ -3513,7 +3513,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* writer flush — the same silent-stale failure mode that once produced
|
* writer flush — the same silent-stale failure mode that once produced
|
||||||
* zero counts from `brain.stats()`.
|
* zero counts from `brain.stats()`.
|
||||||
*/
|
*/
|
||||||
public async flushCounts(): Promise<void> {
|
public override async flushCounts(): Promise<void> {
|
||||||
await super.flushCounts()
|
await super.flushCounts()
|
||||||
await this.saveTypeStatistics()
|
await this.saveTypeStatistics()
|
||||||
await this.saveSubtypeStatistics()
|
await this.saveSubtypeStatistics()
|
||||||
|
|
@ -4297,7 +4297,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* Save statistics data to storage (public interface)
|
* Save statistics data to storage (public interface)
|
||||||
* @param statistics The statistics data to save
|
* @param statistics The statistics data to save
|
||||||
*/
|
*/
|
||||||
public async saveStatistics(statistics: StatisticsData): Promise<void> {
|
public override async saveStatistics(statistics: StatisticsData): Promise<void> {
|
||||||
return this.saveStatisticsData(statistics)
|
return this.saveStatisticsData(statistics)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4305,7 +4305,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* Get statistics data from storage (public interface)
|
* Get statistics data from storage (public interface)
|
||||||
* @returns Promise that resolves to the statistics data or null if not found
|
* @returns Promise that resolves to the statistics data or null if not found
|
||||||
*/
|
*/
|
||||||
public async getStatistics(): Promise<StatisticsData | null> {
|
public override async getStatistics(): Promise<StatisticsData | null> {
|
||||||
return this.getStatisticsData()
|
return this.getStatisticsData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4314,7 +4314,7 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* This method should be implemented by each specific adapter
|
* This method should be implemented by each specific adapter
|
||||||
* @param statistics The statistics data to save
|
* @param statistics The statistics data to save
|
||||||
*/
|
*/
|
||||||
protected abstract saveStatisticsData(
|
protected abstract override saveStatisticsData(
|
||||||
statistics: StatisticsData
|
statistics: StatisticsData
|
||||||
): Promise<void>
|
): Promise<void>
|
||||||
|
|
||||||
|
|
@ -4323,5 +4323,5 @@ export abstract class BaseStorage extends BaseStorageAdapter {
|
||||||
* This method should be implemented by each specific adapter
|
* This method should be implemented by each specific adapter
|
||||||
* @returns Promise that resolves to the statistics data or null if not found
|
* @returns Promise that resolves to the statistics data or null if not found
|
||||||
*/
|
*/
|
||||||
protected abstract getStatisticsData(): Promise<StatisticsData | null>
|
protected abstract override getStatisticsData(): Promise<StatisticsData | null>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export class TransactionExecutionError extends TransactionError {
|
||||||
message: string,
|
message: string,
|
||||||
public readonly operationIndex: number,
|
public readonly operationIndex: number,
|
||||||
public readonly operationName: string | undefined,
|
public readonly operationName: string | undefined,
|
||||||
public readonly cause: Error
|
public override readonly cause: Error
|
||||||
) {
|
) {
|
||||||
super(message, {
|
super(message, {
|
||||||
operationIndex,
|
operationIndex,
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,13 @@ import { NounType, VerbType } from '../types/graphTypes.js'
|
||||||
import { prodLog } from './logger.js'
|
import { prodLog } from './logger.js'
|
||||||
import { findCallerLocation } from './callerLocation.js'
|
import { findCallerLocation } from './callerLocation.js'
|
||||||
|
|
||||||
// Dynamic import for Node.js os and fs modules
|
// 8.0 is Node/Bun/Deno-only (no browser path), so `node:os` / `node:fs` are
|
||||||
let os: any = null
|
// always present — static ESM imports instead of a top-level `await import()`.
|
||||||
let fs: any = null
|
// The TLA form poisoned the module graph with a top-level await, which `bun
|
||||||
try {
|
// build --compile` refuses; the static form also drops the browser/edge
|
||||||
os = await import('node:os')
|
// fallback branches that no supported runtime can reach.
|
||||||
fs = await import('node:fs')
|
import * as os from 'node:os'
|
||||||
} catch (e) {
|
import * as fs from 'node:fs'
|
||||||
// OS/FS modules not available
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSystemMemory = (): number => {
|
const getSystemMemory = (): number => {
|
||||||
if (os) {
|
if (os) {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export class VFSReadStream extends Readable {
|
||||||
this.position = options.start || 0
|
this.position = options.start || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async _read(size: number): Promise<void> {
|
override async _read(size: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
// Lazy load entity
|
// Lazy load entity
|
||||||
if (!this.entity) {
|
if (!this.entity) {
|
||||||
|
|
@ -58,7 +58,7 @@ export class VFSReadStream extends Readable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroy(error: Error | null, callback: (error?: Error | null) => void): void {
|
override _destroy(error: Error | null, callback: (error?: Error | null) => void): void {
|
||||||
// Clean up resources
|
// Clean up resources
|
||||||
this.entity = null
|
this.entity = null
|
||||||
this.data = null
|
this.data = null
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export class VFSWriteStream extends Writable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _write(
|
override async _write(
|
||||||
chunk: any,
|
chunk: any,
|
||||||
encoding: BufferEncoding,
|
encoding: BufferEncoding,
|
||||||
callback: (error?: Error | null) => void
|
callback: (error?: Error | null) => void
|
||||||
|
|
@ -52,7 +52,7 @@ export class VFSWriteStream extends Writable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _final(callback: (error?: Error | null) => void): Promise<void> {
|
override async _final(callback: (error?: Error | null) => void): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this._flush()
|
await this._flush()
|
||||||
callback()
|
callback()
|
||||||
|
|
@ -78,7 +78,7 @@ export class VFSWriteStream extends Writable {
|
||||||
this.chunks = []
|
this.chunks = []
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroy(error: Error | null, callback: (error?: Error | null) => void): void {
|
override _destroy(error: Error | null, callback: (error?: Error | null) => void): void {
|
||||||
// Clean up resources
|
// Clean up resources
|
||||||
this.chunks = []
|
this.chunks = []
|
||||||
this._closed = true
|
this._closed = true
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,24 @@
|
||||||
/**
|
/**
|
||||||
* Bun Compile Test
|
* Bun Runtime Test
|
||||||
*
|
*
|
||||||
* Tests that Brainy works when compiled with `bun build --compile`.
|
* Tests that Brainy runs correctly under the Bun runtime (`bun add` / `bun run`) —
|
||||||
* This verifies:
|
* the supported Bun story. Verifies:
|
||||||
* 1. No native binaries required (pure WASM)
|
* 1. No native binaries required (pure WASM)
|
||||||
* 2. Model is properly bundled
|
* 2. Model is properly bundled
|
||||||
* 3. Embeddings work without network access
|
* 3. Embeddings work without network access
|
||||||
*
|
*
|
||||||
* To test manually:
|
* To run manually:
|
||||||
* bun build tests/integration/bun-compile-test.ts --compile --outfile /tmp/brainy-bun-test
|
* bun tests/integration/bun-runtime-test.ts
|
||||||
* /tmp/brainy-bun-test
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Brainy } from '../../dist/index.js'
|
import { Brainy } from '../../dist/index.js'
|
||||||
import { embeddingManager } from '../../dist/embeddings/EmbeddingManager.js'
|
import { embeddingManager } from '../../dist/embeddings/EmbeddingManager.js'
|
||||||
import { WASMEmbeddingEngine } from '../../dist/embeddings/wasm/index.js'
|
import { WASMEmbeddingEngine } from '../../dist/embeddings/wasm/index.js'
|
||||||
|
|
||||||
async function testBunCompile() {
|
async function testBunRuntime() {
|
||||||
const results: { test: string; passed: boolean; error?: string }[] = []
|
const results: { test: string; passed: boolean; error?: string }[] = []
|
||||||
|
|
||||||
console.log('🚀 Brainy Bun Compile Test\n')
|
console.log('🚀 Brainy Bun Runtime Test\n')
|
||||||
console.log('Runtime:', typeof Bun !== 'undefined' ? `Bun ${Bun.version}` : `Node.js ${process.version}`)
|
console.log('Runtime:', typeof Bun !== 'undefined' ? `Bun ${Bun.version}` : `Node.js ${process.version}`)
|
||||||
console.log('')
|
console.log('')
|
||||||
|
|
||||||
|
|
@ -153,13 +152,13 @@ async function testBunCompile() {
|
||||||
console.log('\n❌ Some tests failed!')
|
console.log('\n❌ Some tests failed!')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
} else {
|
} else {
|
||||||
console.log('\n✅ All tests passed! Brainy works with Bun compile.')
|
console.log('\n✅ All tests passed! Brainy runs under Bun.')
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run tests
|
// Run tests
|
||||||
testBunCompile().catch(error => {
|
testBunRuntime().catch(error => {
|
||||||
console.error('Fatal error:', error)
|
console.error('Fatal error:', error)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
|
@ -19,7 +19,9 @@
|
||||||
"noEmit": false,
|
"noEmit": false,
|
||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"downlevelIteration": true
|
"downlevelIteration": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noImplicitOverride": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*"
|
"src/**/*"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue