updated anthropic production no key warning message

This commit is contained in:
Wayne Sutton
2025-12-26 22:14:04 -08:00
parent 3dcdb69041
commit c312a4c808
4 changed files with 42 additions and 56 deletions

View File

@@ -86,22 +86,20 @@ Integrate AgentMail as an optional newsletter system with email subscriptions, a
flowchart TD
User[User] -->|Subscribe| NewsletterForm[NewsletterSignup Component]
NewsletterForm -->|Mutation| ConvexDB[(Convex Database)]
NewPost[New Blog Post Published] -->|Trigger| SendScript[Send Newsletter Script]
SendScript -->|Query Subscribers| ConvexDB
SendScript -->|Send Emails| AgentMail[AgentMail API]
AgentMail -->|Deliver| Subscribers[Subscriber Inboxes]
EmailIn[Email to Inbox] -->|Webhook| AgentMail
AgentMail -->|Webhook| ConvexWebhook[Convex Webhook Handler]
ConvexWebhook -->|Create Draft| ConvexDB
ContactForm[Contact Form] -->|Send Email| AgentMail
AgentMail -->|Notify| Developer[Developer Email]
```
## Implementation Steps
### Step 1: Database Schema Updates
@@ -146,8 +144,6 @@ emailDrafts: defineTable({
.index("by_createdAt", ["createdAt"]),
```
### Step 2: Site Configuration
**File:** `src/config/siteConfig.ts`Add newsletter configuration interface and default config:
@@ -166,7 +162,7 @@ export interface NewsletterConfig {
// Form field configuration
requireName: boolean; // If true, show name field; if false, email only
showNameOptional: boolean; // If true, show name as optional field
// Home page signup
home: {
enabled: boolean;
@@ -174,7 +170,7 @@ export interface NewsletterConfig {
title: string;
description: string;
};
// Blog post signup (not pages)
posts: {
enabled: boolean;
@@ -182,7 +178,7 @@ export interface NewsletterConfig {
title: string;
description: string;
};
// Dedicated newsletter page
page: {
enabled: boolean;
@@ -195,7 +191,7 @@ export interface NewsletterConfig {
// Auto-send new blog posts
autoSendNewPosts: boolean; // If true, automatically send when post published
sendOnSync: boolean; // Send during npm run sync if new post detected
// Email template
fromName: string;
fromEmail: string; // Uses inboxUsername@inboxDomain
@@ -294,8 +290,6 @@ export const siteConfig: SiteConfig = {
};
```
### Step 3: Newsletter Signup Component
**File:** `src/components/NewsletterSignup.tsx`Create reusable signup form component matching existing UI patterns:
@@ -416,22 +410,31 @@ export default function NewsletterSignup({
}
```
### Step 4: Convex Newsletter Functions
**File:** `convex/newsletter.ts`Create backend functions following Convex best practices:
```typescript
import { query, mutation, internalMutation, internalAction, action } from "./_generated/server";
import {
query,
mutation,
internalMutation,
internalAction,
action,
} from "./_generated/server";
import { v } from "convex/values";
import { internal } from "./_generated/api";
import crypto from "crypto";
// Generate unsubscribe token
function generateUnsubscribeToken(email: string): string {
const secret = process.env.UNSUBSCRIBE_SECRET || "default-secret-change-in-production";
return crypto.createHash("sha256").update(email + secret).digest("hex").substring(0, 32);
const secret =
process.env.UNSUBSCRIBE_SECRET || "default-secret-change-in-production";
return crypto
.createHash("sha256")
.update(email + secret)
.digest("hex")
.substring(0, 32);
}
// Subscribe to newsletter
@@ -508,7 +511,7 @@ export const unsubscribe = mutation({
}),
handler: async (ctx, args) => {
const email = args.email.toLowerCase().trim();
const subscriber = await ctx.db
.query("newsletterSubscribers")
.withIndex("by_email", (q) => q.eq("email", email))
@@ -584,7 +587,7 @@ export const getActiveSubscribers = internalQuery({
.query("newsletterSubscribers")
.withIndex("by_subscribed", (q) => q.eq("subscribed", true))
.collect();
return subscribers.map((sub) => ({
email: sub.email,
name: sub.name,
@@ -636,9 +639,12 @@ export const sendPostNewsletter = internalAction({
}),
handler: async (ctx, args) => {
// Check if already sent
const alreadySent = await ctx.runQuery(internal.newsletter.hasPostBeenSent, {
postSlug: args.postSlug,
});
const alreadySent = await ctx.runQuery(
internal.newsletter.hasPostBeenSent,
{
postSlug: args.postSlug,
},
);
if (alreadySent) {
return {
@@ -662,7 +668,9 @@ export const sendPostNewsletter = internalAction({
}
// Get subscribers
const subscribers = await ctx.runQuery(internal.newsletter.getActiveSubscribers);
const subscribers = await ctx.runQuery(
internal.newsletter.getActiveSubscribers,
);
if (subscribers.length === 0) {
return {
@@ -681,7 +689,7 @@ export const sendPostNewsletter = internalAction({
// Build email content
const siteUrl = process.env.SITE_URL || "https://markdown.fast";
const postUrl = `${siteUrl}/${post.slug}`;
let emailContent = `<h1>${post.title}</h1>`;
if (post.description) {
emailContent += `<p>${post.description}</p>`;
@@ -743,9 +751,9 @@ export const getPostBySlugInternal = internalQuery({
.query("posts")
.withIndex("by_slug", (q) => q.eq("slug", args.slug))
.first();
if (!post) return null;
return {
slug: post.slug,
title: post.title,
@@ -770,8 +778,6 @@ export const getPostBySlugInternal = internalQuery({
});
```
### Step 5: Newsletter Send Script
**File:** `scripts/send-newsletter.ts`Create script to send newsletters (similar to `sync-posts.ts`):
@@ -816,8 +822,6 @@ const postSlug = args[0];
sendNewsletterForPost(postSlug);
```
### Step 6: Auto-Send Integration with Sync Script
**File:** `scripts/sync-posts.ts`Modify sync script to detect new posts and auto-send if enabled:
@@ -834,9 +838,7 @@ async function checkAndSendNewPosts(
if (!autoSend) return;
// Get all synced post slugs
const syncedSlugs = syncedPosts
.filter((p) => p.published)
.map((p) => p.slug);
const syncedSlugs = syncedPosts.filter((p) => p.published).map((p) => p.slug);
// Check which posts haven't been sent yet
for (const slug of syncedSlugs) {
@@ -862,8 +864,6 @@ async function checkAndSendNewPosts(
await checkAndSendNewPosts(parsedPosts, client);
```
### Step 7: Newsletter Page
**File:** `content/pages/newsletter.md`Create dedicated newsletter signup page:
@@ -900,8 +900,6 @@ if (page && page.slug === siteConfig.newsletter.signup.page.slug) {
}
```
### Step 8: Unsubscribe Page
**File:** `src/pages/Unsubscribe.tsx`Create unsubscribe page:
@@ -973,8 +971,6 @@ export default function Unsubscribe() {
<Route path="/unsubscribe" element={<Unsubscribe />} />
```
### Step 9: Integration Points
**File:** `src/pages/Home.tsx`Add newsletter signup above footer:
@@ -1014,8 +1010,6 @@ export default function Unsubscribe() {
</footer>
```
### Step 10: Webhook Handler (Future Email-to-Post)
**File:** `convex/webhooks.ts`Create webhook handler for AgentMail events:
@@ -1030,7 +1024,7 @@ export const agentmailWebhook = httpAction(async (ctx, request) => {
// Add signature verification logic here
const body = await request.json();
// Handle different event types
if (body.type === "message.received") {
// Process incoming email for email-to-post workflow
@@ -1068,7 +1062,7 @@ export const handleIncomingEmail = internalMutation({
const subjectLower = args.subject.toLowerCase();
const isDraft = subjectLower.includes("[draft]");
const isPublish = subjectLower.includes("[publish]");
const status = isPublish ? "published" : isDraft ? "draft" : "draft";
// Create draft post
@@ -1097,8 +1091,6 @@ http.route({
});
```
### Step 11: Package.json and Environment Variables
**File:** `package.json`Add newsletter scripts:
@@ -1124,8 +1116,6 @@ AGENTMAIL_FROM_EMAIL=newsletter@agentmail.to
UNSUBSCRIBE_SECRET=change-this-in-production
```
### Step 12: CSS Styling
**File:** `src/styles/global.css`Add newsletter component styles matching existing theme:
@@ -1213,8 +1203,6 @@ UNSUBSCRIBE_SECRET=change-this-in-production
}
```
### Step 13: Fork Configuration
**File:** `fork-config.json.example`Add newsletter configuration:
@@ -1274,8 +1262,6 @@ The newsletter feature is optional and disabled by default. To enable:
See `prds/agentmailplan-v1.md` for full documentation.
```
## Future Features (Not in Initial Implementation)
These features are planned but not included in steps 1-11:
@@ -1298,4 +1284,4 @@ These can be added incrementally after the core newsletter functionality is work
- [ ] Subscription saves to Convex database
- [ ] Unsubscribe link works with token verification
- [ ] `npm run newsletter:send -- <slug>` sends email to all subscribers
- [ ] Auto-send works during `npm run sync` if enabled
- [ ] Auto-send works during `npm run sync` if enabled

View File

@@ -22,7 +22,7 @@ Your content is instantly available to browsers, LLMs, and AI agents.. Write mar
- **Total Posts**: 12
- **Total Pages**: 4
- **Latest Post**: 2025-12-25
- **Last Updated**: 2025-12-26T20:30:35.290Z
- **Last Updated**: 2025-12-27T06:13:31.118Z
## Tech stack

View File

@@ -109,7 +109,7 @@ export const generateResponse = action({
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) {
const notConfiguredMessage =
"**AI chat is not configured.**\n\n" +
"**AI chat is not configured on production.**\n\n" +
"To enable AI responses, add your `ANTHROPIC_API_KEY` to the Convex environment variables.\n\n" +
"**Setup steps:**\n" +
"1. Get an API key from [Anthropic Console](https://console.anthropic.com/)\n" +

View File

@@ -1,6 +1,6 @@
# llms.txt - Information for AI assistants and LLMs
# Learn more: https://llmstxt.org/
# Last updated: 2025-12-26T20:30:35.292Z
# Last updated: 2025-12-27T06:13:31.119Z
> Your content is instantly available to browsers, LLMs, and AI agents.