diff --git a/bun.lock b/bun.lock index 5d0430e..ee1e0bb 100644 --- a/bun.lock +++ b/bun.lock @@ -12,7 +12,7 @@ }, "devDependencies": { "@convex-dev/auth": "0.0.95", - "@hraness/relay": "github:hraness/relay#2558a0d860d35ec2537cc135380ea4bd89db1c8f", + "@hraness/relay": "github:hraness/relay#5ef01b0613ac49c4da0fcb8d2ee81e667c592992", "@types/bun": "1.4.2", "@types/node": "26.6.2", "convex": "1.45.0", @@ -105,7 +105,7 @@ "@hono/node-server": ["@hono/node-server@2.1.1", "", { "peerDependencies": { "hono": "^4" } }, "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg=="], - "@hraness/relay": ["@hraness/relay@github:hraness/relay#2558a0d", { "dependencies": { "@convex-dev/auth": "0.0.95" }, "peerDependencies": { "convex": ">=1.44.0" } }, "hraness-relay-2558a0d", "sha512-p7Rcth6p8m9WbW5IZzCP0jBEa6Ies3347zBUOfqvbp+fZseuEn/mRyqh0/2dUdntSkK6XxRcR4sZwD1lQhROXw=="], + "@hraness/relay": ["@hraness/relay@github:hraness/relay#5ef01b0", { "dependencies": { "@convex-dev/auth": "0.0.95" }, "peerDependencies": { "convex": ">=1.44.0" } }, "hraness-relay-5ef01b0", "sha512-nYnKFBdq3MpFceto71UwjPNEULS/aY5T9GLgpkj0GCaxRAkqRwysXFnipACwstr6kSKFMFjdDfkgYesAKVnLxw=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.30.0", "", { "dependencies": { "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA=="], diff --git a/convex/relay.ts b/convex/relay.ts index 6641be9..3b3cbd5 100644 --- a/convex/relay.ts +++ b/convex/relay.ts @@ -5,9 +5,8 @@ * The bootstrap token lives in `XCB_RELAY_BOOTSTRAP` on the deployment and * admits the first owner exactly once — it dies the moment a subject * verifies. OTP delivery defaults to `log`; `XCB_RELAY_EMAIL=resend` uses - * Resend via `XCB_RESEND_API_KEY` / `XCB_RESEND_FROM`, `sendgrid` uses the - * SendGrid v3 API via `XCB_SENDGRID_API_KEY` / `XCB_SENDGRID_FROM`, and - * `webhook` POSTs the code to `XCB_OTP_WEBHOOK_URL` with bearer + * Resend via `XCB_RESEND_API_KEY` / `XCB_RESEND_FROM`, and `webhook` + * POSTs the code to `XCB_OTP_WEBHOOK_URL` with bearer * `XCB_OTP_WEBHOOK_TOKEN`. */ import { defineRelay } from "@hraness/relay/backend"; @@ -15,11 +14,9 @@ import type { EmailTransport } from "@hraness/relay/wire"; const email: EmailTransport = process.env.XCB_RELAY_EMAIL === "resend" ? { mode: "resend", keyEnv: "XCB_RESEND_API_KEY", fromEnv: "XCB_RESEND_FROM" } - : process.env.XCB_RELAY_EMAIL === "sendgrid" - ? { mode: "sendgrid", keyEnv: "XCB_SENDGRID_API_KEY", fromEnv: "XCB_SENDGRID_FROM" } - : process.env.XCB_RELAY_EMAIL === "webhook" - ? { mode: "webhook", urlEnv: "XCB_OTP_WEBHOOK_URL", tokenEnv: "XCB_OTP_WEBHOOK_TOKEN" } - : { mode: "log" }; + : process.env.XCB_RELAY_EMAIL === "webhook" + ? { mode: "webhook", urlEnv: "XCB_OTP_WEBHOOK_URL", tokenEnv: "XCB_OTP_WEBHOOK_TOKEN" } + : { mode: "log" }; export const relay = defineRelay({ namespace: "xcb.relay.v1", @@ -37,4 +34,5 @@ export const relay = defineRelay({ openSignup: false, bootstrapInviteEnv: "XCB_RELAY_BOOTSTRAP", authProviderId: "xcb-otp-v1", + productName: "xcb", }); diff --git a/docs/relay-deployment.md b/docs/relay-deployment.md index 064a097..045a0f6 100644 --- a/docs/relay-deployment.md +++ b/docs/relay-deployment.md @@ -23,9 +23,9 @@ Set the relay's environment with `npx convex env set `: forced refresh signs a new session, and the call retries. - `XCB_RELAY_BOOTSTRAP`: a one-time invite for the first owner. It stops working once an owner is verified; set a fresh value only when rebuilding a fleet. -- `XCB_RELAY_EMAIL`: how sign-in codes are delivered: `log`, `sendgrid`, - `resend`, or `webhook`. `sendgrid` needs `XCB_SENDGRID_API_KEY` and - `XCB_SENDGRID_FROM` (a verified sender); `resend` needs `XCB_RESEND_API_KEY` - and `XCB_RESEND_FROM`; `webhook` needs `XCB_OTP_WEBHOOK_URL` and - `XCB_OTP_WEBHOOK_TOKEN`. With `log`, codes are printed to the function log, - which you read from an authenticated Convex session with `npx convex logs`. +- `XCB_RELAY_EMAIL`: how sign-in codes are delivered: `log`, `resend`, or + `webhook`. `resend` needs `XCB_RESEND_API_KEY` and `XCB_RESEND_FROM` (a + branded sender on a verified domain, e.g. `xcb `); + `webhook` needs `XCB_OTP_WEBHOOK_URL` and `XCB_OTP_WEBHOOK_TOKEN`. With + `log`, codes are printed to the function log, which you read from an + authenticated Convex session with `npx convex logs`. diff --git a/package.json b/package.json index 5600c2d..8942471 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ }, "devDependencies": { "@convex-dev/auth": "0.0.95", - "@hraness/relay": "github:hraness/relay#2558a0d860d35ec2537cc135380ea4bd89db1c8f", + "@hraness/relay": "github:hraness/relay#5ef01b0613ac49c4da0fcb8d2ee81e667c592992", "@types/bun": "1.4.2", "@types/node": "26.6.2", "convex": "1.45.0",