@everystack/mcp 0.2.0
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 +100 -0
- package/package.json +39 -0
- package/src/index.ts +58 -0
- package/src/prompts/add-feature.ts +163 -0
- package/src/prompts/debug.ts +136 -0
- package/src/prompts/deploy.ts +131 -0
- package/src/prompts/design-schema.ts +104 -0
- package/src/prompts/index.ts +16 -0
- package/src/prompts/new-app.ts +211 -0
- package/src/prompts/secure.ts +231 -0
- package/src/resources/adding-database.md +169 -0
- package/src/resources/admin.md +81 -0
- package/src/resources/auth.md +115 -0
- package/src/resources/aws-setup.md +173 -0
- package/src/resources/cli.md +108 -0
- package/src/resources/client-api.md +145 -0
- package/src/resources/core.md +196 -0
- package/src/resources/deployment.md +146 -0
- package/src/resources/events.md +87 -0
- package/src/resources/first-run.md +100 -0
- package/src/resources/getting-started.md +75 -0
- package/src/resources/handler-options.md +114 -0
- package/src/resources/images.md +73 -0
- package/src/resources/index.ts +224 -0
- package/src/resources/jobs.md +97 -0
- package/src/resources/logging.md +91 -0
- package/src/resources/plugins.md +68 -0
- package/src/resources/project-claude-md.md +127 -0
- package/src/resources/query-protocol.md +129 -0
- package/src/resources/schema-patterns.md +167 -0
- package/src/resources/security-device.md +99 -0
- package/src/resources/security.md +270 -0
- package/src/resources/ssr.md +82 -0
- package/src/resources/storage.md +63 -0
- package/src/resources/testing.md +118 -0
- package/src/tools/check-environment.ts +319 -0
- package/src/tools/index.ts +58 -0
- package/src/tools/project-status.ts +183 -0
- package/src/tools/project-validate.ts +369 -0
- package/src/tools/schema-analyze.ts +410 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# What is everystack?
|
|
2
|
+
|
|
3
|
+
everystack helps you build apps. Real apps that work on iPhones, Android phones, tablets, computers, and the web — all from the same code.
|
|
4
|
+
|
|
5
|
+
You describe what you want. Claude helps you build it. everystack provides the building blocks.
|
|
6
|
+
|
|
7
|
+
**A note about difficulty:** Building software is hard. Professional engineers are paid well to do this, and projects often take months or years. Claude and everystack make it much more accessible, but you are still building real software with real infrastructure. Things will break. You will hit errors you don't understand. That's normal. The key is to keep going, ask questions, and learn as you go.
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
You start simple: a running app on your screen. Then you build from there.
|
|
12
|
+
|
|
13
|
+
Every app starts the same way — a basic Expo app that works on phones, tablets, and the web. You build the screens, the navigation, the look and feel. Everything is visual and immediate.
|
|
14
|
+
|
|
15
|
+
When your app needs more — user accounts, saved data, file uploads — you add those capabilities one at a time. You never throw away what you already built. Your app grows with you.
|
|
16
|
+
|
|
17
|
+
## What you need to get started
|
|
18
|
+
|
|
19
|
+
These are tools that run on your computer. Claude will help you install each one.
|
|
20
|
+
|
|
21
|
+
**Node.js** — Runs your code. Your app is written in TypeScript (a programming language). Node.js is the engine that makes it work, like how a car needs an engine to drive.
|
|
22
|
+
- Without it: Nothing runs.
|
|
23
|
+
|
|
24
|
+
**git** — Tracks every change you make to your code. Like an unlimited undo button for your entire project. You can always go back to any previous version.
|
|
25
|
+
- Without it: You cannot track changes or undo mistakes.
|
|
26
|
+
|
|
27
|
+
**pnpm** (recommended) — A faster way to install code libraries your app depends on. Recommended but Claude can work without it.
|
|
28
|
+
|
|
29
|
+
That's it. Those three tools are all you need to create an app and see it running on your computer.
|
|
30
|
+
|
|
31
|
+
### When your app needs a database (later)
|
|
32
|
+
|
|
33
|
+
If your app needs user accounts or saved data, you'll add a database. This is not needed to start — only when a feature demands it.
|
|
34
|
+
|
|
35
|
+
**PostgreSQL** — A database that stores your app's data: users, posts, recipes, or whatever your app needs. Like a spreadsheet that your app reads and writes automatically. Read everystack://adding-database when you're ready for this step.
|
|
36
|
+
|
|
37
|
+
### To deploy to the internet (later)
|
|
38
|
+
|
|
39
|
+
You don't need these right away. Install them when you're ready to put your app online so other people can use it.
|
|
40
|
+
|
|
41
|
+
**AWS account + AWS CLI** — AWS (Amazon Web Services) is where your app lives on the internet. Other people's computers run your app so anyone can use it. The AWS CLI is a tool that lets Claude talk to AWS from your computer.
|
|
42
|
+
- Without it: Your app only works on your computer. Nobody else can use it.
|
|
43
|
+
- Setting up AWS requires a credit card for verification. AWS has a free tier for the first 12 months. You control all costs and can delete everything at any time.
|
|
44
|
+
|
|
45
|
+
**AWS credentials** — A password file that proves your computer is allowed to deploy to your AWS account. You create this once during setup.
|
|
46
|
+
- Without them: AWS will reject all deploy commands.
|
|
47
|
+
- New to AWS? Read everystack://aws-setup for a complete walkthrough of creating an account and setting up credentials.
|
|
48
|
+
|
|
49
|
+
## The path from idea to running app
|
|
50
|
+
|
|
51
|
+
1. **You describe your idea.** "I want to build a recipe sharing app."
|
|
52
|
+
2. **Claude checks your computer.** Runs a tool to see what's installed and what's missing.
|
|
53
|
+
3. **Claude helps you install anything missing.** Step by step, one tool at a time. Each one explained before you install it.
|
|
54
|
+
4. **Claude creates your app.** A stock Expo app with the everystack building blocks installed.
|
|
55
|
+
5. **You see it running on your computer.** Your app opens in a browser. You can change things and see updates instantly. Read everystack://first-run for details on this step.
|
|
56
|
+
6. **You build together.** Describe what you want — screens, buttons, colors, layout. Claude builds it. You see changes in real time. This is where most of the work happens.
|
|
57
|
+
7. **Your app grows when it needs to.** When a feature needs user accounts or saved data, Claude helps you add a database. When you need file uploads, you add that too. One thing at a time.
|
|
58
|
+
8. **When you're ready, you deploy.** Your app gets a real URL that anyone can visit. This is a separate step — there's no rush.
|
|
59
|
+
|
|
60
|
+
## Common questions
|
|
61
|
+
|
|
62
|
+
**Do I need to know how to code?**
|
|
63
|
+
Not to start. Claude writes the code and explains what it's doing. But you're building real software — the same kind that teams of engineers get paid to build. Things will break. You'll need to learn as you go. The more you understand, the better your app will be.
|
|
64
|
+
|
|
65
|
+
**How much does AWS cost?**
|
|
66
|
+
For a small app with low traffic, typically under $5/month for a static site and around $20/month once you add a database (the database is the main cost). AWS has a free tier for the first 12 months that covers most of what everystack uses. You can build and run locally for free with no AWS account at all.
|
|
67
|
+
|
|
68
|
+
**Can I change things later?**
|
|
69
|
+
Yes. everystack is built for this. Start with a simple app, add user accounts when you need them, add file uploads when you need them. You never throw away what you already built.
|
|
70
|
+
|
|
71
|
+
**What if something goes wrong?**
|
|
72
|
+
Claude can debug it. everystack has built-in tools that check your project for common mistakes and security issues. And git tracks every change, so you can always go back. Expect things to go wrong — that's part of building software. The tools are here to help you recover.
|
|
73
|
+
|
|
74
|
+
**Do I need a Mac?**
|
|
75
|
+
For now, yes. everystack's setup tools are designed for macOS. Windows and Linux support may come later.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Handler Options Reference
|
|
2
|
+
|
|
3
|
+
> Complete reference for `createHandler(db, schema, options)` from `@everystack/api/handler`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when configuring the PostgREST handler for a V2+ app. Every option is optional -- start minimal and add as needed.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { createHandler } from '@everystack/api/handler';
|
|
12
|
+
import * as schema from '../db/schema';
|
|
13
|
+
|
|
14
|
+
const handler = createHandler(db, schema, {
|
|
15
|
+
basePath: '/api', // Strip this prefix from incoming URLs
|
|
16
|
+
// ... options below
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Returns `(request: Request) => Promise<Response>`.
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
|
|
24
|
+
### auth
|
|
25
|
+
```typescript
|
|
26
|
+
auth: {
|
|
27
|
+
verifyToken: async (token: string) => payload | null, // Required for auth
|
|
28
|
+
publicRoutes: ['GET'], // Methods that skip token verification
|
|
29
|
+
publicRpc: ['health'], // RPC functions that skip all auth (token + client)
|
|
30
|
+
roleHierarchy: ['public', 'authenticated', 'admin'], // For RPC role gates
|
|
31
|
+
roleField: 'role', // JWT field containing user's role
|
|
32
|
+
onAuthenticated: (user) => {}, // Callback after successful auth
|
|
33
|
+
// Client credentials (two-tier auth)
|
|
34
|
+
verifyClient: async (clientId, clientSecret, referer?) => client | null,
|
|
35
|
+
clientHeaders: { id: 'X-Client-Id', secret: 'X-Client-Secret' },
|
|
36
|
+
onClientAuthenticated: (client) => {},
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### pgSettings (RLS)
|
|
41
|
+
```typescript
|
|
42
|
+
pgSettings: (user, client) => ({
|
|
43
|
+
role: user?.role === 'admin' ? 'admin' : user ? 'authenticated' : 'anon',
|
|
44
|
+
'request.jwt.claims': JSON.stringify(user || { role: 'anon' }),
|
|
45
|
+
'app.user_id': String(user?.sub || ''),
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
The `role` key triggers `SET LOCAL ROLE`. All other keys use `set_config(key, value, true)`. Everything is LOCAL scope (resets when transaction ends).
|
|
49
|
+
|
|
50
|
+
### relations
|
|
51
|
+
```typescript
|
|
52
|
+
relations: {
|
|
53
|
+
posts: {
|
|
54
|
+
author: { table: 'users', from: 'authorId', to: 'id' }, // many-to-one
|
|
55
|
+
comments: { table: 'comments', from: 'id', to: 'postId', many: true }, // one-to-many
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
Enables `?select=*,author(*)` embedding. Resolved via batched `WHERE IN` (no N+1).
|
|
60
|
+
|
|
61
|
+
### rpc
|
|
62
|
+
```typescript
|
|
63
|
+
rpc: {
|
|
64
|
+
health: async (body) => ({ status: 'ok' }), // Function syntax
|
|
65
|
+
timeline: { fn: async (body, user) => {}, role: 'authenticated' }, // Object + role
|
|
66
|
+
admin_stats: { fn: async (body, user) => {}, role: 'admin' },
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
Function syntax uses publicRpc/publicRoutes rules. Object syntax enforces role requirement.
|
|
70
|
+
|
|
71
|
+
### hooks
|
|
72
|
+
```typescript
|
|
73
|
+
hooks: {
|
|
74
|
+
posts: {
|
|
75
|
+
beforeCreate: async (body, user, client) => ({ ...body, authorId: user?.sub }),
|
|
76
|
+
afterCreate: async (row, user, client) => {},
|
|
77
|
+
beforeUpdate: async (body, user, client) => body,
|
|
78
|
+
afterUpdate: async (rows, user, client) => {},
|
|
79
|
+
beforeDelete: async (user, client) => {},
|
|
80
|
+
afterDelete: async (rows, user, client) => {},
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
`beforeCreate`/`beforeUpdate` can modify the body by returning a new object.
|
|
85
|
+
|
|
86
|
+
### Access Control
|
|
87
|
+
```typescript
|
|
88
|
+
exposedTables: ['posts', 'profiles'], // 404 for unlisted tables
|
|
89
|
+
hiddenColumns: { users: ['passwordHash'] }, // Strip from all responses
|
|
90
|
+
protectedFields: { profiles: ['role'] }, // Strip from incoming writes
|
|
91
|
+
rowOwnership: { posts: { column: 'authorId', userField: 'sub' } }, // Scope writes to owner
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Safety Limits
|
|
95
|
+
```typescript
|
|
96
|
+
maxEmbedDepth: 3, // Max relation nesting depth (default: 3)
|
|
97
|
+
maxLimit: 1000, // Max ?limit= value (default: 10000)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Other
|
|
101
|
+
```typescript
|
|
102
|
+
softDelete: { column: 'deletedAt', tables: ['posts'] }, // DELETE -> UPDATE SET deletedAt
|
|
103
|
+
naming: 'snake_case', // Response key format ('camelCase' default)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Gotchas
|
|
107
|
+
|
|
108
|
+
- `pgSettings` wraps every query in a transaction. Without it, queries execute directly (no RLS).
|
|
109
|
+
- `hiddenColumns` strips AFTER query execution. Columns are still in the SQL result, just removed from JSON.
|
|
110
|
+
- `protectedFields` strips BEFORE hooks run. Hooks never see protected fields.
|
|
111
|
+
- `exposedTables` doesn't affect RPC endpoints.
|
|
112
|
+
- `rowOwnership` only affects PATCH and DELETE. Reads are governed by RLS.
|
|
113
|
+
- The `role` value in pgSettings is validated against `^[a-zA-Z_][a-zA-Z0-9_]*$`.
|
|
114
|
+
- DELETE without filters returns 400 (safety). Always include at least one filter.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Image Processing
|
|
2
|
+
|
|
3
|
+
> On-demand Sharp image processing on Lambda. Import from `@everystack/images`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when adding image resizing, format conversion, or variant generation (V3).
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
// server/image.ts
|
|
12
|
+
import { createImageHandler } from '@everystack/server/image';
|
|
13
|
+
|
|
14
|
+
export const handler = createImageHandler({
|
|
15
|
+
bucket: Resource.Media.name,
|
|
16
|
+
pathPrefix: '/media/',
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## URL-based Processing
|
|
21
|
+
|
|
22
|
+
Images are processed on-the-fly via query parameters:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
/media/photo.jpg?w=400&h=300&fit=cover&fm=webp&q=80
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| Parameter | Description | Values |
|
|
29
|
+
|-----------|-------------|--------|
|
|
30
|
+
| `w` | Width | pixels |
|
|
31
|
+
| `h` | Height | pixels |
|
|
32
|
+
| `fit` | Resize mode | `cover`, `contain`, `fill`, `inside`, `outside` |
|
|
33
|
+
| `fm` | Output format | `webp`, `avif`, `jpeg`, `png` |
|
|
34
|
+
| `q` | Quality | 1-100 |
|
|
35
|
+
|
|
36
|
+
## Variant Generation
|
|
37
|
+
|
|
38
|
+
Pre-generate variants via background jobs:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { generateVariants } from '@everystack/images/jobs';
|
|
42
|
+
|
|
43
|
+
await publishJob('image:process', {
|
|
44
|
+
key: 'uploads/photo.jpg',
|
|
45
|
+
variants: [
|
|
46
|
+
{ name: 'thumb', width: 150, height: 150, fit: 'cover' },
|
|
47
|
+
{ name: 'large', width: 1200, format: 'webp', quality: 85 },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## EXIF Extraction
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { extractExif } from '@everystack/images';
|
|
56
|
+
|
|
57
|
+
const exif = await extractExif(buffer);
|
|
58
|
+
// { width, height, orientation, gps, camera, ... }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Schema
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { imagesSchema } from '@everystack/images/schema';
|
|
65
|
+
// Adds: image_variants table tracking generated variants
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Gotchas
|
|
69
|
+
|
|
70
|
+
- Sharp runs on Lambda ARM64 (uses Lambda layer or bundled binary)
|
|
71
|
+
- First request for a variant is slow (processing), subsequent are cached
|
|
72
|
+
- CloudFront caches processed images (set appropriate Cache-Control)
|
|
73
|
+
- AVIF encoding is slower than WebP but produces smaller files
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
|
|
5
|
+
// Resolve the directory containing resource files.
|
|
6
|
+
// tsx (our runtime) polyfills __dirname in ESM. ts-jest uses CJS where __dirname is native.
|
|
7
|
+
// We use a dynamic eval to avoid import.meta.url appearing in CJS output (which would throw).
|
|
8
|
+
function getResourcesDir(): string {
|
|
9
|
+
// In CJS (ts-jest), __dirname is a global
|
|
10
|
+
try {
|
|
11
|
+
return (globalThis as Record<string, unknown>).__dirname as string
|
|
12
|
+
|| eval('__dirname') as string;
|
|
13
|
+
} catch {
|
|
14
|
+
// In pure ESM, fall back to import.meta.url
|
|
15
|
+
const { fileURLToPath } = require('node:url');
|
|
16
|
+
return dirname(fileURLToPath(eval('import.meta.url')));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const RESOURCES_DIR = getResourcesDir();
|
|
21
|
+
|
|
22
|
+
function loadResource(filename: string): string {
|
|
23
|
+
return readFileSync(join(RESOURCES_DIR, filename), 'utf-8');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ResourceDef {
|
|
27
|
+
uri: string;
|
|
28
|
+
name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
filename: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const RESOURCES: ResourceDef[] = [
|
|
34
|
+
// Beginner — plain English intro, read first for new users
|
|
35
|
+
{
|
|
36
|
+
uri: 'everystack://getting-started',
|
|
37
|
+
name: 'Getting Started (Beginners)',
|
|
38
|
+
description:
|
|
39
|
+
'Plain English intro for complete beginners. What everystack is, what the tiers mean, what each prerequisite is and why. Read this FIRST for users with no programming experience or no existing project.',
|
|
40
|
+
filename: 'getting-started.md',
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// Beginner — AWS account and credential setup
|
|
44
|
+
{
|
|
45
|
+
uri: 'everystack://aws-setup',
|
|
46
|
+
name: 'AWS Setup (Beginners)',
|
|
47
|
+
description:
|
|
48
|
+
'Step-by-step AWS account creation and IAM credential setup for beginners. Read when check_environment reports missing AWS credentials.',
|
|
49
|
+
filename: 'aws-setup.md',
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Beginner — first local run walkthrough
|
|
53
|
+
{
|
|
54
|
+
uri: 'everystack://first-run',
|
|
55
|
+
name: 'First Run (Beginners)',
|
|
56
|
+
description:
|
|
57
|
+
'What happens when you run your app locally for the first time. Explains Metro bundler, hot reload, opening in browser or phone, and common first-run errors. Read after scaffolding a new project.',
|
|
58
|
+
filename: 'first-run.md',
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// Beginner — V2 transition guide (adding database to existing app)
|
|
62
|
+
{
|
|
63
|
+
uri: 'everystack://adding-database',
|
|
64
|
+
name: 'Adding a Database (V2 Transition)',
|
|
65
|
+
description:
|
|
66
|
+
'Guide for adding PostgreSQL, API handler, and authentication to an existing Expo app. Read this when a feature needs data persistence or user accounts. Covers PostgreSQL setup, V2 package installation, schema creation, handler config, auth flow, migrations, and RLS security.',
|
|
67
|
+
filename: 'adding-database.md',
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Core — read these first (for developers)
|
|
71
|
+
{
|
|
72
|
+
uri: 'everystack://core',
|
|
73
|
+
name: 'everystack Core Architecture',
|
|
74
|
+
description:
|
|
75
|
+
'Architecture, package map, V1-V2-V3 tiers, key patterns, project conventions, handler overview, CLI commands. Read this first.',
|
|
76
|
+
filename: 'core.md',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
uri: 'everystack://security',
|
|
80
|
+
name: 'everystack Security',
|
|
81
|
+
description:
|
|
82
|
+
'Three-layer security model (Edge/API/Database), AWS IAM profiles (Create/Manage/Deploy), RLS guide with copy-paste policies, deployment checklist. Read before any auth or deployment guidance.',
|
|
83
|
+
filename: 'security.md',
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Detail — load on demand
|
|
87
|
+
{
|
|
88
|
+
uri: 'everystack://handler-options',
|
|
89
|
+
name: 'Handler Options Reference',
|
|
90
|
+
description:
|
|
91
|
+
'Complete createHandler() options: auth, relations, rpc, hooks, pgSettings, softDelete, naming, exposedTables, hiddenColumns, protectedFields, rowOwnership, cache.',
|
|
92
|
+
filename: 'handler-options.md',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
uri: 'everystack://query-protocol',
|
|
96
|
+
name: 'Query Protocol',
|
|
97
|
+
description:
|
|
98
|
+
'PostgREST query protocol: filters (eq, neq, gt, lt, like, ilike, is, in), negation, logical groups (or, and), column selection, relation embedding, ordering, pagination, aggregates, JSON path filtering.',
|
|
99
|
+
filename: 'query-protocol.md',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
uri: 'everystack://client-api',
|
|
103
|
+
name: 'Client API',
|
|
104
|
+
description:
|
|
105
|
+
'Typed client: createClient(), query builder (.from, .eq, .select, .order, .limit), mutations (.insert, .update, .delete), token refresh, error handling.',
|
|
106
|
+
filename: 'client-api.md',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
uri: 'everystack://auth',
|
|
110
|
+
name: 'Authentication',
|
|
111
|
+
description:
|
|
112
|
+
'JWT auth: createAuthHandlers(), signup/signin/refresh flows, HS256 edge verification, OAuth, password hashing, token lifecycle, AuthProvider React context.',
|
|
113
|
+
filename: 'auth.md',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
uri: 'everystack://schema-patterns',
|
|
117
|
+
name: 'Schema Design Patterns',
|
|
118
|
+
description:
|
|
119
|
+
'Drizzle schema design: pgTable, column types, relations, indexes, timestamps, soft delete, UUID vs serial, migration workflow, drizzle-kit commands.',
|
|
120
|
+
filename: 'schema-patterns.md',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
uri: 'everystack://deployment',
|
|
124
|
+
name: 'Deployment Guide',
|
|
125
|
+
description:
|
|
126
|
+
'SST deployment: sst.config.ts setup, secrets, stages (dev/production), CloudFront, Lambda configuration, VPC, RDS Aurora Serverless, resource linking.',
|
|
127
|
+
filename: 'deployment.md',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
uri: 'everystack://admin',
|
|
131
|
+
name: 'Admin Dashboard',
|
|
132
|
+
description:
|
|
133
|
+
'Declarative admin: AdminRoot, AdminLayout, resource config, field types, EverystackAdapter, presets, custom widgets, navigation.',
|
|
134
|
+
filename: 'admin.md',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
uri: 'everystack://jobs',
|
|
138
|
+
name: 'Background Jobs',
|
|
139
|
+
description:
|
|
140
|
+
'SQS background workers: createWorkerHandler, publishJob, job types, dead letter queue, cron scheduling, Postgres materialization adapter.',
|
|
141
|
+
filename: 'jobs.md',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
uri: 'everystack://storage',
|
|
145
|
+
name: 'File Storage',
|
|
146
|
+
description:
|
|
147
|
+
'S3 file storage: createStorageHandler, presigned uploads, MIME validation, CDN delivery, ownership enforcement, client upload flow.',
|
|
148
|
+
filename: 'storage.md',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
uri: 'everystack://logging',
|
|
152
|
+
name: 'Logging & Analytics',
|
|
153
|
+
description:
|
|
154
|
+
'Structured logging: log levels, crash reports, analytics events, S3 log storage, CloudWatch ingestion trigger, client SDK, admin dashboard integration.',
|
|
155
|
+
filename: 'logging.md',
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
uri: 'everystack://security-device',
|
|
159
|
+
name: 'Device Security',
|
|
160
|
+
description:
|
|
161
|
+
'Device attestation: Apple App Attest, Google Play Integrity, RS256 device keys, biometric auth, certificate pinning.',
|
|
162
|
+
filename: 'security-device.md',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
uri: 'everystack://testing',
|
|
166
|
+
name: 'Testing Patterns',
|
|
167
|
+
description:
|
|
168
|
+
'Testing conventions: Jest setup, TDD workflow, test file structure, mocking patterns (ESM, sharp, AWS SDK), template database isolation, integration tests.',
|
|
169
|
+
filename: 'testing.md',
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
uri: 'everystack://plugins',
|
|
173
|
+
name: 'Plugin Architecture',
|
|
174
|
+
description:
|
|
175
|
+
'Plugin system: createPluginLambdaHandler, Plugin type, PluginContext, composing handlers from multiple packages, plugin registration order.',
|
|
176
|
+
filename: 'plugins.md',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
uri: 'everystack://ssr',
|
|
180
|
+
name: 'Server-Side Rendering',
|
|
181
|
+
description:
|
|
182
|
+
'SSR: getWebHandler, direct Drizzle queries in loaders, JSON-LD structured data, OG meta tags, cache headers, hydration debugging.',
|
|
183
|
+
filename: 'ssr.md',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
uri: 'everystack://images',
|
|
187
|
+
name: 'Image Processing',
|
|
188
|
+
description:
|
|
189
|
+
'Sharp image processing: createImageHandler, on-demand resizing, format conversion, EXIF extraction, variant generation, CDN delivery.',
|
|
190
|
+
filename: 'images.md',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
uri: 'everystack://events',
|
|
194
|
+
name: 'Events & WebSocket',
|
|
195
|
+
description:
|
|
196
|
+
'Real-time events: PostgreSQL LISTEN/NOTIFY, WebSocket fan-out, Lambda event bridge, client useSignal hook, table change notifications.',
|
|
197
|
+
filename: 'events.md',
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
uri: 'everystack://cli',
|
|
201
|
+
name: 'CLI Reference',
|
|
202
|
+
description:
|
|
203
|
+
'Full CLI command reference: update, db:migrate, db:seed, db:psql, console, logs:errors, logs:tail, logs:query, cache:purge, certs, channels, diag, analyze:ssr.',
|
|
204
|
+
filename: 'cli.md',
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
uri: 'everystack://project-claude-md',
|
|
208
|
+
name: 'Project CLAUDE.md Template',
|
|
209
|
+
description:
|
|
210
|
+
'Template for a project-level CLAUDE.md file. Read this and adapt it when scaffolding a new everystack app. Replace placeholders ({PROJECT_NAME}, {ONE_LINE_DESCRIPTION}, {ANNOTATED_DIRECTORY_TREE}) with actual project details.',
|
|
211
|
+
filename: 'project-claude-md.md',
|
|
212
|
+
},
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
export function registerResources(server: McpServer): void {
|
|
216
|
+
for (const r of RESOURCES) {
|
|
217
|
+
const content = loadResource(r.filename);
|
|
218
|
+
server.resource(r.name, r.uri, { mimeType: 'text/markdown' }, async () => ({
|
|
219
|
+
contents: [{ uri: r.uri, mimeType: 'text/markdown' as const, text: content }],
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export { RESOURCES, loadResource };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Background Jobs
|
|
2
|
+
|
|
3
|
+
> SQS background workers for everystack apps. Import from `@everystack/jobs`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when adding background processing (V3): email sending, image processing, analytics aggregation, etc.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
### Infrastructure
|
|
11
|
+
```typescript
|
|
12
|
+
// sst.config.ts
|
|
13
|
+
const dlq = new sst.aws.Queue('DeadLetterQueue');
|
|
14
|
+
const jobs = new sst.aws.Queue('Jobs', { dlq: dlq.arn });
|
|
15
|
+
|
|
16
|
+
const worker = new sst.aws.Function('Worker', {
|
|
17
|
+
handler: 'server/worker.handler',
|
|
18
|
+
link: [database, jobs, media],
|
|
19
|
+
vpc,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
jobs.subscribe(worker.arn);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Worker Handler
|
|
26
|
+
```typescript
|
|
27
|
+
// server/worker.ts
|
|
28
|
+
import { createWorkerHandler } from '@everystack/server/worker';
|
|
29
|
+
|
|
30
|
+
export const handler = createWorkerHandler(async () => ({
|
|
31
|
+
'image:process': async (payload) => {
|
|
32
|
+
// payload: { imageId, variants: ['thumb', 'large'] }
|
|
33
|
+
},
|
|
34
|
+
'email:send': async (payload) => {
|
|
35
|
+
// payload: { to, subject, body }
|
|
36
|
+
},
|
|
37
|
+
'analytics:aggregate': async (payload) => {
|
|
38
|
+
// payload: { date, metrics: ['pageviews', 'signups'] }
|
|
39
|
+
},
|
|
40
|
+
}));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Dispatching Jobs
|
|
44
|
+
```typescript
|
|
45
|
+
import { publishJob } from '@everystack/jobs';
|
|
46
|
+
|
|
47
|
+
await publishJob('image:process', {
|
|
48
|
+
imageId: 'abc-123',
|
|
49
|
+
variants: ['thumb', 'large'],
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Client SDK
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { createJobClient } from '@everystack/jobs/client';
|
|
57
|
+
|
|
58
|
+
const jobs = createJobClient({ baseUrl: '/api' });
|
|
59
|
+
await jobs.submit('email:send', { to: 'user@example.com', subject: 'Welcome' });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## SQS Adapter
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { createSqsAdapter } from '@everystack/jobs';
|
|
66
|
+
|
|
67
|
+
const adapter = createSqsAdapter({
|
|
68
|
+
queueUrl: Resource.Jobs.url,
|
|
69
|
+
region: 'us-east-1',
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Progressive dispatch: starts with direct function calls, moves to SQS when you need async processing.
|
|
74
|
+
|
|
75
|
+
## Postgres Materialization
|
|
76
|
+
|
|
77
|
+
Optional: materialize job state to PostgreSQL for dashboard visibility:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { jobsSchema } from '@everystack/jobs/schema';
|
|
81
|
+
// Adds: jobs table with status, type, payload, result, timestamps
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Plugin
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { jobsPlugin } from '@everystack/jobs/plugin';
|
|
88
|
+
// Adds job dispatch routes to the handler
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Gotchas
|
|
92
|
+
|
|
93
|
+
- Workers run in a separate Lambda (not the API Lambda)
|
|
94
|
+
- Dead letter queue catches failed jobs after max retries
|
|
95
|
+
- Job payloads must be JSON-serializable
|
|
96
|
+
- SQS has a 256KB message size limit
|
|
97
|
+
- Workers should be idempotent (SQS delivers at-least-once)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Logging & Analytics
|
|
2
|
+
|
|
3
|
+
> Structured logging, crash reports, and analytics. Import from `@everystack/logging`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when adding observability to a V2+ app.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
### Server-side Logging
|
|
11
|
+
```typescript
|
|
12
|
+
import { createLogSink } from '@everystack/logging';
|
|
13
|
+
|
|
14
|
+
const logSink = createLogSink({
|
|
15
|
+
storage: 's3',
|
|
16
|
+
bucket: Resource.LogsBucket.name,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Pass to Lambda handler
|
|
20
|
+
createLambdaHandler({ logSink, /* ... */ });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Client-side SDK
|
|
24
|
+
```typescript
|
|
25
|
+
import { createLogClient } from '@everystack/logging/client';
|
|
26
|
+
|
|
27
|
+
const logger = createLogClient({
|
|
28
|
+
baseUrl: '/api/logs',
|
|
29
|
+
batchSize: 10,
|
|
30
|
+
flushInterval: 30000,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
logger.info('Page viewed', { page: '/home' });
|
|
34
|
+
logger.error('Payment failed', { error, userId });
|
|
35
|
+
logger.event('button_click', { button: 'signup' });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Log Levels
|
|
39
|
+
|
|
40
|
+
| Level | Use case |
|
|
41
|
+
|-------|----------|
|
|
42
|
+
| `debug` | Development-only, verbose details |
|
|
43
|
+
| `info` | Normal operations, user actions |
|
|
44
|
+
| `warn` | Degraded state, retries, fallbacks |
|
|
45
|
+
| `error` | Failed operations, caught exceptions |
|
|
46
|
+
| `fatal` | Unrecoverable errors, crash reports |
|
|
47
|
+
|
|
48
|
+
## Schema
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { loggingSchema } from '@everystack/logging/schema';
|
|
52
|
+
// Adds: logs table with level, source, message, data, traceId, userId, deviceId, etc.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Include in your handler's schema for database-backed log querying.
|
|
56
|
+
|
|
57
|
+
## CloudWatch Trigger
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { createLogIngestionHandler } from '@everystack/logging/trigger';
|
|
61
|
+
// Processes CloudWatch log events, extracts structured data, stores in S3/DB
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Admin Integration
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { loggingAdminConfig } from '@everystack/logging/admin';
|
|
68
|
+
// Adds log viewer widget to admin dashboard
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## CLI Integration
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
everystack logs:errors --stage dev # Recent errors (DB -> S3 fallback)
|
|
75
|
+
everystack logs:query --stage dev --level error --source api
|
|
76
|
+
everystack logs:tail --stage dev # Raw CloudWatch output
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Plugin
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { loggingPlugin } from '@everystack/logging/plugin';
|
|
83
|
+
// Adds log ingestion routes and log query RPC
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Gotchas
|
|
87
|
+
|
|
88
|
+
- Logs are stored in S3 (cheap, durable) with optional DB materialization
|
|
89
|
+
- Client SDK batches logs and flushes periodically (not per-event)
|
|
90
|
+
- `logs:errors` queries DB first, falls back to S3 if logs table doesn't exist
|
|
91
|
+
- `logs:tail` reads CloudWatch (Lambda container output), not application logs
|