Skip to content

Latest commit

 

History

History
225 lines (175 loc) · 5.74 KB

File metadata and controls

225 lines (175 loc) · 5.74 KB

AGENTS.md

Guide for AI agents working on the smslib monorepo.

Project Overview

smslib is an open-source monorepo for sending SMS via multiple gateways/providers. It includes a MailHog-style local dev server for testing without hitting real APIs.

Tech Stack

Component Choice
Runtime TypeScript (strict mode)
Monorepo pnpm workspace + Turbo
API Server Express v5
UI Vite + React 19
Database PouchDB (local-first, schema-flexible)
Container Docker

Directory Structure

smslib/
├── packages/
│   ├── types/                    # Shared TypeScript interfaces
│   ├── core/                     # SmsClient, Transport abstraction
│   └── adapters/
│       ├── twilio/               # International gateway
│       ├── mimsms/               # BD domestic SMS
│       └── alphanet/             # BD domestic SMS
├── apps/
│   └── dev-server/
│       ├── api/                  # Express v5 mock endpoints
│       ├── web/                  # Vite + React 19 UI
│       └── docker/               # Dockerfile + docker-compose
├── docs/
│   ├── plan.md                   # Implementation plan
│   └── ref.*.md                  # Provider API reference docs
├── examples/
├── turbo.json
├── pnpm-workspace.yaml
└── package.json

Key Design Principles

  1. Transport decides environment - base URL is injected via Transport, not adapter
  2. Adapters stay unaware of environment - no if (dev) inside adapters
  3. Dev server mimics real provider APIs - adapter code stays identical between dev/prod
  4. Each adapter is a separate package - incrementally addable
  5. Publishable packages - packages/* are intended for npm publishing (public use)

Provider Base URLs (Defaults)

Adapters use these URLs by default when no custom transport is provided:

Provider Base URL
Twilio https://api.twilio.com/2010-04-01
MiMSMS https://api.mimsms.com
AlphaNet https://api.sms.net.bd

Commands

# Install dependencies
pnpm install

# Run dev server (API + Web)
pnpm dev

# Run only API
pnpm dev:api

# Run only Web UI
pnpm dev:web

# Build all packages
pnpm build

# Lint all packages
pnpm lint

Adding a New Adapter

  1. Create packages/adapters/<name>/ package
  2. Implement SmsAdapter interface from @smslib/types
  3. Add mock endpoints to apps/dev-server/api/src/routes/<name>.ts
  4. Update docs/plan.md with new provider info

Adapter Interface

interface SmsAdapter {
  readonly provider: string;
  send(msg: SmsMessageCreate): Promise<SendResult>;
  getName(): string;
}

Transport Pattern

Adapters default to live URLs. Override via transport for dev:

// Production - adapter creates default transport with live URL
const twilio = new TwilioAdapter({ accountSid: 'AC...', authToken: 'xxx' });
// → internally uses FetchTransport('https://api.twilio.com/2010-04-01')

// Development - override transport baseUrl
const devTransport = new FetchTransport({ baseUrl: 'http://localhost:3000/api' });
const twilio = new TwilioAdapter(
  { accountSid: 'AC...', authToken: 'xxx' },
  devTransport
);

Package Scripts

{
  "dev": "pnpm --filter dev-server dev",
  "dev:api": "pnpm --filter dev-server/api dev",
  "dev:web": "pnpm --filter dev-server/web dev",
  "build": "turbo build",
  "lint": "turbo lint"
}

TypeScript Configuration

  • Target: ES2022
  • Module: NodeNext
  • ModuleResolution: NodeNext
  • Strict mode enabled

Dependency Injection Pattern

Each adapter accepts:

  1. config - provider-specific credentials
  2. transport - HTTP transport with configurable base URL

The adapter only knows the endpoint path (e.g., /Messages.json), while the transport handles the full URL (e.g., http://localhost:3000/api/Messages.json).

Dev Server Routes

Route Provider Mimics
POST /api/twilio/messages Twilio Twilio API
POST /api/mimsms/send MiMSMS MiMSMS API
POST /api/alphanet/sendsms AlphaNet AlphaNet API
GET /api/messages - Message listing
GET /api/messages/:id - Message detail

File Naming Conventions

  • TypeScript source: src/index.ts
  • React components: PascalCase.tsx
  • Utilities: camelCase.ts
  • Route handlers: kebab-case.ts
  • Test files: *.test.ts or *.spec.ts

Workspace Dependencies

Use workspace:* for internal package dependencies:

{
  "dependencies": {
    "@smslib/types": "workspace:*"
  }
}

Publishing to npm

Packages under packages/* are intended for public npm publishing.

Package Requirements for Publishing

Each publishable package must have:

  • name: @smslib/<package-name>
  • version: Semver format (e.g., 0.1.0)
  • type: "module"
  • license: "MIT" or similar
  • description: Brief description
  • repository: Link to git repo
  • exports: Proper ESM export mapping
  • main: CJS fallback (.js)
  • types: TypeScript declaration (.d.ts)

Example package.json (publishable)

{
  "name": "@smslib/adapter-twilio",
  "version": "0.1.0",
  "type": "module",
  "license": "MIT",
  "description": "Twilio SMS adapter for smslib",
  "repository": "https://github.com/mrmeaow/smslib",
  "main": "./dist/index.js",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "files": ["dist"]
}

Internal Dependencies

During development, use workspace:*:

"dependencies": {
  "@smslib/types": "workspace:*"
}

When publishing, these will be replaced with actual version ranges.