autoblogger 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +433 -68
- package/dist/index.d.mts +132 -24
- package/dist/index.d.ts +132 -24
- package/dist/index.js +259 -245
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -245
- package/dist/index.mjs.map +1 -1
- package/dist/ui.d.mts +0 -1
- package/dist/ui.d.ts +0 -1
- package/dist/ui.js +877 -782
- package/dist/ui.js.map +1 -1
- package/dist/ui.mjs +689 -594
- package/dist/ui.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,164 +1,529 @@
|
|
|
1
1
|
# Autoblogger
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/autoblogger)
|
|
4
|
+
[](https://github.com/hrosenblume/autoblogger/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
A complete content management system that embeds into your Next.js app. Write blog posts with AI assistance, manage revisions, handle comments, and auto-generate drafts from RSS feeds—all from a dashboard that lives inside your existing application.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install autoblogger
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What is Autoblogger?
|
|
15
|
+
|
|
16
|
+
Autoblogger is an **embeddable CMS package**. Instead of running a separate blog platform like WordPress or Ghost, you install Autoblogger as an npm package and mount it inside your Next.js app. It becomes part of your application—using your database, your auth system, and your hosting.
|
|
17
|
+
|
|
18
|
+
**This is not a standalone application.** It's a library that provides:
|
|
19
|
+
|
|
20
|
+
1. **A React dashboard** — A full writer/admin interface you mount at a route like `/writer`
|
|
21
|
+
2. **API handlers** — RESTful endpoints you mount at a route like `/api/cms`
|
|
22
|
+
3. **Data utilities** — Functions to query posts, render markdown, generate SEO metadata
|
|
23
|
+
|
|
24
|
+
You keep full control. Autoblogger uses your Prisma client, respects your auth, and stores everything in your database.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Who is this for?
|
|
29
|
+
|
|
30
|
+
- **Developers building blogs** who want a writing dashboard without building one from scratch
|
|
31
|
+
- **Teams** who need collaborative editing with comments and revision history
|
|
32
|
+
- **AI-assisted writers** who want to generate drafts with Claude or GPT
|
|
33
|
+
- **Content aggregators** who want to auto-draft posts from RSS feeds
|
|
34
|
+
|
|
35
|
+
---
|
|
4
36
|
|
|
5
37
|
## Features
|
|
6
38
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
39
|
+
| Feature | Description |
|
|
40
|
+
|---------|-------------|
|
|
41
|
+
| **AI Writing** | Generate essays with Claude or GPT. Stream responses in real-time. Chat to refine your content. |
|
|
42
|
+
| **WYSIWYG Editor** | Tiptap-based editor with formatting toolbar. Syncs to markdown for storage. |
|
|
43
|
+
| **Revision History** | Every save creates a revision. Browse and restore any previous version. |
|
|
44
|
+
| **Inline Comments** | Highlight text and leave comments. Reply in threads. Resolve when done. |
|
|
45
|
+
| **RSS Auto-Draft** | Subscribe to RSS feeds. Filter articles by keywords. Auto-generate draft posts from news. |
|
|
46
|
+
| **Tag Management** | Organize posts with tags. Bulk edit from the settings panel. |
|
|
47
|
+
| **User Roles** | Admin, writer, and drafter roles with different permissions. |
|
|
48
|
+
| **SEO Fields** | Custom title, description, keywords, and OG image per post. |
|
|
49
|
+
| **Preview Links** | Generate expiring preview URLs for unpublished drafts. |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Requirements
|
|
54
|
+
|
|
55
|
+
Before installing, make sure you have:
|
|
56
|
+
|
|
57
|
+
- **Next.js 14 or 15** (App Router)
|
|
58
|
+
- **React 18 or 19**
|
|
59
|
+
- **Prisma 5 or 6** with a configured database
|
|
60
|
+
- **Node.js 20+**
|
|
61
|
+
|
|
62
|
+
You'll also need API keys if you want AI features:
|
|
63
|
+
|
|
64
|
+
- **Anthropic API key** for Claude models
|
|
65
|
+
- **OpenAI API key** for GPT models
|
|
66
|
+
|
|
67
|
+
---
|
|
12
68
|
|
|
13
69
|
## Installation
|
|
14
70
|
|
|
71
|
+
### Step 1: Install the package
|
|
72
|
+
|
|
15
73
|
```bash
|
|
16
74
|
npm install autoblogger
|
|
17
75
|
```
|
|
18
76
|
|
|
19
|
-
|
|
77
|
+
This installs Autoblogger and its dependencies (Tiptap editor, AI SDKs, markdown utilities).
|
|
78
|
+
|
|
79
|
+
### Step 2: Add the database models
|
|
80
|
+
|
|
81
|
+
Autoblogger needs several tables in your database. Copy the models from the package's schema file into your own Prisma schema.
|
|
82
|
+
|
|
83
|
+
**Option A: Copy the file and merge manually**
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# View the schema
|
|
87
|
+
cat node_modules/autoblogger/prisma/schema.prisma
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Then copy the models (Post, Revision, Comment, User, Tag, etc.) into your `prisma/schema.prisma`.
|
|
91
|
+
|
|
92
|
+
**Option B: If starting fresh, use it directly**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
cp node_modules/autoblogger/prisma/schema.prisma ./prisma/schema.prisma
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The required models are:
|
|
99
|
+
|
|
100
|
+
| Model | Purpose |
|
|
101
|
+
|-------|---------|
|
|
102
|
+
| `Post` | Blog posts with title, markdown content, status, SEO fields |
|
|
103
|
+
| `Revision` | Version history for posts |
|
|
104
|
+
| `Comment` | Inline editor comments with threading |
|
|
105
|
+
| `User` | CMS users with roles (admin, writer, drafter) |
|
|
106
|
+
| `Tag` | Tags for organizing posts |
|
|
107
|
+
| `PostTag` | Many-to-many relation between posts and tags |
|
|
108
|
+
| `AISettings` | AI model preferences and prompt templates |
|
|
109
|
+
| `IntegrationSettings` | Feature flags like auto-draft enabled |
|
|
110
|
+
| `TopicSubscription` | RSS feed subscriptions for auto-drafting |
|
|
111
|
+
| `NewsItem` | Individual RSS items fetched from subscriptions |
|
|
112
|
+
|
|
113
|
+
### Step 3: Run the migration
|
|
20
114
|
|
|
21
|
-
|
|
115
|
+
After adding the models to your schema:
|
|
22
116
|
|
|
23
117
|
```bash
|
|
24
|
-
cp node_modules/autoblogger/prisma/schema.prisma ./prisma/
|
|
25
118
|
npx prisma migrate dev --name add-autoblogger
|
|
26
119
|
```
|
|
27
120
|
|
|
28
|
-
|
|
121
|
+
This creates the tables in your database.
|
|
122
|
+
|
|
123
|
+
### Step 4: Generate the Prisma client
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx prisma generate
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Configuration
|
|
132
|
+
|
|
133
|
+
Create a configuration file that sets up Autoblogger with your app's Prisma client and auth:
|
|
29
134
|
|
|
30
135
|
```typescript
|
|
31
136
|
// lib/cms.ts
|
|
32
137
|
import { createAutoblogger } from 'autoblogger'
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
138
|
+
import { prisma } from '@/lib/db' // Your Prisma client
|
|
139
|
+
import { auth } from '@/lib/auth' // Your auth function (e.g., NextAuth)
|
|
35
140
|
|
|
36
141
|
export const cms = createAutoblogger({
|
|
142
|
+
// Required: Your Prisma client instance
|
|
37
143
|
prisma,
|
|
38
144
|
|
|
145
|
+
// Required: Authentication configuration
|
|
39
146
|
auth: {
|
|
40
|
-
|
|
147
|
+
// Function that returns the current session/user
|
|
148
|
+
getSession: () => auth(),
|
|
149
|
+
|
|
150
|
+
// Check if user is an admin (can access settings, manage users)
|
|
41
151
|
isAdmin: (session) => session?.user?.role === 'admin',
|
|
152
|
+
|
|
153
|
+
// Check if user can publish posts (admins and writers can, drafters can't)
|
|
42
154
|
canPublish: (session) => ['admin', 'writer'].includes(session?.user?.role ?? ''),
|
|
43
155
|
},
|
|
44
156
|
|
|
157
|
+
// Optional: AI configuration
|
|
45
158
|
ai: {
|
|
46
159
|
anthropicKey: process.env.ANTHROPIC_API_KEY,
|
|
47
160
|
openaiKey: process.env.OPENAI_API_KEY,
|
|
48
161
|
},
|
|
49
162
|
|
|
163
|
+
// Optional: File upload handler
|
|
50
164
|
storage: {
|
|
51
|
-
upload: async (file) => {
|
|
52
|
-
//
|
|
53
|
-
|
|
165
|
+
upload: async (file: File) => {
|
|
166
|
+
// Implement your upload logic here (S3, Cloudflare R2, Vercel Blob, etc.)
|
|
167
|
+
// Return an object with the public URL
|
|
168
|
+
const url = await uploadToYourStorage(file)
|
|
169
|
+
return { url }
|
|
54
170
|
}
|
|
55
171
|
},
|
|
56
|
-
|
|
57
|
-
styles: {
|
|
58
|
-
container: 'max-w-2xl mx-auto px-6',
|
|
59
|
-
title: 'text-2xl font-bold',
|
|
60
|
-
prose: 'prose dark:prose-invert max-w-none',
|
|
61
|
-
},
|
|
62
172
|
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Environment Variables
|
|
176
|
+
|
|
177
|
+
Add these to your `.env.local`:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Database (you probably already have this)
|
|
181
|
+
DATABASE_URL="postgresql://..."
|
|
63
182
|
|
|
64
|
-
|
|
183
|
+
# AI API keys (optional, only needed for AI features)
|
|
184
|
+
ANTHROPIC_API_KEY="sk-ant-..."
|
|
185
|
+
OPENAI_API_KEY="sk-..."
|
|
65
186
|
```
|
|
66
187
|
|
|
67
|
-
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Mounting the API
|
|
191
|
+
|
|
192
|
+
Autoblogger needs API routes to handle requests from the dashboard. Create a catch-all route:
|
|
68
193
|
|
|
69
194
|
```typescript
|
|
70
195
|
// app/api/cms/[...path]/route.ts
|
|
71
196
|
import { cms } from '@/lib/cms'
|
|
72
|
-
import {
|
|
73
|
-
|
|
74
|
-
|
|
197
|
+
import { NextRequest } from 'next/server'
|
|
198
|
+
|
|
199
|
+
async function handler(
|
|
200
|
+
req: NextRequest,
|
|
201
|
+
{ params }: { params: Promise<{ path: string[] }> }
|
|
202
|
+
) {
|
|
203
|
+
const { path } = await params
|
|
204
|
+
return cms.handleRequest(req, path.join('/'))
|
|
205
|
+
}
|
|
75
206
|
|
|
76
|
-
export
|
|
77
|
-
export const POST = handler
|
|
78
|
-
export const PATCH = handler
|
|
79
|
-
export const DELETE = handler
|
|
207
|
+
export { handler as GET, handler as POST, handler as PATCH, handler as DELETE }
|
|
80
208
|
```
|
|
81
209
|
|
|
82
|
-
|
|
210
|
+
This single file handles all CMS API routes:
|
|
211
|
+
|
|
212
|
+
| Route | Purpose |
|
|
213
|
+
|-------|---------|
|
|
214
|
+
| `GET /api/cms/posts` | List all posts |
|
|
215
|
+
| `POST /api/cms/posts` | Create a new post |
|
|
216
|
+
| `PATCH /api/cms/posts/:id` | Update a post |
|
|
217
|
+
| `DELETE /api/cms/posts/:id` | Delete a post |
|
|
218
|
+
| `GET /api/cms/revisions` | List revisions |
|
|
219
|
+
| `POST /api/cms/revisions/:id/restore` | Restore a revision |
|
|
220
|
+
| `GET /api/cms/comments` | List comments |
|
|
221
|
+
| `POST /api/cms/ai/generate` | Generate essay with AI |
|
|
222
|
+
| `POST /api/cms/ai/chat` | Chat with AI (streaming) |
|
|
223
|
+
| ... | And more |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Mounting the Dashboard
|
|
228
|
+
|
|
229
|
+
The dashboard is a React component that renders the full CMS interface. Mount it at a route in your app:
|
|
83
230
|
|
|
84
231
|
```typescript
|
|
85
232
|
// app/writer/[[...path]]/page.tsx
|
|
86
|
-
'use client'
|
|
87
|
-
|
|
88
233
|
import { AutobloggerDashboard } from 'autoblogger/ui'
|
|
89
|
-
import {
|
|
90
|
-
|
|
91
|
-
|
|
234
|
+
import { auth } from '@/lib/auth'
|
|
235
|
+
import { redirect } from 'next/navigation'
|
|
236
|
+
|
|
237
|
+
export default async function WriterPage({
|
|
238
|
+
params
|
|
239
|
+
}: {
|
|
240
|
+
params: Promise<{ path?: string[] }>
|
|
241
|
+
}) {
|
|
242
|
+
// Protect this route - only authenticated users
|
|
243
|
+
const session = await auth()
|
|
244
|
+
if (!session) {
|
|
245
|
+
redirect('/login')
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const { path } = await params
|
|
249
|
+
|
|
92
250
|
return (
|
|
93
251
|
<AutobloggerDashboard
|
|
94
|
-
basePath="/writer"
|
|
95
252
|
apiBasePath="/api/cms"
|
|
96
|
-
|
|
253
|
+
session={session}
|
|
254
|
+
path={path?.join('/') || ''}
|
|
97
255
|
/>
|
|
98
256
|
)
|
|
99
257
|
}
|
|
100
258
|
```
|
|
101
259
|
|
|
102
|
-
|
|
260
|
+
The `[[...path]]` syntax is a catch-all route that captures the dashboard's internal navigation:
|
|
261
|
+
|
|
262
|
+
| URL | Dashboard Page |
|
|
263
|
+
|-----|----------------|
|
|
264
|
+
| `/writer` | Post list (drafts, published, suggested) |
|
|
265
|
+
| `/writer/editor/my-post-slug` | Edit a specific post |
|
|
266
|
+
| `/writer/settings` | Settings overview |
|
|
267
|
+
| `/writer/settings/ai` | AI model and prompt configuration |
|
|
268
|
+
| `/writer/settings/users` | User management |
|
|
269
|
+
| `/writer/settings/tags` | Tag management |
|
|
270
|
+
| `/writer/settings/topics` | RSS topic subscriptions |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Configuring Tailwind
|
|
275
|
+
|
|
276
|
+
Autoblogger's UI uses Tailwind CSS classes. Add the package's files to your Tailwind content configuration so the classes aren't purged:
|
|
103
277
|
|
|
104
278
|
```javascript
|
|
105
|
-
// tailwind.config.js
|
|
279
|
+
// tailwind.config.js (or tailwind.config.ts)
|
|
106
280
|
module.exports = {
|
|
107
|
-
presets: [require('autoblogger/styles/preset')],
|
|
108
281
|
content: [
|
|
109
282
|
'./app/**/*.{js,ts,jsx,tsx}',
|
|
110
|
-
'./
|
|
283
|
+
'./components/**/*.{js,ts,jsx,tsx}',
|
|
284
|
+
// Add this line to include Autoblogger's components
|
|
285
|
+
'./node_modules/autoblogger/dist/**/*.{js,mjs}',
|
|
111
286
|
],
|
|
287
|
+
// ... rest of your config
|
|
112
288
|
}
|
|
113
289
|
```
|
|
114
290
|
|
|
115
|
-
|
|
291
|
+
The dashboard uses semantic color tokens like `bg-card`, `text-muted-foreground`, `border-border`, etc. These come from shadcn/ui conventions. If you're using shadcn, they'll work automatically. Otherwise, add these CSS variables to your globals:
|
|
292
|
+
|
|
293
|
+
```css
|
|
294
|
+
/* globals.css */
|
|
295
|
+
:root {
|
|
296
|
+
--background: 0 0% 100%;
|
|
297
|
+
--foreground: 0 0% 3.9%;
|
|
298
|
+
--card: 0 0% 100%;
|
|
299
|
+
--card-foreground: 0 0% 3.9%;
|
|
300
|
+
--popover: 0 0% 100%;
|
|
301
|
+
--popover-foreground: 0 0% 3.9%;
|
|
302
|
+
--primary: 0 0% 9%;
|
|
303
|
+
--primary-foreground: 0 0% 98%;
|
|
304
|
+
--secondary: 0 0% 96.1%;
|
|
305
|
+
--secondary-foreground: 0 0% 9%;
|
|
306
|
+
--muted: 0 0% 96.1%;
|
|
307
|
+
--muted-foreground: 0 0% 45.1%;
|
|
308
|
+
--accent: 0 0% 96.1%;
|
|
309
|
+
--accent-foreground: 0 0% 9%;
|
|
310
|
+
--destructive: 0 84.2% 60.2%;
|
|
311
|
+
--destructive-foreground: 0 0% 98%;
|
|
312
|
+
--border: 0 0% 89.8%;
|
|
313
|
+
--input: 0 0% 89.8%;
|
|
314
|
+
--ring: 0 0% 3.9%;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.dark {
|
|
318
|
+
--background: 0 0% 3.9%;
|
|
319
|
+
--foreground: 0 0% 98%;
|
|
320
|
+
--card: 0 0% 3.9%;
|
|
321
|
+
--card-foreground: 0 0% 98%;
|
|
322
|
+
--popover: 0 0% 3.9%;
|
|
323
|
+
--popover-foreground: 0 0% 98%;
|
|
324
|
+
--primary: 0 0% 98%;
|
|
325
|
+
--primary-foreground: 0 0% 9%;
|
|
326
|
+
--secondary: 0 0% 14.9%;
|
|
327
|
+
--secondary-foreground: 0 0% 98%;
|
|
328
|
+
--muted: 0 0% 14.9%;
|
|
329
|
+
--muted-foreground: 0 0% 63.9%;
|
|
330
|
+
--accent: 0 0% 14.9%;
|
|
331
|
+
--accent-foreground: 0 0% 98%;
|
|
332
|
+
--destructive: 0 62.8% 30.6%;
|
|
333
|
+
--destructive-foreground: 0 0% 98%;
|
|
334
|
+
--border: 0 0% 14.9%;
|
|
335
|
+
--input: 0 0% 14.9%;
|
|
336
|
+
--ring: 0 0% 83.1%;
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Displaying Posts on Your Site
|
|
343
|
+
|
|
344
|
+
Use the CMS data layer to fetch posts for your public pages:
|
|
116
345
|
|
|
117
346
|
```typescript
|
|
118
|
-
// app/blog/
|
|
347
|
+
// app/blog/page.tsx
|
|
119
348
|
import { cms } from '@/lib/cms'
|
|
120
|
-
import
|
|
349
|
+
import Link from 'next/link'
|
|
350
|
+
|
|
351
|
+
export default async function BlogPage() {
|
|
352
|
+
const { posts } = await cms.data.posts.findAll({
|
|
353
|
+
where: { status: 'published' },
|
|
354
|
+
orderBy: { publishedAt: 'desc' },
|
|
355
|
+
take: 20,
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
return (
|
|
359
|
+
<div>
|
|
360
|
+
<h1>Blog</h1>
|
|
361
|
+
<ul>
|
|
362
|
+
{posts.map(post => (
|
|
363
|
+
<li key={post.id}>
|
|
364
|
+
<Link href={`/blog/${post.slug}`}>
|
|
365
|
+
{post.title}
|
|
366
|
+
</Link>
|
|
367
|
+
</li>
|
|
368
|
+
))}
|
|
369
|
+
</ul>
|
|
370
|
+
</div>
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Rendering a Single Post
|
|
121
376
|
|
|
122
|
-
|
|
123
|
-
|
|
377
|
+
```typescript
|
|
378
|
+
// app/blog/[slug]/page.tsx
|
|
379
|
+
import { cms } from '@/lib/cms'
|
|
380
|
+
import { renderMarkdown } from 'autoblogger/markdown'
|
|
381
|
+
import { generateSeoMetadata } from 'autoblogger/seo'
|
|
382
|
+
import { notFound } from 'next/navigation'
|
|
383
|
+
|
|
384
|
+
export default async function PostPage({
|
|
385
|
+
params
|
|
386
|
+
}: {
|
|
387
|
+
params: Promise<{ slug: string }>
|
|
388
|
+
}) {
|
|
389
|
+
const { slug } = await params
|
|
390
|
+
const post = await cms.data.posts.findBySlug(slug)
|
|
391
|
+
|
|
392
|
+
if (!post || post.status !== 'published') {
|
|
393
|
+
notFound()
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const html = renderMarkdown(post.markdown)
|
|
124
397
|
|
|
125
398
|
return (
|
|
126
399
|
<article>
|
|
127
400
|
<h1>{post.title}</h1>
|
|
128
|
-
<
|
|
401
|
+
{post.subtitle && <p className="text-xl text-gray-600">{post.subtitle}</p>}
|
|
402
|
+
<div
|
|
403
|
+
className="prose dark:prose-invert"
|
|
404
|
+
dangerouslySetInnerHTML={{ __html: html }}
|
|
405
|
+
/>
|
|
129
406
|
</article>
|
|
130
407
|
)
|
|
131
408
|
}
|
|
132
409
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
410
|
+
// Generate SEO metadata
|
|
411
|
+
export async function generateMetadata({
|
|
412
|
+
params
|
|
413
|
+
}: {
|
|
414
|
+
params: Promise<{ slug: string }>
|
|
415
|
+
}) {
|
|
416
|
+
const { slug } = await params
|
|
417
|
+
const post = await cms.data.posts.findBySlug(slug)
|
|
418
|
+
|
|
419
|
+
if (!post) return {}
|
|
420
|
+
|
|
421
|
+
return generateSeoMetadata(post)
|
|
137
422
|
}
|
|
138
423
|
```
|
|
139
424
|
|
|
140
|
-
|
|
425
|
+
---
|
|
141
426
|
|
|
142
|
-
|
|
427
|
+
## Package Exports
|
|
428
|
+
|
|
429
|
+
Autoblogger provides several entry points:
|
|
143
430
|
|
|
144
431
|
```typescript
|
|
145
|
-
//
|
|
432
|
+
// Main entry — server-side data layer and API handlers
|
|
433
|
+
import { createAutoblogger } from 'autoblogger'
|
|
434
|
+
|
|
435
|
+
// UI components — React dashboard (client-side)
|
|
146
436
|
import { AutobloggerDashboard } from 'autoblogger/ui'
|
|
147
|
-
import { MyCustomField } from '@/components/MyCustomField'
|
|
148
437
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
438
|
+
// Markdown utilities — render markdown to HTML, parse HTML to markdown
|
|
439
|
+
import { renderMarkdown, parseMarkdown } from 'autoblogger/markdown'
|
|
440
|
+
|
|
441
|
+
// SEO utilities — generate meta tags from post data
|
|
442
|
+
import { generateSeoMetadata } from 'autoblogger/seo'
|
|
443
|
+
|
|
444
|
+
// Article styles — CSS class helpers for consistent article layout
|
|
445
|
+
import { ARTICLE_STYLES } from 'autoblogger/styles/article'
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## AI Models
|
|
451
|
+
|
|
452
|
+
Autoblogger supports these AI models out of the box:
|
|
453
|
+
|
|
454
|
+
| ID | Name | Provider | Best For |
|
|
455
|
+
|----|------|----------|----------|
|
|
456
|
+
| `claude-sonnet` | Claude Sonnet 4.5 | Anthropic | Fast, balanced writing |
|
|
457
|
+
| `claude-opus` | Claude Opus 4.5 | Anthropic | Complex, nuanced essays |
|
|
458
|
+
| `gpt-5.2` | GPT-5.2 | OpenAI | General purpose |
|
|
459
|
+
| `gpt-5-mini` | GPT-5 Mini | OpenAI | Quick drafts |
|
|
460
|
+
|
|
461
|
+
Configure the default model and custom prompts in the dashboard under **Settings → AI**.
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## User Roles
|
|
466
|
+
|
|
467
|
+
Autoblogger supports three roles:
|
|
468
|
+
|
|
469
|
+
| Role | Permissions |
|
|
470
|
+
|------|-------------|
|
|
471
|
+
| `admin` | Full access. Manage users, settings, publish/delete any post. |
|
|
472
|
+
| `writer` | Create posts, publish their own posts, edit drafts. |
|
|
473
|
+
| `drafter` | Create drafts only. Cannot publish. |
|
|
474
|
+
|
|
475
|
+
Roles are stored in the `User.role` field. Your auth configuration determines how roles are checked.
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Troubleshooting
|
|
480
|
+
|
|
481
|
+
### "Cannot find module 'autoblogger/ui'"
|
|
482
|
+
|
|
483
|
+
Make sure you're importing from the correct path and that the package is installed:
|
|
484
|
+
|
|
485
|
+
```bash
|
|
486
|
+
npm install autoblogger
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Tailwind classes not applying
|
|
490
|
+
|
|
491
|
+
Add the package to your Tailwind content config:
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
content: [
|
|
495
|
+
// ... your files
|
|
496
|
+
'./node_modules/autoblogger/dist/**/*.{js,mjs}',
|
|
497
|
+
]
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### AI features not working
|
|
501
|
+
|
|
502
|
+
Check that your API keys are set in environment variables:
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
ANTHROPIC_API_KEY="sk-ant-..."
|
|
506
|
+
OPENAI_API_KEY="sk-..."
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
And that you're passing them in the config:
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
ai: {
|
|
513
|
+
anthropicKey: process.env.ANTHROPIC_API_KEY,
|
|
514
|
+
openaiKey: process.env.OPENAI_API_KEY,
|
|
159
515
|
}
|
|
160
516
|
```
|
|
161
517
|
|
|
518
|
+
### Database errors
|
|
519
|
+
|
|
520
|
+
Make sure you've:
|
|
521
|
+
1. Added all required models to your Prisma schema
|
|
522
|
+
2. Run `npx prisma migrate dev`
|
|
523
|
+
3. Run `npx prisma generate`
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
162
527
|
## License
|
|
163
528
|
|
|
164
|
-
MIT
|
|
529
|
+
MIT © [Hunter Rosenblume](https://github.com/hrosenblume)
|