diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..fc501dc --- /dev/null +++ b/.env.example @@ -0,0 +1,51 @@ +# ============================================================================= +# OpenThreads — Environment Variables +# Copy this file to .env and fill in your values. +# ============================================================================= + +# Server +PORT=3000 +NODE_ENV=development + +# MongoDB +# When using Docker Compose: mongodb://openthreads:openthreads@localhost:27017/openthreads +MONGODB_URI=mongodb://openthreads:openthreads@localhost:27017/openthreads + +# Security +# IMPORTANT: Change this in production! Use a long, random string. +JWT_SECRET=change-me-in-production + +# Reply Token TTL (in seconds) +# Default: 86400 (24 hours) +REPLY_TOKEN_TTL=86400 + +# Base URL for OpenThreads (used to build replyTo URLs and form links) +OPENTHREADS_BASE_URL=http://localhost:3000 + +# ============================================================================= +# Channel Credentials +# Add credentials for each channel you want to enable. +# ============================================================================= + +# Slack +# SLACK_BOT_TOKEN=xoxb-your-slack-bot-token +# SLACK_SIGNING_SECRET=your-slack-signing-secret +# SLACK_APP_TOKEN=xapp-your-slack-app-token + +# Telegram +# TELEGRAM_BOT_TOKEN=your-telegram-bot-token + +# Discord +# DISCORD_BOT_TOKEN=your-discord-bot-token +# DISCORD_CLIENT_ID=your-discord-client-id + +# ============================================================================= +# Trust Layer (optional) +# Enable for production deployments requiring strong authentication and +# cryptographic evidence (JWS signing, WebAuthn, audit logging). +# ============================================================================= + +# TRUST_LAYER_ENABLED=false +# TRUST_JWS_ALGORITHM=RS256 +# TRUST_PRIVATE_KEY_PATH=./keys/private.pem +# TRUST_PUBLIC_KEY_PATH=./keys/public.pem diff --git a/.github/workflows/claude-task.yml b/.github/workflows/claude-task.yml index 489dad2..b4ccebf 100644 --- a/.github/workflows/claude-task.yml +++ b/.github/workflows/claude-task.yml @@ -25,3 +25,4 @@ jobs: with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} claude_args: "--model claude-sonnet-4-6" + allowed_bots: "claude[bot]" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c305e91 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Dependencies +node_modules/ + +# Build outputs +dist/ +.next/ +*.tsbuildinfo + +# Environment files +.env +.env.local +.env.*.local +!.env.example + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* +bun-debug.log* + +# Test coverage +coverage/ + +# OS +.DS_Store diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..5fed30d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +.next/ +coverage/ +*.lockb +bun.lockb diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..f5fd668 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..789489e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + mongodb: + image: mongo:7.0 + container_name: openthreads-mongodb + ports: + - '27017:27017' + environment: + MONGO_INITDB_ROOT_USERNAME: openthreads + MONGO_INITDB_ROOT_PASSWORD: openthreads + MONGO_INITDB_DATABASE: openthreads + volumes: + - mongodb_data:/data/db + healthcheck: + test: ['CMD', 'mongosh', '--eval', "db.adminCommand('ping')"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + restart: unless-stopped + +volumes: + mongodb_data: + driver: local diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..8b0fdbe --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,38 @@ +import js from '@eslint/js' +import tsPlugin from '@typescript-eslint/eslint-plugin' +import tsParser from '@typescript-eslint/parser' +import prettierConfig from 'eslint-config-prettier' + +export default [ + js.configs.recommended, + { + files: ['**/*.{ts,tsx}'], + languageOptions: { + parser: tsParser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + }, + plugins: { + '@typescript-eslint': tsPlugin, + }, + rules: { + ...tsPlugin.configs.recommended.rules, + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-explicit-any': 'warn', + }, + }, + prettierConfig, + { + ignores: [ + '**/dist/**', + '**/node_modules/**', + '**/.next/**', + '**/coverage/**', + '*.config.js', + '*.config.mjs', + '*.config.ts', + ], + }, +] diff --git a/package.json b/package.json new file mode 100644 index 0000000..a9f539f --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "openthreads", + "version": "0.0.1", + "private": true, + "workspaces": [ + "packages/core", + "packages/storage/mongodb", + "packages/channels", + "packages/server", + "packages/trust" + ], + "scripts": { + "dev": "bun run --filter '*' dev", + "build": "bun run --filter '*' build", + "test": "bun test", + "lint": "eslint 'packages/**/*.{ts,tsx}'", + "lint:fix": "eslint 'packages/**/*.{ts,tsx}' --fix", + "format": "prettier --write 'packages/**/*.{ts,tsx,json,md}'", + "typecheck": "tsc --build", + "prepare": "husky" + }, + "devDependencies": { + "@eslint/js": "^9.0.0", + "@types/node": "^22.0.0", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "eslint": "^9.0.0", + "eslint-config-prettier": "^9.0.0", + "husky": "^9.0.0", + "lint-staged": "^15.0.0", + "prettier": "^3.0.0", + "typescript": "^5.0.0", + "vite": "^5.0.0", + "vite-plugin-dts": "^4.0.0" + }, + "lint-staged": { + "*.{ts,tsx}": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md}": [ + "prettier --write" + ] + } +} diff --git a/packages/channels/package.json b/packages/channels/package.json new file mode 100644 index 0000000..f29ec7a --- /dev/null +++ b/packages/channels/package.json @@ -0,0 +1,29 @@ +{ + "name": "@openthreads/channels", + "version": "0.0.1", + "private": false, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "vite build", + "dev": "vite build --watch", + "test": "bun test" + }, + "devDependencies": { + "vite": "*", + "vite-plugin-dts": "*", + "typescript": "*" + }, + "dependencies": { + "@openthreads/core": "workspace:*" + } +} diff --git a/packages/channels/src/index.test.ts b/packages/channels/src/index.test.ts new file mode 100644 index 0000000..7a02e09 --- /dev/null +++ b/packages/channels/src/index.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'bun:test' + +describe('@openthreads/channels', () => { + it('exports channel types', async () => { + const mod = await import('./index') + expect(mod).toBeDefined() + }) +}) diff --git a/packages/channels/src/index.ts b/packages/channels/src/index.ts new file mode 100644 index 0000000..15ad8ec --- /dev/null +++ b/packages/channels/src/index.ts @@ -0,0 +1,5 @@ +// @openthreads/channels +// Custom channel adapters (Baileys/WhatsApp, etc.) +// Native Chat SDK adapters live in @openthreads/core + +export * from './types' diff --git a/packages/channels/src/types.ts b/packages/channels/src/types.ts new file mode 100644 index 0000000..dcd6594 --- /dev/null +++ b/packages/channels/src/types.ts @@ -0,0 +1,8 @@ +import type { Channel } from '@openthreads/core' + +export interface ChannelAdapter { + channel: Channel + connect(): Promise + disconnect(): Promise + send(target: string, message: unknown): Promise +} diff --git a/packages/channels/tsconfig.json b/packages/channels/tsconfig.json new file mode 100644 index 0000000..77c920c --- /dev/null +++ b/packages/channels/tsconfig.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "references": [ + { "path": "../core" } + ], + "include": ["src"] +} diff --git a/packages/channels/vite.config.ts b/packages/channels/vite.config.ts new file mode 100644 index 0000000..bea0790 --- /dev/null +++ b/packages/channels/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import dts from 'vite-plugin-dts' +import { resolve } from 'path' + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'OpenThreadsChannels', + formats: ['es', 'cjs'], + fileName: (format) => `index.${format === 'es' ? 'js' : 'cjs'}`, + }, + rollupOptions: { + external: ['@openthreads/core'], + }, + }, + plugins: [dts({ rollupTypes: true })], +}) diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 0000000..f5e5076 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,26 @@ +{ + "name": "@openthreads/core", + "version": "0.0.1", + "private": false, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "vite build", + "dev": "vite build --watch", + "test": "bun test" + }, + "devDependencies": { + "vite": "*", + "vite-plugin-dts": "*", + "typescript": "*" + } +} diff --git a/packages/core/src/index.test.ts b/packages/core/src/index.test.ts new file mode 100644 index 0000000..6e0c74c --- /dev/null +++ b/packages/core/src/index.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'bun:test' + +describe('@openthreads/core', () => { + it('exports types', async () => { + const mod = await import('./index') + expect(mod).toBeDefined() + }) +}) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts new file mode 100644 index 0000000..22be2ad --- /dev/null +++ b/packages/core/src/index.ts @@ -0,0 +1,5 @@ +// @openthreads/core +// Router, reply engine, envelope, thread/turn management, +// abstract storage interface + +export * from './types' diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts new file mode 100644 index 0000000..33c0cc1 --- /dev/null +++ b/packages/core/src/types.ts @@ -0,0 +1,68 @@ +// Core types for OpenThreads + +export interface Thread { + threadId: string + channelId: string + nativeThreadId?: string + createdAt: Date +} + +export interface Turn { + turnId: string + threadId: string + message: Message | Message[] + createdAt: Date +} + +export type Message = ChatMessage | A2HIntent + +export interface ChatMessage { + text: string + attachments?: unknown[] +} + +export type A2HIntentType = 'INFORM' | 'COLLECT' | 'AUTHORIZE' | 'ESCALATE' | 'RESULT' + +export interface A2HIntent { + intent: A2HIntentType + context: Record + traceId?: string +} + +export interface Envelope { + threadId: string + turnId: string + replyTo: string + source: { + channel: string + channelId: string + sender: { id: string; name: string } + } + message: Message | Message[] +} + +export interface Channel { + channelId: string + type: string + name: string + config: Record + createdAt: Date +} + +export interface Route { + routeId: string + name: string + channelId: string + recipient: { + webhookUrl: string + } + filters: Record + createdAt: Date +} + +export interface StorageAdapter { + getThread(threadId: string): Promise + createThread(thread: Omit): Promise + getChannel(channelId: string): Promise + getRoutes(channelId: string): Promise +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 0000000..07dc754 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["src"] +} diff --git a/packages/core/vite.config.ts b/packages/core/vite.config.ts new file mode 100644 index 0000000..415e641 --- /dev/null +++ b/packages/core/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import dts from 'vite-plugin-dts' +import { resolve } from 'path' + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'OpenThreadsCore', + formats: ['es', 'cjs'], + fileName: (format) => `index.${format === 'es' ? 'js' : 'cjs'}`, + }, + rollupOptions: { + external: [], + }, + }, + plugins: [dts({ rollupTypes: true })], +}) diff --git a/packages/server/next.config.ts b/packages/server/next.config.ts new file mode 100644 index 0000000..8d9e44d --- /dev/null +++ b/packages/server/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from 'next' + +const nextConfig: NextConfig = { + transpilePackages: ['@openthreads/core', '@openthreads/storage-mongodb'], +} + +export default nextConfig diff --git a/packages/server/package.json b/packages/server/package.json new file mode 100644 index 0000000..29ae9a4 --- /dev/null +++ b/packages/server/package.json @@ -0,0 +1,23 @@ +{ + "name": "@openthreads/server", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "test": "bun test" + }, + "dependencies": { + "@openthreads/core": "workspace:*", + "@openthreads/storage-mongodb": "workspace:*", + "next": "^15.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "typescript": "*" + } +} diff --git a/packages/server/src/app/layout.tsx b/packages/server/src/app/layout.tsx new file mode 100644 index 0000000..4759d10 --- /dev/null +++ b/packages/server/src/app/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'OpenThreads', + description: 'Unified communication channel abstraction with human-in-the-loop support', +} + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/packages/server/src/app/page.tsx b/packages/server/src/app/page.tsx new file mode 100644 index 0000000..9d6c137 --- /dev/null +++ b/packages/server/src/app/page.tsx @@ -0,0 +1,8 @@ +export default function Home() { + return ( +
+

OpenThreads

+

Unified communication channel abstraction with human-in-the-loop support.

+
+ ) +} diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json new file mode 100644 index 0000000..fa110c7 --- /dev/null +++ b/packages/server/tsconfig.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "ES2022"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "preserve", + "incremental": true, + "composite": false, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/storage/mongodb/package.json b/packages/storage/mongodb/package.json new file mode 100644 index 0000000..54f0254 --- /dev/null +++ b/packages/storage/mongodb/package.json @@ -0,0 +1,33 @@ +{ + "name": "@openthreads/storage-mongodb", + "version": "0.0.1", + "private": false, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "vite build", + "dev": "vite build --watch", + "test": "bun test" + }, + "peerDependencies": { + "mongodb": ">=6.0.0" + }, + "devDependencies": { + "mongodb": "^6.0.0", + "vite": "*", + "vite-plugin-dts": "*", + "typescript": "*" + }, + "dependencies": { + "@openthreads/core": "workspace:*" + } +} diff --git a/packages/storage/mongodb/src/adapter.ts b/packages/storage/mongodb/src/adapter.ts new file mode 100644 index 0000000..7ba53c1 --- /dev/null +++ b/packages/storage/mongodb/src/adapter.ts @@ -0,0 +1,30 @@ +import type { MongoClient, Db } from 'mongodb' +import type { StorageAdapter, Thread, Channel, Route } from '@openthreads/core' + +export class MongoDBStorageAdapter implements StorageAdapter { + private db: Db + + constructor(client: MongoClient, dbName?: string) { + this.db = client.db(dbName) + } + + async getThread(threadId: string): Promise { + const doc = await this.db.collection('threads').findOne({ threadId }) + return doc ?? null + } + + async createThread(thread: Omit): Promise { + const doc: Thread = { ...thread, createdAt: new Date() } + await this.db.collection('threads').insertOne(doc) + return doc + } + + async getChannel(channelId: string): Promise { + const doc = await this.db.collection('channels').findOne({ channelId }) + return doc ?? null + } + + async getRoutes(channelId: string): Promise { + return this.db.collection('routes').find({ channelId }).toArray() + } +} diff --git a/packages/storage/mongodb/src/index.test.ts b/packages/storage/mongodb/src/index.test.ts new file mode 100644 index 0000000..825599d --- /dev/null +++ b/packages/storage/mongodb/src/index.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'bun:test' + +describe('@openthreads/storage-mongodb', () => { + it('exports MongoDBStorageAdapter', async () => { + const { MongoDBStorageAdapter } = await import('./index') + expect(MongoDBStorageAdapter).toBeDefined() + }) +}) diff --git a/packages/storage/mongodb/src/index.ts b/packages/storage/mongodb/src/index.ts new file mode 100644 index 0000000..c55db40 --- /dev/null +++ b/packages/storage/mongodb/src/index.ts @@ -0,0 +1,4 @@ +// @openthreads/storage-mongodb +// MongoDB implementation of the StorageAdapter interface + +export { MongoDBStorageAdapter } from './adapter' diff --git a/packages/storage/mongodb/tsconfig.json b/packages/storage/mongodb/tsconfig.json new file mode 100644 index 0000000..732df5f --- /dev/null +++ b/packages/storage/mongodb/tsconfig.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "references": [ + { "path": "../../core" } + ], + "include": ["src"] +} diff --git a/packages/storage/mongodb/vite.config.ts b/packages/storage/mongodb/vite.config.ts new file mode 100644 index 0000000..dd7cc4e --- /dev/null +++ b/packages/storage/mongodb/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import dts from 'vite-plugin-dts' +import { resolve } from 'path' + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'OpenThreadsMongoDB', + formats: ['es', 'cjs'], + fileName: (format) => `index.${format === 'es' ? 'js' : 'cjs'}`, + }, + rollupOptions: { + external: ['mongodb', '@openthreads/core'], + }, + }, + plugins: [dts({ rollupTypes: true })], +}) diff --git a/packages/trust/package.json b/packages/trust/package.json new file mode 100644 index 0000000..852175b --- /dev/null +++ b/packages/trust/package.json @@ -0,0 +1,29 @@ +{ + "name": "@openthreads/trust", + "version": "0.0.1", + "private": false, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "vite build", + "dev": "vite build --watch", + "test": "bun test" + }, + "devDependencies": { + "vite": "*", + "vite-plugin-dts": "*", + "typescript": "*" + }, + "dependencies": { + "@openthreads/core": "workspace:*" + } +} diff --git a/packages/trust/src/index.test.ts b/packages/trust/src/index.test.ts new file mode 100644 index 0000000..351d79d --- /dev/null +++ b/packages/trust/src/index.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from 'bun:test' + +describe('@openthreads/trust', () => { + it('exports trust types', async () => { + const mod = await import('./index') + expect(mod).toBeDefined() + }) +}) diff --git a/packages/trust/src/index.ts b/packages/trust/src/index.ts new file mode 100644 index 0000000..06edcc1 --- /dev/null +++ b/packages/trust/src/index.ts @@ -0,0 +1,5 @@ +// @openthreads/trust +// Optional trust layer: JWS signing, strong authentication, audit logging +// Enable for compliance requirements; skip for lightweight deployments + +export * from './types' diff --git a/packages/trust/src/types.ts b/packages/trust/src/types.ts new file mode 100644 index 0000000..4291c1c --- /dev/null +++ b/packages/trust/src/types.ts @@ -0,0 +1,21 @@ +import type { A2HIntent } from '@openthreads/core' + +export interface TrustConfig { + enabled: boolean + jwsAlgorithm?: string + privateKeyPath?: string + publicKeyPath?: string +} + +export interface SignedEvidence { + intent: A2HIntent + signature: string + timestamp: Date + nonce: string +} + +export interface TrustLayer { + config: TrustConfig + signIntent(intent: A2HIntent): Promise + verifyEvidence(evidence: SignedEvidence): Promise +} diff --git a/packages/trust/tsconfig.json b/packages/trust/tsconfig.json new file mode 100644 index 0000000..77c920c --- /dev/null +++ b/packages/trust/tsconfig.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "references": [ + { "path": "../core" } + ], + "include": ["src"] +} diff --git a/packages/trust/vite.config.ts b/packages/trust/vite.config.ts new file mode 100644 index 0000000..dbc47bb --- /dev/null +++ b/packages/trust/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import dts from 'vite-plugin-dts' +import { resolve } from 'path' + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'OpenThreadsTrust', + formats: ['es', 'cjs'], + fileName: (format) => `index.${format === 'es' ? 'js' : 'cjs'}`, + }, + rollupOptions: { + external: ['@openthreads/core'], + }, + }, + plugins: [dts({ rollupTypes: true })], +}) diff --git a/scripts/seed.ts b/scripts/seed.ts new file mode 100644 index 0000000..ba45726 --- /dev/null +++ b/scripts/seed.ts @@ -0,0 +1,108 @@ +/** + * Seed script for development data. + * + * Creates sample channels, routes, and threads in MongoDB. + * + * Usage: + * bun scripts/seed.ts + * + * Requires MONGODB_URI to be set in .env or as an environment variable. + */ + +import { MongoClient } from 'mongodb' + +const MONGODB_URI = + process.env.MONGODB_URI ?? 'mongodb://openthreads:openthreads@localhost:27017/openthreads' + +async function seed() { + const client = new MongoClient(MONGODB_URI) + + try { + console.log('Connecting to MongoDB...') + await client.connect() + const db = client.db() + + // --- Channels --- + console.log('Seeding channels...') + await db.collection('channels').deleteMany({}) + await db.collection('channels').insertMany([ + { + channelId: 'channel_slack_main', + type: 'slack', + name: 'Main Slack Bot', + config: { + botToken: 'xoxb-replace-with-real-token', + signingSecret: 'replace-with-real-signing-secret', + }, + createdAt: new Date(), + }, + { + channelId: 'channel_telegram_main', + type: 'telegram', + name: 'Main Telegram Bot', + config: { + botToken: 'replace-with-real-telegram-bot-token', + }, + createdAt: new Date(), + }, + ]) + + // --- Routes --- + console.log('Seeding routes...') + await db.collection('routes').deleteMany({}) + await db.collection('routes').insertMany([ + { + routeId: 'route_default_slack', + name: 'Default Slack Route', + channelId: 'channel_slack_main', + recipient: { + webhookUrl: 'http://localhost:8080/webhook', + }, + filters: {}, + createdAt: new Date(), + }, + { + routeId: 'route_default_telegram', + name: 'Default Telegram Route', + channelId: 'channel_telegram_main', + recipient: { + webhookUrl: 'http://localhost:8080/webhook', + }, + filters: {}, + createdAt: new Date(), + }, + ]) + + // --- Threads --- + console.log('Seeding threads...') + await db.collection('threads').deleteMany({}) + await db.collection('threads').insertMany([ + { + threadId: 'ot_thr_sample001', + channelId: 'channel_slack_main', + nativeThreadId: 'T_SAMPLE_001', + turns: [], + createdAt: new Date(), + }, + { + threadId: 'ot_thr_sample002', + channelId: 'channel_telegram_main', + nativeThreadId: null, + turns: [], + createdAt: new Date(), + }, + ]) + + console.log('✓ Seed completed successfully') + console.log(' - 2 channels created') + console.log(' - 2 routes created') + console.log(' - 2 threads created') + } catch (error) { + console.error('Seed failed:', error) + process.exit(1) + } finally { + await client.close() + } +} + +seed() diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..74fc444 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "composite": true, + "isolatedModules": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true + }, + "exclude": ["node_modules", "dist"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e576685 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "files": [], + "references": [ + { "path": "packages/core" }, + { "path": "packages/storage/mongodb" }, + { "path": "packages/channels" }, + { "path": "packages/trust" } + ] +}