diff --git a/README.md b/README.md index 4440e63..2b61e84 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,22 @@ one sync run stripe --full-refresh Change hooks (`onInsert`, `onUpdate`, `onChange`) fire per-page during sync — pipe to a shell command, a flow, or an event log. Root-array responses (e.g. Hacker News `/v0/topstories.json` → `[9129911, 9129199, ...]`) are supported by setting `resultsPath` to `""`, `"$"`, or `"."`; primitive elements are auto-wrapped as `{ [idField]: value }`. Run `one guide sync` for the full reference. +### `one relay` + +Receive webhooks from platforms and forward them to any connected platform via passthrough actions. + +```bash +one relay platforms # List relay-capable platforms + event type counts +one relay event-types # List supported event types for a platform +one relay create --connection-key --create-webhook --event-filters '["event.type"]' +one relay activate --actions '' # Attach passthrough forwarding actions +one relay list # List existing relay endpoints +one relay events --platform

# Inspect received events +one relay deliveries --endpoint-id # Check delivery status +``` + +Start with `one relay platforms` to discover which platforms support relay at all, then drill into `event-types ` for the specific events. Run `one guide relay` for the full reference including `--metadata` requirements per platform. + ### `one guide [topic]` Get the full CLI usage guide, designed for AI agents that only have the binary (no MCP, no IDE skills). diff --git a/package-lock.json b/package-lock.json index 96c8a0b..8deac9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@withone/cli", - "version": "1.41.0", + "version": "1.42.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@withone/cli", - "version": "1.41.0", + "version": "1.42.0", "dependencies": { "@clack/prompts": "^0.9.1", "commander": "^13.1.0", @@ -1210,6 +1210,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -1593,6 +1594,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -2144,6 +2146,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 0792608..36ffeb0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@withone/cli", - "version": "1.41.0", + "version": "1.42.0", "description": "CLI for managing One", "type": "module", "files": [ diff --git a/skills/one/references/relay.md b/skills/one/references/relay.md index 40ff15c..90bd370 100644 --- a/skills/one/references/relay.md +++ b/skills/one/references/relay.md @@ -16,6 +16,14 @@ one --agent connection list Identify source (sends webhooks) and destination (receives forwarded data). Note both connection keys. +If you're unsure whether the source platform supports relay at all, list relay-capable platforms first: + +```bash +one --agent relay platforms +``` + +This returns `[{ "platform": "", "eventTypeCount": }, ...]` for every platform that One can receive webhooks from. If your source isn't in the list, relay won't work for it. + ### Step 2: Get event types ```bash @@ -173,6 +181,13 @@ one --agent relay activate --actions '[{ }]' ``` +## Discovery Commands + +```bash +one --agent relay platforms # All relay-capable platforms + event type counts +one --agent relay event-types # Event types for a specific platform +``` + ## Management Commands ```bash diff --git a/src/commands/relay.ts b/src/commands/relay.ts index 638a01a..30b116e 100644 --- a/src/commands/relay.ts +++ b/src/commands/relay.ts @@ -422,6 +422,47 @@ export async function relayDeliveriesCommand(options: { } } +export async function relayPlatformsCommand(): Promise { + const { apiKey } = getConfig(); + const api = new OneApi(apiKey, getApiBase()); + const spinner = output.createSpinner(); + spinner.start('Loading relay-capable platforms...'); + + try { + const platforms = await api.listRelayPlatforms(); + + if (output.isAgentMode()) { + output.json({ platforms }); + return; + } + + spinner.stop(`${platforms.length} relay-capable platform${platforms.length === 1 ? '' : 's'} found`); + + if (platforms.length === 0) { + console.log('\n No relay-capable platforms available.\n'); + return; + } + + console.log(); + printTable( + [ + { key: 'platform', label: 'Platform' }, + { key: 'eventTypeCount', label: 'Event types', color: pc.dim }, + ], + platforms.map(p => ({ platform: p.platform, eventTypeCount: String(p.eventTypeCount) })) + ); + console.log(); + console.log( + pc.dim( + ` Run ${pc.cyan('one relay event-types ')} to see the full event list for a platform.\n` + ) + ); + } catch (error) { + spinner.stop('Failed to load relay platforms'); + output.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); + } +} + export async function relayEventTypesCommand(platform: string): Promise { const { apiKey } = getConfig(); const api = new OneApi(apiKey, getApiBase()); diff --git a/src/index.ts b/src/index.ts index 5bc0e00..0cc236b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ import { relayEventGetCommand, relayDeliveriesCommand, relayEventTypesCommand, + relayPlatformsCommand, } from './commands/relay.js'; import { registerSyncCommands } from './lib/sync/index.js'; @@ -103,6 +104,7 @@ program one cache update-all Re-fetch fresh data for all cached entries Webhook Relay: + one relay platforms List platforms that support relay + event type counts one relay create Create a relay endpoint for a connection one relay list List relay endpoints one relay activate Activate with passthrough actions @@ -642,6 +644,13 @@ relay await relayEventTypesCommand(platform); }); +relay + .command('platforms') + .description('List all platforms that support webhook relay, with their event type counts') + .action(async () => { + await relayPlatformsCommand(); + }); + // ── Sync Commands ── diff --git a/src/lib/api.ts b/src/lib/api.ts index 404e6fa..523670e 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -579,6 +579,10 @@ export class OneApi { return this.requestFull({ path: '/webhooks/relay/event-types', queryParams: { platform } }); } + async listRelayPlatforms(): Promise> { + return this.requestFull({ path: '/webhooks/relay/platforms' }); + } + async waitForConnection( platform: string, diff --git a/src/lib/guide-content.ts b/src/lib/guide-content.ts index 09cc412..543a7f1 100644 --- a/src/lib/guide-content.ts +++ b/src/lib/guide-content.ts @@ -78,6 +78,7 @@ Receive webhooks from platforms (Stripe, GitHub, Airtable, Attio, Google Calenda **Quick start:** \`\`\`bash +one --agent relay platforms # See relay-capable platforms one --agent relay event-types # See available events one --agent relay create --connection-key --create-webhook --event-filters '["event.type"]' one --agent relay activate --actions '[{"type":"passthrough","actionId":"...","connectionKey":"...","body":{...}}]' @@ -228,6 +229,7 @@ Webhook relay receives events from platforms (Stripe, GitHub, Airtable, Attio, G ## Commands \`\`\`bash +one --agent relay platforms # List relay-capable platforms + event type counts one --agent relay event-types # List available events one --agent relay create --connection-key --create-webhook --event-filters '["event.type"]' one --agent relay activate --actions '' # Add forwarding actions @@ -242,7 +244,7 @@ one --agent relay deliveries --endpoint-id # Check delivery status ## Building a Relay -1. **Discover connections** — identify source and destination platforms +1. **Discover connections** — identify source and destination platforms. Use \`one --agent relay platforms\` to see which platforms support relay at all before digging into a specific one. 2. **Get event types** — \`one --agent relay event-types \` 3. **Get source knowledge** — understand the incoming webhook payload shape (\`{{payload.*}}\` paths) 4. **Get destination knowledge** — understand the outgoing API body shape diff --git a/src/lib/sync/index.ts b/src/lib/sync/index.ts index e6ee7af..c600c18 100644 --- a/src/lib/sync/index.ts +++ b/src/lib/sync/index.ts @@ -1,7 +1,7 @@ import type { Command } from 'commander'; import * as output from '../output.js'; import { OneApi } from '../api.js'; -import { getApiKey, getAccessControlFromAllSources } from '../config.js'; +import { getApiKey, getApiBase, getAccessControlFromAllSources } from '../config.js'; import { discoverModels } from './models.js'; import { readProfile, writeProfile, writeDraftProfile, listProfiles, generateTemplate } from './profile.js'; import { syncModel } from './runner.js'; @@ -122,7 +122,7 @@ function getApi(): OneApi { if (!apiKey) { output.error('No API key configured. Run "one init" first.'); } - return new OneApi(apiKey); + return new OneApi(apiKey!, getApiBase()); } // ── sync profiles (built-in) ──