Adapter SDK

Store

SQLite-backed persistent storage for session mappings and message deduplication.

Store

The adapter store provides persistent storage for session-to-container mappings, bidirectional message ID mapping, replay cursors, and update offsets. Backed by SQLite via better-sqlite3.

AdapterStore Interface

interface AdapterStore {
  readonly containers: SessionContainerRepo
  readonly messages: MessageMapRepo
  readonly seen: SessionSeenRepo
  readonly offset: UpdateOffsetRepo
  close(): void
}

Default Store

The runtime creates a SQLite store automatically when you provide dataDir:

const runtime = createAdapterRuntime({
  dataDir: '/path/to/data',  // SQLite DB at /path/to/data/state.db
  // ...
})

Or create one manually:

import { createSqliteStore } from '@oro.ad/bridge-adapter-sdk'

const store = createSqliteStore({ dataDir: '/path/to/data' })

SessionContainerRepo

Maps bridge sessions to platform containers.

interface SessionContainerRow {
  conversation_id: string
  container_id: string          // platform-side ID
  title: string | null
  project_name: string | null
  status: string | null
  metadata: string | null       // JSON string for custom data
  created_at: string
  updated_at: string
  closed_at: string | null
}

Methods

// Create or update a mapping
store.containers.upsert({
  conversation_id: 'claude_abc123',
  container_id: '925',
  title: 'My Session',
  project_name: 'my-project',
  status: 'active',
})

// Lookups
const row = store.containers.findByConversationId('claude_abc123')
const row = store.containers.findByContainerId('925')
const all = store.containers.listAll()

// Lifecycle
store.containers.markClosed('claude_abc123')
store.containers.delete('claude_abc123')

MessageMapRepo

Bidirectional mapping between bridge message IDs and platform message IDs. Used for deduplication and cross-referencing.

interface MessageMapRow {
  bridge_message_id: string
  conversation_id: string
  platform_chat_id: string | null
  platform_container_id: string
  platform_message_id: string
  direction: 'inbound' | 'outbound'
  created_at: string
}

Methods

// Record a mapping
store.messages.insert({
  bridge_message_id: 'msg_xyz',
  conversation_id: 'claude_abc123',
  platform_container_id: '925',
  platform_message_id: '12345',
  direction: 'outbound',
})

// Dedup check
store.messages.hasBridgeMessage('msg_xyz')  // boolean

// Lookup
store.messages.findPlatformIdByBridgeId('msg_xyz')  // string | undefined

// Cleanup
store.messages.deleteForConversation('claude_abc123')
store.messages.pruneOlderThan(30)  // delete entries older than 30 days

SessionSeenRepo

Tracks the last-seen message ID per session for replay cursor.

store.seen.get('claude_abc123')                          // string | undefined
store.seen.set('claude_abc123', 'msg_last_seen')
store.seen.delete('claude_abc123')

UpdateOffsetRepo

Stores the platform's last processed update ID (e.g., Telegram's update_id).

store.offset.get()        // string (default: '0')
store.offset.set('12345')

Custom Store

You can provide a custom AdapterStore implementation instead of SQLite:

const runtime = createAdapterRuntime({
  store: myCustomStore,   // must implement AdapterStore interface
  // ...
})