From 55f320ddf4ac992143fed479a144e247ca1033cc Mon Sep 17 00:00:00 2001 From: Jacob Date: Thu, 12 Mar 2026 01:12:58 -0400 Subject: [PATCH] chore: fix CI lint, add npm READMEs, v0.1.2 - Fix ESLint varsIgnorePattern so _tollway destructuring doesn't fail lint - Add comprehensive README.md to both packages (shown on npmjs.com) - Add homepage, bugs, and funding fields to both package.json files - Bump to v0.1.2 Co-Authored-By: Claude Sonnet 4.6 --- .eslintrc.cjs | 2 +- packages/tollway-client/README.md | 109 +++++++++++++++++++ packages/tollway-client/package.json | 13 ++- packages/tollway-server/README.md | 157 +++++++++++++++++++++++++++ packages/tollway-server/package.json | 13 ++- 5 files changed, 289 insertions(+), 5 deletions(-) create mode 100644 packages/tollway-client/README.md create mode 100644 packages/tollway-server/README.md diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e04222e..f4b0330 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,7 +12,7 @@ module.exports = { }, rules: { '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_' }], '@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }], }, ignorePatterns: ['dist/', 'node_modules/', '*.cjs', '*.config.*'], diff --git a/packages/tollway-client/README.md b/packages/tollway-client/README.md new file mode 100644 index 0000000..7d3193f --- /dev/null +++ b/packages/tollway-client/README.md @@ -0,0 +1,109 @@ +# @tollway/client + +Drop-in `fetch` replacement for AI agents. Handles Tollway identity headers, site policy enforcement, HTTP 402 payment flows, and structured data extraction automatically. + +Part of the [Tollway open protocol](https://tollway.dev) — robots.txt rebuilt for the agentic era. + +## Install + +```bash +npm install @tollway/client +``` + +## Quick Start + +```ts +import { createAgent } from '@tollway/client'; + +const agent = createAgent({ + did: process.env.AGENT_DID, // did:key:z6Mk... + privateKey: process.env.AGENT_KEY, // Ed25519 private key (hex) + purpose: 'Summarise recent AI news', + scope: 'read', +}); + +const result = await agent.fetch('https://techcrunch.com/2026/03/09/ai-news/'); + +console.log(result.data); // { title, description, url, domain } +console.log(result.attribution); // "TechCrunch (https://...)" if required +console.log(result.paid); // true if a micropayment was made +console.log(result.cost); // "0.001" USDC +console.log(result.policy); // site's tollway.json policy +``` + +## API + +### `createAgent(options)` + +Returns an agent instance bound to a set of identity options. + +```ts +const agent = createAgent({ + did: 'did:key:z6Mk...', // required — your agent's DID + privateKey: '...', // required — Ed25519 private key (hex) + purpose: 'Research', // required — human-readable intent + scope: 'read', // required — read | search | summarize | train | scrape_bulk + wallet: '0x...', // optional — USDC wallet for payments + maxPriceUsdc: '0.01', // optional — max per-request price (default 0.01) + principalDid: 'did:key:...', // optional — operator DID if different from agent + framework: 'langchain/0.3.0', // optional — framework identifier + reputationOracle: 'https://...', // optional — custom reputation oracle +}); + +agent.fetch(url, init?) // fetch with identity headers attached +agent.checkPolicy(url) // fetch site's tollway.json without making a request +agent.options // the options this agent was created with +``` + +### `fetch(url, init?)` + +Low-level fetch with optional `tollway` options. Use `createAgent` for most cases. + +```ts +import { fetch } from '@tollway/client'; + +const result = await fetch('https://example.com/', { + tollway: { did, privateKey, purpose, scope }, +}); +``` + +### `getReputation(did, oracle?)` + +Look up an agent's reputation score from a Tollway reputation oracle. + +```ts +import { getReputation } from '@tollway/client'; + +const rep = await getReputation('did:key:z6Mk...'); +// { score: 0.95, observations: 1234, flags: [] } +``` + +## How It Works + +1. **Policy fetch** — checks `/.well-known/tollway.json` on the target site (cached 5 min) +2. **Identity headers** — attaches `X-Tollway-DID`, `X-Tollway-Purpose`, `X-Tollway-Scope`, `X-Tollway-Nonce`, `X-Tollway-Timestamp`, and an Ed25519 `X-Tollway-Signature` +3. **402 handling** — if the site returns HTTP 402, attempts payment via x402 (USDC on Base) and retries +4. **Extraction** — parses OG tags and metadata from HTML responses into structured JSON + +## Generating a DID + Key Pair + +```ts +import { generateKeyPair } from '@noble/ed25519'; +import { base58btc } from 'multiformats/bases/base58'; + +const privKey = crypto.getRandomValues(new Uint8Array(32)); +const pubKey = await generateKeyPair(privKey); // ed25519 + +// Multicodec prefix for Ed25519 public key: 0xed01 +const multicodecKey = new Uint8Array([0xed, 0x01, ...pubKey]); +const did = `did:key:z${base58btc.encode(multicodecKey)}`; +const privateKeyHex = Buffer.from(privKey).toString('hex'); +``` + +## Protocol + +`@tollway/client` implements the [Tollway v0.1 specification](https://github.com/TollwayProtocol/Tollway/blob/main/SPEC.md). + +- **Spec:** CC BY 4.0 +- **Code:** MIT +- **GitHub:** [TollwayProtocol/Tollway](https://github.com/TollwayProtocol/Tollway) diff --git a/packages/tollway-client/package.json b/packages/tollway-client/package.json index c8f0b58..e799d1d 100644 --- a/packages/tollway-client/package.json +++ b/packages/tollway-client/package.json @@ -1,6 +1,6 @@ { "name": "@tollway/client", - "version": "0.1.1", + "version": "0.1.2", "description": "Drop-in fetch replacement for AI agents — identity headers, policy enforcement, and payment flows", "keywords": [ "tollway", @@ -27,9 +27,18 @@ "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", + "homepage": "https://tollway.dev", + "bugs": { + "url": "https://github.com/TollwayProtocol/Tollway/issues" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/TollwayProtocol" + }, "files": [ "dist", - "LICENSE" + "LICENSE", + "README.md" ], "scripts": { "build": "tsup", diff --git a/packages/tollway-server/README.md b/packages/tollway-server/README.md new file mode 100644 index 0000000..bbca7e3 --- /dev/null +++ b/packages/tollway-server/README.md @@ -0,0 +1,157 @@ +# @tollway/server + +Express and Next.js middleware for the [Tollway protocol](https://tollway.dev). Automatically serves `/.well-known/tollway.json`, validates agent identity headers, enforces rate limits, and handles HTTP 402 payment flows. + +Part of the Tollway open protocol — robots.txt rebuilt for the agentic era. + +## Install + +```bash +npm install @tollway/server +``` + +## Quick Start — Express + +```ts +import express from 'express'; +import { tollwayMiddleware } from '@tollway/server'; + +const app = express(); + +app.use(tollwayMiddleware({ + policy: { + freeRequestsPerDay: 100, + trainingAllowed: false, + attributionRequired: true, + prohibitedActions: ['scrape_bulk'], + paymentRequiredActions: ['train'], + pricing: [ + { action: 'read', price: '0.001' }, + { action: 'summarize', price: '0.005' }, + { action: 'train', price: '0.05' }, + ], + }, + paymentAddress: process.env.WALLET_ADDRESS, // USDC address on Base +})); +``` + +Your policy is now live at `GET /.well-known/tollway.json`. All agent requests are validated, rate-limited, and logged automatically. + +## Quick Start — Next.js + +```ts +// middleware.ts +import { createNextjsMiddleware } from '@tollway/server'; + +const tollway = createNextjsMiddleware({ + policy: { + freeRequestsPerDay: 100, + trainingAllowed: false, + prohibitedActions: ['scrape_bulk'], + }, + paymentAddress: process.env.WALLET_ADDRESS, +}); + +export async function middleware(request: Request) { + const response = await tollway(request); + if (response) return response; // handled by Tollway (policy, 402, etc.) + // your normal middleware continues here +} + +export const config = { + matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'], +}; +``` + +## Generate `tollway.json` standalone + +No server needed — generate a static policy file to host anywhere: + +```ts +import { generateTollwayJson } from '@tollway/server'; + +const json = generateTollwayJson( + { + freeRequestsPerDay: 1000, + trainingAllowed: false, + attributionRequired: true, + prohibitedActions: ['scrape_bulk'], + }, + '0xYourWalletAddress', +); + +// Write to public/.well-known/tollway.json +``` + +## API + +### `tollwayMiddleware(options)` → Express middleware + +| Option | Type | Description | +|--------|------|-------------| +| `policy` | `ServerPolicy` | Site policy (see below) | +| `paymentAddress` | `string?` | USDC address for micropayments | +| `paymentNetwork` | `string?` | Chain (default: `"base"`) | +| `enableLogging` | `boolean?` | Log agent requests (default: `true`) | +| `onAgentRequest` | `fn?` | Callback on every verified agent request | +| `onPayment` | `fn?` | Callback on payment received | + +### `ServerPolicy` + +```ts +{ + freeRequestsPerDay?: number; // free tier before payment kicks in + pricing?: { action, price }[]; // per-action USDC prices + trainingAllowed?: boolean; + attributionRequired?: boolean; + attributionFormat?: string; // e.g. "{title} ({url})" + cacheAllowed?: boolean; + cacheTtlSeconds?: number; + minimumReputation?: number; // 0–1 + requireDid?: boolean; + allowedActions?: string[]; + prohibitedActions?: string[]; // e.g. ["scrape_bulk", "train"] + paymentRequiredActions?: string[]; + requestsPerMinute?: number; + requestsPerDay?: number; +} +``` + +### What the middleware does + +For every request: + +1. **Serves policy** — `GET /.well-known/tollway.json` returns your policy JSON +2. **Passes through** — non-agent requests (no `X-Tollway-*` headers) continue normally +3. **Validates timestamp** — rejects requests outside a ±5-minute window +4. **Checks nonce** — prevents replay attacks +5. **Verifies DID** — validates `did:key` Ed25519 signatures +6. **Enforces actions** — 403 for prohibited scopes +7. **Rate limits** — 429 per DID per minute/day +8. **Handles payment** — 402 with payment details if action requires it +9. **Attaches identity** — sets `req.tollwayIdentity` for downstream handlers +10. **Responds headers** — adds `X-Tollway-Served: 1` to responses + +### Accessing agent identity downstream + +```ts +app.get('/article', (req, res) => { + const agent = req.tollwayIdentity; // AgentIdentity | undefined + if (agent) { + console.log(agent.did, agent.purpose, agent.scope, agent.verified); + } + // ... +}); +``` + +## Production notes + +The default nonce store and rate-limit counters are **in-memory**. For multi-instance deployments, replace them with Redis. See [CONTRIBUTING.md](https://github.com/TollwayProtocol/Tollway/blob/main/CONTRIBUTING.md) for guidance. + +## Protocol + +`@tollway/server` implements the [Tollway v0.1 specification](https://github.com/TollwayProtocol/Tollway/blob/main/SPEC.md). + +- **Spec:** CC BY 4.0 +- **Code:** MIT +- **GitHub:** [TollwayProtocol/Tollway](https://github.com/TollwayProtocol/Tollway) diff --git a/packages/tollway-server/package.json b/packages/tollway-server/package.json index 4909090..8fc97a3 100644 --- a/packages/tollway-server/package.json +++ b/packages/tollway-server/package.json @@ -1,6 +1,6 @@ { "name": "@tollway/server", - "version": "0.1.1", + "version": "0.1.2", "description": "Express/Next.js middleware for the Tollway protocol — policy serving, identity validation, and payment flows", "keywords": [ "tollway", @@ -27,9 +27,18 @@ "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", + "homepage": "https://tollway.dev", + "bugs": { + "url": "https://github.com/TollwayProtocol/Tollway/issues" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/TollwayProtocol" + }, "files": [ "dist", - "LICENSE" + "LICENSE", + "README.md" ], "scripts": { "build": "tsup",