npm package: @nilobot/knowledge-connector
Description: Simple connectors for Google Drive, Notion, and Dropbox
Author: nilobot
Latest version: 0.1.0

# @nilobot/knowledge-connector

Simple, lightweight connectors for Google Drive, Notion, and Dropbox. Built for knowledge base ingestion and document processing.

## Features

- ✅ **Google Drive** - OAuth, list files, download content, export Google Docs
- ✅ **Notion** - OAuth, search pages, fetch blocks and content
- ✅ **Dropbox** - OAuth, list files, download content
- ✅ **TypeScript First** - Full type safety and IntelliSense
- ✅ **Framework Agnostic** - Works with Next.js, Express, standalone scripts
- ✅ **Lightweight** - Only essential dependencies
- ✅ **Auto Token Refresh** - Handles expired tokens automatically
- ✅ **Error Handling** - Custom error types for better debugging

## Installation

```bash
pnpm add @nilobot/knowledge-connector
# or
npm install @nilobot/knowledge-connector
# or
yarn add @nilobot/knowledge-connector
```

## Quick Start

### Google Drive

```typescript
import { DriveConnector } from '@nilobot/knowledge-connector';

const drive = new DriveConnector({
  clientId: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  redirectUri: 'http://localhost:3000/callback',
});

// 1. Get auth URL
const authUrl = drive.getAuthUrl();
// User visits URL and authorizes

// 2. Exchange code for tokens
const tokens = await drive.exchangeCode(code);

// 3. List files
const result = await drive.list({ folderId: 'root' });

// 4. Download file
const content = await drive.fetch(result.items[0].id);
```

### Notion

```typescript
import { NotionConnector } from '@nilobot/knowledge-connector';

const notion = new NotionConnector({
  accessToken: process.env.NOTION_ACCESS_TOKEN,
});

// Search for pages
const result = await notion.list({ query: 'meeting notes' });

// Fetch page content
const content = await notion.fetch(result.items[0].id);
console.log(content.data); // Plain text content
```

### Dropbox

```typescript
import { DropboxConnector } from '@nilobot/knowledge-connector';

const dropbox = new DropboxConnector({
  clientId: process.env.DROPBOX_CLIENT_ID,
  clientSecret: process.env.DROPBOX_CLIENT_SECRET,
  redirectUri: 'http://localhost:3000/callback',
});

// OAuth flow
const authUrl = dropbox.getAuthUrl();
const tokens = await dropbox.exchangeCode(code);

// List files
const result = await dropbox.list({ path: '' });

// Download file
const content = await dropbox.fetch(result.items[0].id);
```

## API Reference

### Common Interface

All connectors implement the `Connector` interface:

```typescript
interface Connector {
  getAuthUrl(state?: string): string;
  exchangeCode(code: string): Promise<Tokens>;
  setTokens(tokens: Tokens): void;
  list(options?: ListOptions): Promise<ListResult>;
  fetch(itemId: string): Promise<Content>;
  getMetadata(itemId: string): Promise<Item>;
}
```

### DriveConnector

#### Constructor

```typescript
new DriveConnector(config: DriveConfig)
```

**Config:**
```typescript
interface DriveConfig {
  clientId: string;
  clientSecret: string;
  redirectUri: string;
  accessToken?: string;
  refreshToken?: string;
  tokenStore?: TokenStore;
  userId?: string;
  scopes?: string[];
}
```

#### Methods

**`export(itemId: string, mimeType: string): Promise<Content>`**

Export Google Workspace files (Docs, Sheets, Slides) to different formats.

```typescript
// Export Google Doc to plain text
const content = await drive.export(docId, 'text/plain');

// Export Spreadsheet to CSV
const csv = await drive.export(sheetId, 'text/csv');
```

### NotionConnector

#### Constructor

```typescript
new NotionConnector(config: NotionConfig)
```

**Config:**
```typescript
interface NotionConfig {
  accessToken: string;
  clientId?: string;
  clientSecret?: string;
  redirectUri?: string;
}
```

### DropboxConnector

#### Constructor

```typescript
new DropboxConnector(config: DropboxConfig)
```

**Config:**
```typescript
interface DropboxConfig {
  clientId: string;
  clientSecret: string;
  redirectUri: string;
  accessToken?: string;
  refreshToken?: string;
}
```

## Token Storage

For production use, implement a `TokenStore` to persist tokens:

```typescript
import { TokenStore, Tokens } from '@nilobot/knowledge-connector';
import prisma from './db';

class PrismaTokenStore implements TokenStore {
  async get(userId: string, provider: string): Promise<Tokens | null> {
    const record = await prisma.token.findUnique({
      where: { userId_provider: { userId, provider } },
    });
    
    if (!record) return null;
    
    return {
      accessToken: record.accessToken,
      refreshToken: record.refreshToken || undefined,
      expiresAt: record.expiresAt || undefined,
    };
  }

  async set(userId: string, provider: string, tokens: Tokens): Promise<void> {
    await prisma.token.upsert({
      where: { userId_provider: { userId, provider } },
      create: { userId, provider, ...tokens },
      update: tokens,
    });
  }

  async delete(userId: string, provider: string): Promise<void> {
    await prisma.token.delete({
      where: { userId_provider: { userId, provider } },
    });
  }
}

// Use it
const drive = new DriveConnector({
  clientId: '...',
  clientSecret: '...',
  redirectUri: '...',
  tokenStore: new PrismaTokenStore(),
  userId: 'user123',
});

// Connector will auto-load and refresh tokens
const files = await drive.list();
```

## Error Handling

The package provides custom error types:

```typescript
import {
  AuthenticationError,
  RateLimitError,
  NotFoundError,
  QuotaExceededError,
  ConfigurationError,
} from '@niloflora/knowledge-connector';

import {
  AuthenticationError,
  RateLimitError,
  NotFoundError,
  QuotaExceededError,
  ConfigurationError,
} from '@nilobot/knowledge-connector';

try {
  const files = await drive.list();
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Handle auth errors (expired token, invalid credentials)
    console.error('Authentication failed:', error.message);
  } else if (error instanceof RateLimitError) {
    // Handle rate limiting
    console.error('Rate limited. Retry after:', error.retryAfter);
  } else if (error instanceof NotFoundError) {
    // Handle not found errors
    console.error('Resource not found:', error.message);
  }
}
```

## Usage in Next.js

### API Route Example

```typescript
// app/api/drive/list/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { DriveConnector } from '@nilobot/knowledge-connector';
import { auth } from '@/lib/auth';
import { PrismaTokenStore } from '@/lib/token-store';

export async function GET(req: NextRequest) {
  const session = await auth();
  if (!session?.user?.id) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const drive = new DriveConnector({
    clientId: process.env.GOOGLE_CLIENT_ID!,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    redirectUri: process.env.GOOGLE_REDIRECT_URI!,
    tokenStore: new PrismaTokenStore(),
    userId: session.user.id,
  });

  try {
    const result = await drive.list({ folderId: 'root' });
    return NextResponse.json(result);
  } catch (error) {
    return NextResponse.json(
      { error: error.message },
      { status: 500 }
    );
  }
}
```

## Examples

See the `examples/` directory for complete usage examples:

- [`drive-example.ts`](examples/drive-example.ts) - Google Drive integration
- [`notion-example.ts`](examples/notion-example.ts) - Notion integration
- [`dropbox-example.ts`](examples/dropbox-example.ts) - Dropbox integration

## Development

```bash
# Install dependencies
pnpm install

# Build
pnpm build

# Watch mode
pnpm dev

# Run tests
pnpm test

# Type check
pnpm typecheck
```

## License

MIT

## Contributing

Contributions welcome! Please open an issue or PR.