Files
linsa-linsa-io/packages/worker/readme.md

8.2 KiB

Worker Package

A Cloudflare Worker that provides both HTTP API endpoints (via Hono) and RPC methods (via WorkerEntrypoint) for service bindings.

Features

  • HTTP API: REST endpoints using Hono framework
  • RPC Methods: Type-safe RPC calls via WorkerEntrypoint for service bindings
  • CORS Support: Pre-configured CORS for API endpoints
  • TypeScript: Full type safety across the worker

Project Structure

packages/worker/
├── src/
│   ├── index.ts       # Main entry point (exports HTTP handler and RPC class)
│   └── rpc.ts         # RPC methods (WorkerEntrypoint class)
├── wrangler.jsonc     # Cloudflare Worker configuration
├── tsconfig.json      # TypeScript configuration
├── vitest.config.mts  # Vitest configuration
└── package.json       # Package dependencies and scripts

HTTP API Endpoints

Health Check

GET /health

Returns the health status of the worker.

Response:

{
	"status": "ok",
	"message": "Worker is running!"
}

Root

GET /

Returns information about available endpoints.

Response:

{
	"message": "Welcome to the Cloudflare Worker API",
	"endpoints": {
		"health": "/health",
		"api": "/api/v1"
	}
}

Hello Endpoint

GET /api/v1/hello?name=World

Returns a greeting message.

Query Parameters:

  • name (optional): Name to greet (default: "World")

Response:

{
	"message": "Hello, World!"
}

Admin API (write access)

These endpoints write directly to Postgres for pragmatic data ingestion.

Authentication:

  • If ADMIN_API_KEY is set, include Authorization: Bearer <ADMIN_API_KEY>.
  • If ADMIN_API_KEY is not set, requests are allowed (useful for local dev).

Canvas

  • POST /api/v1/admin/canvas
  • PATCH /api/v1/admin/canvas/:canvasId
  • POST /api/v1/admin/canvas/:canvasId/images
  • PATCH /api/v1/admin/canvas/images/:imageId
  • DELETE /api/v1/admin/canvas/images/:imageId

Chat

  • POST /api/v1/admin/chat/threads
  • PATCH /api/v1/admin/chat/threads/:threadId
  • POST /api/v1/admin/chat/messages

Context Items

  • POST /api/v1/admin/context-items
  • PATCH /api/v1/admin/context-items/:itemId
  • POST /api/v1/admin/context-items/:itemId/link
  • DELETE /api/v1/admin/context-items/:itemId

Browser Sessions

  • POST /api/v1/admin/browser-sessions
  • PATCH /api/v1/admin/browser-sessions/:sessionId
  • DELETE /api/v1/admin/browser-sessions/:sessionId

External Logs

To forward logs into 1focus Logs for the linsa server, set these secrets/vars in the worker:

  • FOCUS_LOGS_API_KEY (required)
  • FOCUS_LOGS_SERVER (optional, default: linsa)
  • FOCUS_LOGS_ENDPOINT (optional, default: https://1focus.app/api/logs)

Then send a log:

curl -X POST "http://localhost:8787/api/v1/admin/logs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{"message":"Hello from linsa","level":"info"}'

Example (create chat thread)

curl -X POST "http://localhost:8787/api/v1/admin/chat/threads" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{"title":"Research notes","userId":"user_123"}'

RPC Methods

The WorkerRpc class provides the following methods for service bindings:

sayHello

async sayHello(name: string): Promise<{ message: string; timestamp: number }>

Returns a greeting message with timestamp.

Example:

const result = await env.WORKER_RPC.sayHello('World');
// { message: "Hello, World!", timestamp: 1234567890 }

calculate

async calculate(
  operation: 'add' | 'subtract' | 'multiply' | 'divide',
  a: number,
  b: number
): Promise<number>

Performs arithmetic operations.

Example:

const sum = await env.WORKER_RPC.calculate('add', 5, 3);
// 8

getData

async getData(key: string): Promise<{ key: string; found: boolean; value?: string }>

Fetches data by key. Can be extended to use KV, D1, or R2 bindings.

Example:

const result = await env.WORKER_RPC.getData('myKey');
// { key: "myKey", found: false, value: undefined }

processBatch

async processBatch(items: string[]): Promise<{ processed: number; items: string[] }>

Processes a batch of items.

Example:

const result = await env.WORKER_RPC.processBatch(['item1', 'item2']);
// { processed: 2, items: ["ITEM1", "ITEM2"] }

Development

Install Dependencies

pnpm install

Start Development Server

pnpm dev

The worker will be available at http://localhost:8787

Database configuration

Set DATABASE_URL locally or configure the HYPERDRIVE binding in wrangler.jsonc. In production, use wrangler secret put ADMIN_API_KEY to secure the admin endpoints.

Run Tests

pnpm test

Linting

# Check for linting issues
pnpm lint

# Fix linting issues
pnpm lint:fix

Format Code

pnpm format

Deployment

Prerequisites

  1. Install Wrangler CLI (included in dependencies)
  2. Login to Cloudflare:
pnpm wrangler login

Update Configuration

Edit wrangler.jsonc and update:

  • name: Your worker name
  • account_id: Your Cloudflare account ID (if needed)

Deploy to Cloudflare

pnpm deploy

Configuration

wrangler.jsonc

Key configuration options:

{
	"name": "fullstack-monorepo-template-worker",
	"main": "src/index.ts",
	"compatibility_date": "2025-09-06",
}

Adding Bindings

You can add various bindings to your worker:

KV Namespace

"kv_namespaces": [
  {
    "binding": "MY_KV",
    "id": "your-kv-namespace-id"
  }
]

D1 Database

"d1_databases": [
  {
    "binding": "DB",
    "database_name": "my-database",
    "database_id": "your-database-id"
  }
]

R2 Bucket

"r2_buckets": [
  {
    "binding": "MY_BUCKET",
    "bucket_name": "my-bucket"
  }
]

Environment Variables

"vars": {
  "MY_VARIABLE": "production_value"
}

Using RPC from Other Workers

To call this worker's RPC methods from another worker:

  1. Add a service binding in the calling worker's wrangler.jsonc:
{
	"services": [
		{
			"binding": "WORKER_RPC",
			"service": "fullstack-monorepo-template-worker",
			"entrypoint": "WorkerRpc",
		},
	],
}
  1. Call RPC methods with full type safety:
export default {
	async fetch(request: Request, env: Env) {
		// Call RPC methods
		const greeting = await env.WORKER_RPC.sayHello('World');
		const sum = await env.WORKER_RPC.calculate('add', 5, 3);

		return new Response(JSON.stringify({ greeting, sum }));
	},
};

Adding New Endpoints

HTTP Endpoint

Add new routes in src/index.ts:

app.get('/api/v1/users', (c) => {
	return c.json({ users: [] });
});

RPC Method

Add new methods in src/rpc.ts:

export class WorkerRpc extends WorkerEntrypoint {
	async getUser(userId: string): Promise<User> {
		// Your logic here
		return { id: userId, name: 'John Doe' };
	}
}

Testing

Tests use Vitest with the Cloudflare Workers pool. Create test files alongside your source files:

// src/index.test.ts
import { describe, it, expect } from 'vitest';

describe('Worker', () => {
	it('should return health status', async () => {
		const response = await fetch('http://localhost:8787/health');
		const data = await response.json();
		expect(data.status).toBe('ok');
	});
});

TypeScript Types

The worker uses @cloudflare/workers-types for Cloudflare-specific types. These are automatically available in your TypeScript files.

Tech Stack

  • Runtime: Cloudflare Workers
  • Framework: Hono (HTTP API)
  • RPC: WorkerEntrypoint (Service Bindings)
  • Language: TypeScript
  • Testing: Vitest + @cloudflare/vitest-pool-workers
  • Package Manager: pnpm

Resources