@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,169 @@
|
|
|
1
|
+
# Adding a Database to Your App
|
|
2
|
+
|
|
3
|
+
Your app needs to remember things between sessions. User accounts, saved recipes, posts, settings — data that lives beyond a single visit. This guide walks you through adding a database and data layer to your existing Expo app.
|
|
4
|
+
|
|
5
|
+
## What you're adding
|
|
6
|
+
|
|
7
|
+
You already have a running Expo app. Now you're adding:
|
|
8
|
+
|
|
9
|
+
- **PostgreSQL** — a database that stores your app's data. Think of it as a spreadsheet your app reads and writes automatically.
|
|
10
|
+
- **@everystack/api** — handles requests from your app to the database. When the app asks "show me all recipes," this package translates that into a database query.
|
|
11
|
+
- **@everystack/auth** — user signup, login, and session management. Handles passwords securely and issues tokens that prove who the user is.
|
|
12
|
+
- **@everystack/admin** — a dashboard for managing your app's data (users, content, settings).
|
|
13
|
+
- **@everystack/logging** — structured logging so you can see what your app is doing.
|
|
14
|
+
- **@everystack/security** — device attestation and biometric auth.
|
|
15
|
+
- **@everystack/query** — React hooks that make it easy to fetch and display data.
|
|
16
|
+
- **Drizzle ORM** — defines your database tables in TypeScript. You describe what data you want to store, and Drizzle creates the tables for you.
|
|
17
|
+
|
|
18
|
+
## Step 1: Install PostgreSQL
|
|
19
|
+
|
|
20
|
+
PostgreSQL is the database. It runs as a service on your computer.
|
|
21
|
+
|
|
22
|
+
**macOS:**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
brew install postgresql@16
|
|
26
|
+
brew services start postgresql@16
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Linux:**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
sudo apt install postgresql
|
|
33
|
+
sudo systemctl start postgresql
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Verify it's running
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pg_isready
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
You should see: `accepting connections`. If not, the service isn't running — try the start command again.
|
|
43
|
+
|
|
44
|
+
## Step 2: Create your database
|
|
45
|
+
|
|
46
|
+
A database is like a blank spreadsheet. You need to create one for your app.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
createdb my-app-dev
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Replace `my-app-dev` with your app name plus `-dev` (the `-dev` helps you remember this is your local development database).
|
|
53
|
+
|
|
54
|
+
### Verify it works
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
psql my-app-dev -c "SELECT 1"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
You should see a table with the value `1`. If so, your database is ready.
|
|
61
|
+
|
|
62
|
+
## Step 3: Install V2 packages
|
|
63
|
+
|
|
64
|
+
From your project directory:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pnpm add @everystack/api @everystack/auth @everystack/admin @everystack/logging @everystack/security @everystack/query
|
|
68
|
+
pnpm add drizzle-orm
|
|
69
|
+
pnpm add -D drizzle-kit
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Step 4: Create your database schema
|
|
73
|
+
|
|
74
|
+
The schema defines what data your app stores. Create a file at `db/schema.ts`.
|
|
75
|
+
|
|
76
|
+
A schema is like designing a spreadsheet before you start filling in data. You decide what columns each table has, what type of data goes in each column, and how tables relate to each other.
|
|
77
|
+
|
|
78
|
+
Read everystack://schema-patterns for design patterns and examples. Key conventions:
|
|
79
|
+
|
|
80
|
+
- UUID primary keys with `defaultRandom()`
|
|
81
|
+
- `created_at` and `updated_at` timestamps on all tables
|
|
82
|
+
- Foreign key references with proper cascading
|
|
83
|
+
- Relations defined for both SSR and API query embedding
|
|
84
|
+
- Snake_case column names
|
|
85
|
+
|
|
86
|
+
## Step 5: Configure the handler
|
|
87
|
+
|
|
88
|
+
Create `server/api.ts`. This is the bridge between your app and the database.
|
|
89
|
+
|
|
90
|
+
Read everystack://handler-options for the full reference. At minimum, configure:
|
|
91
|
+
|
|
92
|
+
- `basePath` — the URL prefix for API routes (usually `/api`)
|
|
93
|
+
- `auth.verifyToken` — how to verify JWT tokens
|
|
94
|
+
- `pgSettings` — injects the user's identity into database queries for row-level security
|
|
95
|
+
- `exposedTables` — which tables the API can access (whitelist)
|
|
96
|
+
- `rowOwnership` — which column identifies the owner of each row
|
|
97
|
+
|
|
98
|
+
## Step 6: Set up authentication
|
|
99
|
+
|
|
100
|
+
Read everystack://auth for the full auth flow.
|
|
101
|
+
|
|
102
|
+
- Create auth handlers with `createAuthHandlers()`
|
|
103
|
+
- Create `lib/auth-context.tsx` with `AuthProvider` for your React components
|
|
104
|
+
- Add signup and signin screens to your app
|
|
105
|
+
|
|
106
|
+
## Step 7: Create an API route
|
|
107
|
+
|
|
108
|
+
Create `app/api/[...path]+api.ts` — this is an Expo Router API route that mounts your handler:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { handler } from '../../server/api';
|
|
112
|
+
|
|
113
|
+
export async function GET(request: Request) {
|
|
114
|
+
return handler(request);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function POST(request: Request) {
|
|
118
|
+
return handler(request);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ... PATCH, DELETE
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Step 8: Run migrations
|
|
125
|
+
|
|
126
|
+
Migrations create the actual tables in your database based on your schema.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx drizzle-kit generate
|
|
130
|
+
npx drizzle-kit migrate
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The first command generates SQL files from your schema. The second runs them against your database.
|
|
134
|
+
|
|
135
|
+
## Step 9: Security
|
|
136
|
+
|
|
137
|
+
**This is not optional.** Read everystack://security for the three-layer security model.
|
|
138
|
+
|
|
139
|
+
Your database needs Row Level Security (RLS) policies. These are rules that control who can see and change what data. Even if your app code has a bug, the database enforces access control.
|
|
140
|
+
|
|
141
|
+
At minimum:
|
|
142
|
+
- Create database roles (`anon`, `authenticated`, `admin`)
|
|
143
|
+
- Add RLS policies to every table
|
|
144
|
+
- Set up GRANTs so each role can only access what it should
|
|
145
|
+
|
|
146
|
+
The security resource has copy-paste SQL templates for common patterns.
|
|
147
|
+
|
|
148
|
+
## Step 10: Verify
|
|
149
|
+
|
|
150
|
+
Run your app:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npx expo start
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
You should be able to:
|
|
157
|
+
1. See the app in your browser
|
|
158
|
+
2. Sign up for a new account
|
|
159
|
+
3. Create data (a post, a recipe, etc.)
|
|
160
|
+
4. Refresh the page and see the data persists
|
|
161
|
+
5. Log out and log back in — your data is still there
|
|
162
|
+
|
|
163
|
+
## What's next
|
|
164
|
+
|
|
165
|
+
Continue building features. If your app later needs file uploads or background processing (like sending emails or resizing images), those are separate packages you can add incrementally:
|
|
166
|
+
|
|
167
|
+
- **File uploads:** `@everystack/storage` — read everystack://storage
|
|
168
|
+
- **Background jobs:** `@everystack/jobs` — read everystack://jobs
|
|
169
|
+
- **Image processing:** `@everystack/images` — read everystack://images
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Admin Dashboard
|
|
2
|
+
|
|
3
|
+
> Declarative admin dashboard for everystack apps. Import from `@everystack/admin`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when adding an admin interface to a V2+ app.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { AdminRoot, AdminLayout, EverystackAdapter } from '@everystack/admin';
|
|
12
|
+
|
|
13
|
+
const adapter = new EverystackAdapter({ baseUrl: '/api' });
|
|
14
|
+
|
|
15
|
+
const config = {
|
|
16
|
+
resources: {
|
|
17
|
+
posts: {
|
|
18
|
+
fields: {
|
|
19
|
+
id: { type: 'text', label: 'ID' },
|
|
20
|
+
title: { type: 'text', label: 'Title' },
|
|
21
|
+
body: { type: 'textarea', label: 'Body' },
|
|
22
|
+
status: { type: 'select', label: 'Status', options: ['draft', 'published'] },
|
|
23
|
+
authorId: { type: 'reference', label: 'Author', reference: 'users' },
|
|
24
|
+
createdAt: { type: 'date', label: 'Created' },
|
|
25
|
+
},
|
|
26
|
+
list: { columns: ['title', 'status', 'createdAt'] },
|
|
27
|
+
edit: { fields: ['title', 'body', 'status'] },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default function AdminRootLayout() {
|
|
33
|
+
return (
|
|
34
|
+
<AdminRoot config={config} adapter={adapter}>
|
|
35
|
+
<AdminLayout onNavigate={router.push}>
|
|
36
|
+
<Slot />
|
|
37
|
+
</AdminLayout>
|
|
38
|
+
</AdminRoot>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Field Types
|
|
44
|
+
|
|
45
|
+
| Type | Description |
|
|
46
|
+
|------|-------------|
|
|
47
|
+
| `text` | Single-line text input |
|
|
48
|
+
| `textarea` | Multi-line text |
|
|
49
|
+
| `number` | Numeric input |
|
|
50
|
+
| `date` | Date picker |
|
|
51
|
+
| `boolean` | Toggle/checkbox |
|
|
52
|
+
| `select` | Dropdown (requires `options`) |
|
|
53
|
+
| `reference` | Foreign key reference (requires `reference` table name) |
|
|
54
|
+
| `json` | JSON editor |
|
|
55
|
+
| `image` | Image URL with preview |
|
|
56
|
+
|
|
57
|
+
## EverystackAdapter
|
|
58
|
+
|
|
59
|
+
Connects the admin dashboard to the PostgREST API:
|
|
60
|
+
```typescript
|
|
61
|
+
const adapter = new EverystackAdapter({
|
|
62
|
+
baseUrl: '/api',
|
|
63
|
+
getToken: () => token,
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Methods: `getList`, `getOne`, `create`, `update`, `delete`. Translates admin operations to PostgREST queries.
|
|
68
|
+
|
|
69
|
+
## Presets
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { twitterPreset } from '@everystack/admin/presets/twitter';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Presets provide pre-configured admin layouts for common app patterns.
|
|
76
|
+
|
|
77
|
+
## Gotchas
|
|
78
|
+
|
|
79
|
+
- Admin pages should be behind auth (add auth check in layout)
|
|
80
|
+
- EverystackAdapter respects `exposedTables` and `hiddenColumns` from the handler
|
|
81
|
+
- Reference fields require the referenced table to be in `exposedTables`
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Authentication
|
|
2
|
+
|
|
3
|
+
> JWT auth flows, OAuth, edge verification. Import from `@everystack/auth`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when adding user authentication to a V2+ app.
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { createAuthHandlers } from '@everystack/auth';
|
|
12
|
+
import { createDb, getJwtSecret } from '@everystack/server/db';
|
|
13
|
+
|
|
14
|
+
const { db } = createDb(schema);
|
|
15
|
+
const auth = createAuthHandlers(db, schema, getJwtSecret());
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`getJwtSecret()` reads the JWT secret from SST Resource linking (`Resource.JwtSecret.value`).
|
|
19
|
+
|
|
20
|
+
## Auth Handlers
|
|
21
|
+
|
|
22
|
+
`createAuthHandlers()` returns Web Standard request handlers:
|
|
23
|
+
|
|
24
|
+
| Handler | Method | Path | Description |
|
|
25
|
+
|---------|--------|------|-------------|
|
|
26
|
+
| `signup` | POST | `/api/auth/signup` | Create account (email + password) |
|
|
27
|
+
| `signin` | POST | `/api/auth/signin` | Login, returns access + refresh token |
|
|
28
|
+
| `refresh` | POST | `/api/auth/refresh` | Exchange refresh token for new access token |
|
|
29
|
+
| `verifyToken` | - | - | JWT verification function (for handler auth config) |
|
|
30
|
+
|
|
31
|
+
### Route Setup
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
export const handler = createLambdaHandler({
|
|
35
|
+
init: async () => ({ api, ...auth }),
|
|
36
|
+
routes: (h) => [
|
|
37
|
+
{ path: '/api/auth/signup', method: 'POST', exact: true, handler: h.signup },
|
|
38
|
+
{ path: '/api/auth/signin', method: 'POST', exact: true, handler: h.signin },
|
|
39
|
+
{ path: '/api/auth/refresh', method: 'POST', exact: true, handler: h.refresh },
|
|
40
|
+
{ path: '/api', handler: h.api },
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Token Lifecycle
|
|
46
|
+
|
|
47
|
+
1. **Signup**: creates user, hashes password (bcrypt, cost 12), returns access + refresh tokens
|
|
48
|
+
2. **Signin**: verifies password, returns access + refresh tokens
|
|
49
|
+
3. **Access token**: short-lived JWT (15 min recommended for edge, 1h otherwise)
|
|
50
|
+
4. **Refresh token**: long-lived, DB-backed, one-time-use rotation (old token invalidated on use)
|
|
51
|
+
|
|
52
|
+
## Edge JWT Verification
|
|
53
|
+
|
|
54
|
+
CloudFront Functions verify JWTs before requests reach Lambda:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { generateCffVerifier } from '@everystack/auth/cff';
|
|
58
|
+
|
|
59
|
+
const source = generateCffVerifier({
|
|
60
|
+
functionName: 'verifyJwt',
|
|
61
|
+
clockSkewSec: 30,
|
|
62
|
+
});
|
|
63
|
+
// source is portable ES2019 JS for CloudFront Functions runtime
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Properties: HS256 only, constant-time comparison, algorithm pinning (prevents alg=none attacks), no external dependencies.
|
|
67
|
+
|
|
68
|
+
## OAuth
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { createOAuthHandlers } from '@everystack/auth/oauth';
|
|
72
|
+
|
|
73
|
+
const oauth = createOAuthHandlers(db, schema, getJwtSecret(), {
|
|
74
|
+
providers: {
|
|
75
|
+
google: { clientId: '...', clientSecret: '...' },
|
|
76
|
+
apple: { clientId: '...', teamId: '...', keyId: '...', privateKey: '...' },
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## React Client
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { AuthProvider, useAuth } from '@everystack/auth/client';
|
|
85
|
+
|
|
86
|
+
// Wrap your app
|
|
87
|
+
<AuthProvider baseUrl="/api/auth">
|
|
88
|
+
<App />
|
|
89
|
+
</AuthProvider>
|
|
90
|
+
|
|
91
|
+
// In components
|
|
92
|
+
const { user, signIn, signUp, signOut, isLoading } = useAuth();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Auth Plugin
|
|
96
|
+
|
|
97
|
+
For plugin-based composition:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { authPlugin } from '@everystack/auth/plugin';
|
|
101
|
+
|
|
102
|
+
// Adds signup, signin, refresh, verify, signout routes
|
|
103
|
+
// Decorates verifyToken with audience check, client resolution, device attestation
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Plugin layers: audience check -> client resolution -> device attestation -> custom claims validation -> claims enrichment.
|
|
107
|
+
|
|
108
|
+
## Gotchas
|
|
109
|
+
|
|
110
|
+
- JWT secret must be stored in SST secrets, never in code
|
|
111
|
+
- Access tokens should be 15 min max when using edge verification
|
|
112
|
+
- Refresh tokens are one-time-use: using a refresh token invalidates it
|
|
113
|
+
- bcrypt cost factor defaults to 12 (configurable)
|
|
114
|
+
- `verifyToken` returns the JWT payload (not just true/false)
|
|
115
|
+
- The `publicRpc` array skips BOTH token auth AND client auth
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Setting Up AWS for everystack
|
|
2
|
+
|
|
3
|
+
AWS (Amazon Web Services) rents you computers on the internet. When you deploy your app, it runs on AWS servers so anyone in the world can use it. This guide walks you through creating an account and giving your computer permission to deploy.
|
|
4
|
+
|
|
5
|
+
## What does everystack use on AWS?
|
|
6
|
+
|
|
7
|
+
Your app is made up of a few building blocks. Each one is an AWS service:
|
|
8
|
+
|
|
9
|
+
| Service | What it does | Plain English | Tier | Typical cost |
|
|
10
|
+
|---------|-------------|---------------|------|-------------|
|
|
11
|
+
| **S3** | File storage | Holds your app's files (HTML, CSS, JavaScript, images) | V1+ | Pennies/month |
|
|
12
|
+
| **CloudFront** | Content delivery network | Makes your app load fast for users worldwide | V1+ | Free tier covers most small apps |
|
|
13
|
+
| **Lambda** | Serverless compute | Runs your server code only when someone visits | V1+ | Free tier: 1M requests/month |
|
|
14
|
+
| **RDS** | Managed database | Stores your users, posts, and data (Aurora Serverless) | V2+ | ~$15/month minimum |
|
|
15
|
+
| **SQS** | Message queue | Processes background tasks like sending emails | V3 | Pennies/month |
|
|
16
|
+
|
|
17
|
+
**Total cost for a small app with low traffic:** Under $5/month for V1, ~$20/month for V2+ (the database is the main cost).
|
|
18
|
+
|
|
19
|
+
AWS has a **free tier** for the first 12 months that covers most of what everystack uses at low traffic. You will not be charged anything significant while learning.
|
|
20
|
+
|
|
21
|
+
## Step 1: Create an AWS account
|
|
22
|
+
|
|
23
|
+
1. Go to https://aws.amazon.com/free
|
|
24
|
+
2. Click **Create a Free Account**
|
|
25
|
+
3. You will need:
|
|
26
|
+
- An email address
|
|
27
|
+
- A credit card (required for verification, but free tier usage will not be charged)
|
|
28
|
+
- A phone number for verification
|
|
29
|
+
4. Choose the **Basic Support** plan (free)
|
|
30
|
+
5. After account creation, sign in to the AWS Console at https://console.aws.amazon.com to confirm it works
|
|
31
|
+
|
|
32
|
+
## Step 2: Create an IAM user for everystack
|
|
33
|
+
|
|
34
|
+
Your AWS account has a "root user" (the email you signed up with). The root user has unlimited power over your account. You should never use it for daily work. Instead, create a dedicated user just for everystack.
|
|
35
|
+
|
|
36
|
+
**IAM** stands for Identity and Access Management. It controls who can do what in your AWS account.
|
|
37
|
+
|
|
38
|
+
### Create the user
|
|
39
|
+
|
|
40
|
+
1. Sign in to the **AWS Console** at https://console.aws.amazon.com
|
|
41
|
+
2. In the top search bar, type **IAM** and click on it
|
|
42
|
+
3. Click **Users** in the left sidebar
|
|
43
|
+
4. Click **Create user**
|
|
44
|
+
5. Enter the user name: `everystack-dev`
|
|
45
|
+
6. Click **Next**
|
|
46
|
+
|
|
47
|
+
### Create the permissions policy
|
|
48
|
+
|
|
49
|
+
This policy gives the user exactly the permissions SST needs to deploy your app.
|
|
50
|
+
|
|
51
|
+
7. Select **Attach policies directly**
|
|
52
|
+
8. Click **Create policy** (this opens a new tab)
|
|
53
|
+
9. Click the **JSON** tab
|
|
54
|
+
10. Delete anything in the editor and paste this:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"Version": "2012-10-17",
|
|
59
|
+
"Statement": [
|
|
60
|
+
{
|
|
61
|
+
"Sid": "EverystackDeploy",
|
|
62
|
+
"Effect": "Allow",
|
|
63
|
+
"Action": [
|
|
64
|
+
"cloudformation:*",
|
|
65
|
+
"s3:*",
|
|
66
|
+
"lambda:*",
|
|
67
|
+
"cloudfront:*",
|
|
68
|
+
"iam:CreateRole",
|
|
69
|
+
"iam:DeleteRole",
|
|
70
|
+
"iam:GetRole",
|
|
71
|
+
"iam:GetRolePolicy",
|
|
72
|
+
"iam:PassRole",
|
|
73
|
+
"iam:AttachRolePolicy",
|
|
74
|
+
"iam:DetachRolePolicy",
|
|
75
|
+
"iam:PutRolePolicy",
|
|
76
|
+
"iam:DeleteRolePolicy",
|
|
77
|
+
"iam:ListRolePolicies",
|
|
78
|
+
"iam:ListAttachedRolePolicies",
|
|
79
|
+
"iam:TagRole",
|
|
80
|
+
"iam:UntagRole",
|
|
81
|
+
"iam:CreateServiceLinkedRole",
|
|
82
|
+
"rds:*",
|
|
83
|
+
"ec2:DescribeVpcs",
|
|
84
|
+
"ec2:DescribeSubnets",
|
|
85
|
+
"ec2:DescribeSecurityGroups",
|
|
86
|
+
"ec2:DescribeRouteTables",
|
|
87
|
+
"ec2:DescribeAvailabilityZones",
|
|
88
|
+
"ec2:DescribeVpcEndpoints",
|
|
89
|
+
"ec2:CreateSecurityGroup",
|
|
90
|
+
"ec2:DeleteSecurityGroup",
|
|
91
|
+
"ec2:AuthorizeSecurityGroupIngress",
|
|
92
|
+
"ec2:RevokeSecurityGroupIngress",
|
|
93
|
+
"ec2:AuthorizeSecurityGroupEgress",
|
|
94
|
+
"ec2:RevokeSecurityGroupEgress",
|
|
95
|
+
"ec2:CreateVpcEndpoint",
|
|
96
|
+
"ec2:DeleteVpcEndpoint",
|
|
97
|
+
"ec2:CreateTags",
|
|
98
|
+
"ec2:DeleteTags",
|
|
99
|
+
"route53:*",
|
|
100
|
+
"sqs:*",
|
|
101
|
+
"ssm:*",
|
|
102
|
+
"logs:*",
|
|
103
|
+
"sts:GetCallerIdentity",
|
|
104
|
+
"sts:AssumeRole"
|
|
105
|
+
],
|
|
106
|
+
"Resource": "*"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
11. Click **Next**
|
|
113
|
+
12. Name the policy: `everystack-dev-policy`
|
|
114
|
+
13. Optionally add a description: "Permissions for everystack SST deploys"
|
|
115
|
+
14. Click **Create policy**
|
|
116
|
+
|
|
117
|
+
### Attach the policy to the user
|
|
118
|
+
|
|
119
|
+
15. Go back to the **Create user** tab in your browser
|
|
120
|
+
16. Click the refresh button on the policy list
|
|
121
|
+
17. Search for `everystack-dev-policy`
|
|
122
|
+
18. Check the box next to it
|
|
123
|
+
19. Click **Next**, then **Create user**
|
|
124
|
+
|
|
125
|
+
### Create an access key
|
|
126
|
+
|
|
127
|
+
20. Click on the user name **everystack-dev**
|
|
128
|
+
21. Go to the **Security credentials** tab
|
|
129
|
+
22. Under **Access keys**, click **Create access key**
|
|
130
|
+
23. Select **Command Line Interface (CLI)**
|
|
131
|
+
24. Check the confirmation checkbox, click **Next**, then **Create access key**
|
|
132
|
+
25. **Save both keys now.** You will not see the secret key again after this page:
|
|
133
|
+
- **Access key ID** (looks like: `AKIAIOSFODNN7EXAMPLE`)
|
|
134
|
+
- **Secret access key** (looks like: `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`)
|
|
135
|
+
|
|
136
|
+
## Step 3: Configure your computer
|
|
137
|
+
|
|
138
|
+
Open a terminal and run:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
aws configure
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
It will ask four questions:
|
|
145
|
+
|
|
146
|
+
- **AWS Access Key ID:** Paste the access key ID from Step 2
|
|
147
|
+
- **AWS Secret Access Key:** Paste the secret access key from Step 2
|
|
148
|
+
- **Default region name:** `us-east-1` (recommended, or choose your nearest region)
|
|
149
|
+
- **Default output format:** `json`
|
|
150
|
+
|
|
151
|
+
## Step 4: Verify it works
|
|
152
|
+
|
|
153
|
+
Run this command:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
aws sts get-caller-identity
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
You should see something like:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"UserId": "AIDAIOSFODNN7EXAMPLE",
|
|
164
|
+
"Account": "123456789012",
|
|
165
|
+
"Arn": "arn:aws:iam::123456789012:user/everystack-dev"
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
If you see your account number and `everystack-dev`, your credentials are working. You are ready to deploy.
|
|
170
|
+
|
|
171
|
+
## Production hardening
|
|
172
|
+
|
|
173
|
+
The `everystack-dev` user above has broad permissions suitable for getting started. When you are ready to harden your setup for production, read `everystack://security` for a three-profile model that separates infrastructure creation, day-to-day operations, and CI/CD into distinct IAM users with minimal permissions.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
> Full command reference for the `everystack` CLI. Import from `@everystack/cli`.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
Read this when deploying, debugging, or managing a deployed everystack app. All commands use AWS IAM credentials (not shared secrets).
|
|
7
|
+
|
|
8
|
+
## Authentication
|
|
9
|
+
|
|
10
|
+
| Operation | Auth Mechanism |
|
|
11
|
+
|-----------|---------------|
|
|
12
|
+
| `db:migrate`, `db:seed`, `console` | IAM -> Lambda invoke |
|
|
13
|
+
| `update --platform web` | IAM -> S3 PutObject + Lambda invoke |
|
|
14
|
+
| `update --platform ios/android` | `EVERYSTACK_TOKEN` -> HTTP POST |
|
|
15
|
+
| `logs:errors`, `logs:query` | IAM -> Lambda invoke |
|
|
16
|
+
| `logs:tail` | IAM -> CloudWatch FilterLogEvents |
|
|
17
|
+
| `cache:purge` | IAM -> CloudFront KVS |
|
|
18
|
+
| `certs:*` | Local only (no network) |
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
### OTA Updates
|
|
23
|
+
```bash
|
|
24
|
+
everystack update --channel production --message "Fix login bug"
|
|
25
|
+
everystack update --channel production --platform ios --message "iOS fix"
|
|
26
|
+
everystack update --channel staging --platform web
|
|
27
|
+
```
|
|
28
|
+
Flags: `--channel` (default: production), `--message`, `--platform` (ios/android/web/all), `--skip-export`.
|
|
29
|
+
|
|
30
|
+
### Database
|
|
31
|
+
```bash
|
|
32
|
+
everystack db:migrate # Run migrations via Lambda
|
|
33
|
+
everystack db:seed # Seed database (dev only)
|
|
34
|
+
everystack db:psql --stage dev -c "SELECT * FROM posts" # Read-only SQL via Lambda
|
|
35
|
+
everystack console --stage dev # Interactive REPL with db + schema
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The REPL has `db`, `schema`, `eq`, `and`, `or`, `gt`, `lt`, `count`, `sum`, `avg`, `sql`, `desc`, `asc` in scope.
|
|
39
|
+
|
|
40
|
+
### Logs
|
|
41
|
+
```bash
|
|
42
|
+
everystack logs:errors --stage dev # Recent errors (DB -> S3 fallback)
|
|
43
|
+
everystack logs:errors --stage dev --limit 50 --level fatal
|
|
44
|
+
everystack logs:tail --stage dev # CloudWatch Lambda output
|
|
45
|
+
everystack logs:tail --stage dev --filter ERROR --since 1h
|
|
46
|
+
everystack logs:query --stage dev --level error --source api
|
|
47
|
+
everystack logs:query --stage dev --traceId "abc123"
|
|
48
|
+
everystack logs:query --stage dev --userId "user_123" --since 30m
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Cache
|
|
52
|
+
```bash
|
|
53
|
+
everystack cache:purge # Global cache bust
|
|
54
|
+
everystack cache:purge --origin web # Per-origin
|
|
55
|
+
everystack cache:purge --path "/api/posts" # Per-path
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Code Signing
|
|
59
|
+
```bash
|
|
60
|
+
everystack certs:generate --output ./certs # Generate RSA key pair
|
|
61
|
+
everystack certs:configure --input ./certs --keyid main # Add to app.json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Channels
|
|
65
|
+
```bash
|
|
66
|
+
everystack channels list
|
|
67
|
+
everystack channels create --name staging
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### SSR Debugging
|
|
71
|
+
```bash
|
|
72
|
+
everystack diag https://myapp.com # Version + cache check
|
|
73
|
+
everystack diag https://myapp.com/page --hydration # Runtime hydration analysis
|
|
74
|
+
everystack analyze:ssr # Static analysis for SSR anti-patterns
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
The CLI auto-discovers resources from `.sst/outputs.json` (written by `sst deploy`). Required outputs:
|
|
80
|
+
```typescript
|
|
81
|
+
return {
|
|
82
|
+
routerUrl: router.url,
|
|
83
|
+
apiFunctionName: api.name,
|
|
84
|
+
updatesBucket: updates.name,
|
|
85
|
+
clientBundlesBucket: clientBundles.name,
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Use `--stage` flag to target specific deployments: reads from `.sst/outputs.{stage}.json`.
|
|
90
|
+
|
|
91
|
+
## Environment Variables
|
|
92
|
+
|
|
93
|
+
| Variable | Purpose |
|
|
94
|
+
|----------|---------|
|
|
95
|
+
| `AWS_REGION` | AWS region (default: us-east-1) |
|
|
96
|
+
| `AWS_PROFILE` | AWS credentials profile |
|
|
97
|
+
| `EVERYSTACK_TOKEN` | JWT for authenticated mobile uploads |
|
|
98
|
+
|
|
99
|
+
## Lambda onAction Integration
|
|
100
|
+
|
|
101
|
+
The CLI invokes Lambda with `_action` payloads. Your handler must dispatch them:
|
|
102
|
+
```typescript
|
|
103
|
+
onAction: async (action, payload) => {
|
|
104
|
+
if (action === 'migrate') return runMigrations(db, './drizzle');
|
|
105
|
+
if (action === 'seed') return runSeed(db, schema);
|
|
106
|
+
// ... console, db:psql, logs:errors, logs:query, etc.
|
|
107
|
+
}
|
|
108
|
+
```
|