diff --git a/AGENTS.md b/AGENTS.md index 7e3807f..0a69e3d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,7 +62,6 @@ The auth server currently needs messaging support for exactly these flows: - email OTP - SMS OTP - magic link email -- bootstrap invite email Treat those as the primary domain API for `0.1.0`. @@ -106,7 +105,7 @@ Keep the first release intentionally narrow. - a provider-agnostic core package - AWS email and SMS support - Twilio SMS support -- the four auth flows already used by SeamlessAuth +- the three auth flows already used by SeamlessAuth - docs and examples that show how an adopter API should consume the package ### Out of scope @@ -133,7 +132,6 @@ Bias toward APIs that would let the auth server keep call sites similar to: - `sendOtpEmail(...)` - `sendOtpSms(...)` - `sendMagicLinkEmail(...)` -- `sendBootstrapInviteEmail(...)` ## Style Guidance diff --git a/README.md b/README.md index 93c05cd..48cebb1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ It gives SeamlessAuth a small, explicit way to deliver auth emails and SMS witho For `0.1.0`, the scope is intentionally narrow: - TypeScript packages only -- the four auth flows already used by SeamlessAuth +- the three auth flows already used by SeamlessAuth - AWS SES email - AWS SNS SMS - Twilio SMS @@ -25,7 +25,6 @@ SeamlessAuth needs to send exactly these auth-related messages today: - email OTP - SMS OTP - magic link email -- bootstrap invite email This repo packages that responsibility into: @@ -51,7 +50,6 @@ The core service keeps the auth-domain API small: - `sendOtpEmail(...)` - `sendOtpSms(...)` - `sendMagicLinkEmail(...)` -- `sendBootstrapInviteEmail(...)` ## Install diff --git a/docs/adopter-user-story.md b/docs/adopter-user-story.md index 407d617..8ad66dc 100644 --- a/docs/adopter-user-story.md +++ b/docs/adopter-user-story.md @@ -37,7 +37,6 @@ The intended flow is: - OTP email - OTP SMS - magic link email - - bootstrap invite email 5. SeamlessAuth delivers a good default experience without forcing the adopter to own message rendering. ## Why This Model Works diff --git a/docs/architecture.md b/docs/architecture.md index 9bf5bee..d3fd5b4 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -6,12 +6,11 @@ Provide a public auth-messaging package system for SeamlessAuth that sits behind ## Product Boundary -SeamlessAuth currently needs messaging support for four auth workflows: +SeamlessAuth currently needs messaging support for three auth workflows: - OTP email - OTP SMS - magic link email -- bootstrap invite email That is the right boundary for this repo. It should stay focused on auth delivery, not expand into a generic notification platform. @@ -112,7 +111,6 @@ Public operations: - `sendOtpEmail` - `sendOtpSms` - `sendMagicLinkEmail` -- `sendBootstrapInviteEmail` This keeps the API aligned with current SeamlessAuth responsibilities. diff --git a/docs/provider-model.md b/docs/provider-model.md index cc5bf5a..9aad07c 100644 --- a/docs/provider-model.md +++ b/docs/provider-model.md @@ -20,12 +20,11 @@ The provider model should separate: ## Launch Matrix -| Flow | Channel | AWS | Twilio | -| ---------------- | ------- | --- | ------ | -| Email OTP | Email | Yes | No | -| SMS OTP | SMS | Yes | Yes | -| Magic link | Email | Yes | No | -| Bootstrap invite | Email | Yes | No | +| Flow | Channel | AWS | Twilio | +| ---------- | ------- | --- | ------ | +| Email OTP | Email | Yes | No | +| SMS OTP | SMS | Yes | Yes | +| Magic link | Email | Yes | No | This is why a channel-based composition model is safer than a single `provider: "aws" | "twilio"` switch. @@ -46,14 +45,12 @@ export interface AuthMessagingHandlers { sendOtpEmail?: (input: SendOtpEmailInput) => Promise; sendOtpSms?: (input: SendOtpSmsInput) => Promise; sendMagicLinkEmail?: (input: SendMagicLinkEmailInput) => Promise; - sendBootstrapInviteEmail?: (input: SendBootstrapInviteEmailInput) => Promise; } export interface AuthMessagingService { sendOtpEmail(input: SendOtpEmailInput): Promise; sendOtpSms(input: SendOtpSmsInput): Promise; sendMagicLinkEmail(input: SendMagicLinkEmailInput): Promise; - sendBootstrapInviteEmail(input: SendBootstrapInviteEmailInput): Promise; } ``` @@ -96,7 +93,6 @@ Today that means: - OTP email subject/body - OTP SMS body - magic link email subject/body -- bootstrap invite email subject/body Transports deliver rendered content. They do not own auth business logic. diff --git a/docs/roadmap.md b/docs/roadmap.md index 0e8b25d..964d253 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -40,7 +40,7 @@ Ship and stabilize a realistic `0.1.0` for TypeScript users integrating Seamless - TypeScript packages publishable to npm - official support for AWS email/SMS and Twilio SMS -- support for the four current SeamlessAuth message flows +- support for the three current SeamlessAuth message flows - documented integration path for SeamlessAuth server-side adapters - tests for core logic and provider adapters - README and package docs that make setup understandable without reading source diff --git a/examples/seamless-review-api/src/localSmoke.ts b/examples/seamless-review-api/src/localSmoke.ts index 345776b..f24abe4 100644 --- a/examples/seamless-review-api/src/localSmoke.ts +++ b/examples/seamless-review-api/src/localSmoke.ts @@ -48,11 +48,6 @@ async function main() { to: "reviewer@example.com", magicLinkUrl: "https://review.example.com/verify-magic-link?token=xyz", }); - - await authMessaging.sendBootstrapInviteEmail({ - to: "admin@example.com", - inviteUrl: "https://review.example.com/login?bootstrapToken=bootstrap-token", - }); } void main(); diff --git a/examples/seamless-review-api/src/withAuthMessageAudit.ts b/examples/seamless-review-api/src/withAuthMessageAudit.ts index 2e2673c..04dd4ec 100644 --- a/examples/seamless-review-api/src/withAuthMessageAudit.ts +++ b/examples/seamless-review-api/src/withAuthMessageAudit.ts @@ -1,6 +1,5 @@ import type { MessagingClient, - SendBootstrapInviteEmailInput, SendMagicLinkEmailInput, SendOtpEmailInput, SendOtpSmsInput, @@ -32,15 +31,7 @@ export type AuthMessageAuditEntry = messageId?: string; } | { - operation: "sendBootstrapInviteEmail"; - status: "sent"; - to: string; - provider: string; - channel: "email" | "sms"; - messageId?: string; - } - | { - operation: "sendOtpEmail" | "sendOtpSms" | "sendMagicLinkEmail" | "sendBootstrapInviteEmail"; + operation: "sendOtpEmail" | "sendOtpSms" | "sendMagicLinkEmail"; status: "failed"; to: string; error: unknown; @@ -115,16 +106,5 @@ export function withAuthMessageAudit( throw error; } }, - - async sendBootstrapInviteEmail(input: SendBootstrapInviteEmailInput) { - try { - const result = await messaging.sendBootstrapInviteEmail(input); - await auditSuccess(audit, "sendBootstrapInviteEmail", input.to, result); - return result; - } catch (error) { - await auditFailure(audit, "sendBootstrapInviteEmail", input.to, error); - throw error; - } - }, }; } diff --git a/packages/core/README.md b/packages/core/README.md index 6998ba3..1809349 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -7,7 +7,6 @@ This package owns the shared messaging contracts and the auth-focused service su - OTP email - OTP SMS - magic link email -- bootstrap invite email It exposes: diff --git a/packages/core/src/messages.ts b/packages/core/src/messages.ts index 6fae3e5..7602d28 100644 --- a/packages/core/src/messages.ts +++ b/packages/core/src/messages.ts @@ -18,10 +18,3 @@ export interface SendMagicLinkEmailInput { from?: string; subject?: string; } - -export interface SendBootstrapInviteEmailInput { - to: string; - inviteUrl: string; - from?: string; - subject?: string; -} diff --git a/packages/core/src/service.ts b/packages/core/src/service.ts index 2d9323c..6340246 100644 --- a/packages/core/src/service.ts +++ b/packages/core/src/service.ts @@ -69,25 +69,6 @@ function buildMagicLinkHtml(appName: string, magicLinkUrl: string): string { ].join("\n"); } -function buildBootstrapInviteText(appName: string, inviteUrl: string): string { - return [ - `You have been invited to bootstrap ${appName}.`, - "", - "Use the link below to continue:", - inviteUrl, - ].join("\n"); -} - -function buildBootstrapInviteHtml(appName: string, inviteUrl: string): string { - return [ - "
", - `

Bootstrap invite for ${appName}

`, - "

Use the link below to continue:

", - `

${inviteUrl}

`, - "
", - ].join("\n"); -} - function buildOtpSmsText(appName: string, token: string | number): string { return `Your ${appName} verification code is: ${token}. No one will ever ask you for this code. Do not share it.`; } @@ -207,34 +188,6 @@ export function createAuthMessagingService( return email.send(message); }, - - async sendBootstrapInviteEmail(input) { - if (handlers?.sendBootstrapInviteEmail) { - return handlers.sendBootstrapInviteEmail(input); - } - - if (!email) { - throw new UnsupportedChannelError("email"); - } - - assertLikelyEmail(input.to, "input.to"); - assertLikelyUrl(input.inviteUrl, "input.inviteUrl"); - - const message = applyEmailOverride( - overrides?.bootstrapInviteEmail, - input, - { - to: input.to, - from: input.from ?? defaults?.emailFrom, - subject: input.subject ?? `${appName} - Bootstrap invite`, - text: buildBootstrapInviteText(appName, input.inviteUrl), - html: buildBootstrapInviteHtml(appName, input.inviteUrl), - }, - context, - ); - - return email.send(message); - }, }; } diff --git a/packages/core/src/transports.ts b/packages/core/src/transports.ts index 06da7d5..1f56964 100644 --- a/packages/core/src/transports.ts +++ b/packages/core/src/transports.ts @@ -1,9 +1,4 @@ -import type { - SendBootstrapInviteEmailInput, - SendMagicLinkEmailInput, - SendOtpEmailInput, - SendOtpSmsInput, -} from "./messages.js"; +import type { SendMagicLinkEmailInput, SendOtpEmailInput, SendOtpSmsInput } from "./messages.js"; import type { DeliveryResult, EmailMessage, SmsMessage } from "./types.js"; export interface EmailTransport { @@ -20,7 +15,6 @@ export interface AuthMessagingHandlers { sendOtpEmail(input: SendOtpEmailInput): Promise; sendOtpSms(input: SendOtpSmsInput): Promise; sendMagicLinkEmail(input: SendMagicLinkEmailInput): Promise; - sendBootstrapInviteEmail(input: SendBootstrapInviteEmailInput): Promise; } export interface AuthMessageOverrideContext { @@ -43,18 +37,12 @@ export interface AuthMessageOverrides { defaults: EmailMessage, context: AuthMessageOverrideContext, ) => EmailMessage; - bootstrapInviteEmail?: ( - input: SendBootstrapInviteEmailInput, - defaults: EmailMessage, - context: AuthMessageOverrideContext, - ) => EmailMessage; } export interface AuthMessagingService { sendOtpEmail(input: SendOtpEmailInput): Promise; sendOtpSms(input: SendOtpSmsInput): Promise; sendMagicLinkEmail(input: SendMagicLinkEmailInput): Promise; - sendBootstrapInviteEmail(input: SendBootstrapInviteEmailInput): Promise; } export type EmailProvider = EmailTransport;