brainy/integrations/README.md
David Snelling b5bc9000cf feat: Integration Hub for external tool connectivity
- Add native config option: `new Brainy({ integrations: true })`
- OData integration for Excel Power Query and Power BI
- Google Sheets integration with Apps Script
- Server-Sent Events (SSE) for real-time streaming
- Webhooks for push notifications
- Zero-config with sensible defaults
- Full tree-shaking when disabled
2026-01-20 16:21:11 -08:00

7.6 KiB

Brainy Integrations

Connect Brainy to spreadsheets, BI tools, and external systems with zero configuration.

Quick Start

import { Brainy } from '@soulcraft/brainy'

const brain = new Brainy({ integrations: true })
await brain.init()

// That's it! Your endpoints are ready:
console.log(brain.hub.endpoints)
// { odata: '/odata', sheets: '/sheets', sse: '/events', webhooks: '/webhooks' }

Supported Tools

Tool Protocol How to Connect
Excel OData Data → Get Data → From OData Feed → http://your-server/odata
Power BI OData Get Data → OData Feed → http://your-server/odata
Tableau OData Connect → OData → http://your-server/odata
Google Sheets REST Install Apps Script add-on (see below)
Any SSE Client SSE new EventSource('http://your-server/events')

Excel (Power Query)

Connect in 3 clicks:

  1. Data tab → Get DataFrom Other SourcesFrom OData Feed
  2. Enter URL: http://your-server/odata
  3. Click OKLoad

Query Options

Excel Power Query supports OData query parameters:

/odata/Entities?$filter=Type eq 'person'&$top=100
/odata/Entities?$select=Id,Type,Metadata_name
/odata/Entities?$orderby=CreatedAt desc
/odata/Entities?$search=machine learning

Refresh Data

  • Manual: DataRefresh All
  • Automatic: Query Properties → Set refresh interval

Power BI

Connect:

  1. Get DataOData Feed
  2. Enter URL: http://your-server/odata
  3. Select tables: Entities, Relationships
  4. Click Load

Advanced

Power BI DirectQuery is supported for real-time data.


Tableau

Connect:

  1. ConnectTo a ServerOData
  2. Enter: http://your-server/odata
  3. Drag tables to canvas

Google Sheets

Setup (5 minutes):

  1. Open your Google Sheet
  2. ExtensionsApps Script
  3. Delete existing code
  4. Copy integrations/google-sheets/Code.gs into the editor
  5. Create new file Sidebar.html, paste from integrations/google-sheets/Sidebar.html
  6. Project SettingsScript properties → Add:
    • BRAINY_URL = http://your-server
  7. Save and refresh spreadsheet

Custom Functions:

=BRAINY_QUERY("type:person", 100)     // Query entities
=BRAINY_GET("entity-id")               // Get one entity
=BRAINY_SIMILAR("machine learning", 5) // Semantic search
=BRAINY_RELATIONS("entity-id", "from") // Get relationships

Sidebar:

ExtensionsBrainyOpen Sidebar

  • Search and insert results
  • Add new entities
  • Sync selected range to Brainy

Real-Time Streaming (SSE)

JavaScript:

const source = new EventSource('http://your-server/events')

source.onmessage = (event) => {
  const data = JSON.parse(event.data)
  console.log('Change:', data)
}

// Filter by type
const filtered = new EventSource('http://your-server/events?types=noun&operations=create,update')

Query Parameters:

  • types - Entity types: noun, verb, vfs
  • operations - Operations: create, update, delete
  • nounTypes - Filter by noun type: person, document, etc.

Webhooks

Push events to external URLs:

const brain = new Brainy({ integrations: true })
await brain.init()

// Register a webhook
await brain.hub.webhooks?.register({
  url: 'https://your-app.com/webhook',
  events: { entityTypes: ['noun'], operations: ['create', 'update'] },
  secret: 'your-hmac-secret'  // optional, for signature verification
})

Webhook Payload:

{
  "events": [
    {
      "id": "event-123",
      "type": "noun",
      "operation": "create",
      "entityId": "entity-456",
      "timestamp": 1704067200000
    }
  ],
  "deliveredAt": 1704067201000
}

Signature Verification:

Webhooks include X-Brainy-Signature header with HMAC-SHA256 signature.


Server Examples

Minimal (in-memory):

import { Brainy } from '@soulcraft/brainy'

const brain = new Brainy({ integrations: true })
await brain.init()

// Add some data
await brain.add({ type: 'Person', metadata: { name: 'Alice' } })

// Get connection instructions
console.log(brain.hub.getInstructions())

Express:

import express from 'express'
import { Brainy } from '@soulcraft/brainy'

const app = express()
const brain = new Brainy({
  storage: { type: 'filesystem', options: { basePath: './data' } },
  integrations: true
})
await brain.init()

app.use(express.json())

// Route all integrations
app.all(['/odata/*', '/sheets/*', '/events/*'], async (req, res) => {
  const response = await brain.hub.handleRequest({
    method: req.method,
    path: req.path,
    query: req.query as Record<string, string>,
    headers: req.headers as Record<string, string>,
    body: req.body
  })

  res.status(response.status).set(response.headers)
  if (response.body) res.json(response.body)
  else res.end()
})

app.listen(3000, () => {
  console.log('Brainy server ready!')
  console.log('Excel/Power BI: http://localhost:3000/odata')
  console.log('Google Sheets: http://localhost:3000/sheets')
  console.log('SSE Stream: http://localhost:3000/events')
})

Hono (Cloudflare Workers):

import { Hono } from 'hono'
import { Brainy } from '@soulcraft/brainy'

const app = new Hono()

const brain = new Brainy({
  storage: { type: 'memory' },
  integrations: true
})
await brain.init()

app.all('/odata/*', async (c) => {
  const response = await brain.hub.handleRequest({
    method: c.req.method,
    path: c.req.path,
    query: Object.fromEntries(new URL(c.req.url).searchParams),
    headers: Object.fromEntries(c.req.raw.headers),
    body: await c.req.json().catch(() => undefined)
  })
  return c.json(response.body, response.status)
})

export default app

Configuration

Custom Base Path:

const brain = new Brainy({
  integrations: { basePath: '/api/v1' }
})
await brain.init()

// Endpoints become:
// /api/v1/odata
// /api/v1/sheets
// /api/v1/events

Select Integrations:

// Only OData and Sheets
const brain = new Brainy({
  integrations: { enable: ['odata', 'sheets'] }
})
await brain.init()

Per-Integration Config:

const brain = new Brainy({
  integrations: {
    config: {
      odata: { basePath: '/data' },
      sse: { heartbeatInterval: 15000 }
    }
  }
})
await brain.init()

Troubleshooting

Excel: "Can't connect to OData feed"

  • Ensure server is running and accessible
  • Check firewall settings
  • Try opening URL in browser first

Google Sheets: "Brainy URL not configured"

  • Add BRAINY_URL in Apps Script → Project Settings → Script properties

Power BI: "Invalid OData"

  • Ensure $metadata endpoint returns valid XML
  • Try: http://your-server/odata/$metadata

SSE: "Connection dropped"

  • Check network/proxy timeout settings
  • The integration sends heartbeats every 30 seconds by default

API Reference

OData Endpoints

GET  /odata/$metadata      - Schema (XML)
GET  /odata/Entities       - List entities
GET  /odata/Entities('id') - Get entity
GET  /odata/Relationships  - List relationships
POST /odata/Entities       - Create entity

Sheets Endpoints

GET  /sheets/query?q=...&limit=100  - Query entities
GET  /sheets/entity/:id             - Get entity
GET  /sheets/similar?text=...&k=10  - Semantic search
POST /sheets/add                    - Add entity

SSE Endpoint

GET /events                           - All events
GET /events?types=noun                - Filter by type
GET /events?operations=create,update  - Filter by operation