@everystack/mcp 0.2.2 → 0.3.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/LICENSE +681 -0
- package/README.md +45 -10
- package/dist/adding-database.md +169 -0
- package/dist/admin.md +81 -0
- package/dist/auth.md +115 -0
- package/dist/aws-setup.md +276 -0
- package/dist/cli.md +108 -0
- package/dist/client-api.md +145 -0
- package/dist/core.md +196 -0
- package/dist/deployment.md +146 -0
- package/dist/events.md +87 -0
- package/dist/first-run.md +100 -0
- package/dist/getting-started.md +75 -0
- package/dist/handler-options.md +114 -0
- package/dist/images.md +93 -0
- package/dist/index.cjs +23726 -0
- package/dist/jobs.md +97 -0
- package/dist/logging.md +91 -0
- package/dist/plugins.md +68 -0
- package/dist/project-claude-md.md +102 -0
- package/dist/query-protocol.md +129 -0
- package/dist/schema-patterns.md +167 -0
- package/dist/security-device.md +99 -0
- package/dist/security.md +270 -0
- package/dist/ssr.md +82 -0
- package/dist/storage.md +63 -0
- package/dist/testing.md +118 -0
- package/package.json +26 -14
- package/src/gates/detectors/embedded-data-bundle.ts +58 -0
- package/src/gates/detectors/hand-written-migration.ts +42 -0
- package/src/gates/detectors/secret-in-public-env.ts +41 -0
- package/src/gates/engine.ts +80 -0
- package/src/gates/registry.ts +25 -0
- package/src/gates/telemetry.ts +143 -0
- package/src/gates/types.ts +70 -0
- package/src/governance/cli.ts +193 -0
- package/src/governance/grounding.ts +344 -0
- package/src/index.ts +97 -50
- package/src/prompts/claude-md.ts +90 -0
- package/src/prompts/governance-setup.ts +85 -0
- package/src/prompts/index.ts +4 -0
- package/src/prompts/new-app.ts +4 -1
- package/src/resources/project-claude-md.md +69 -94
- package/src/tools/index.ts +6 -39
package/README.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# @everystack/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The governance layer that governs how any agent builds everystack. Beyond architecture knowledge
|
|
4
|
+
and guided prompts, it keeps the build **on-script**: a **grounding gate** (read the project
|
|
5
|
+
contract before editing) and **cheat gates** (block the training-consensus shortcuts — bundling
|
|
6
|
+
data instead of using the DB, hand-writing migrations, leaking a secret into the client bundle),
|
|
7
|
+
with **telemetry** that records what the agent tried. The teeth run as Claude Code hooks; the same
|
|
8
|
+
logic is importable so the operator CLI can self-gate at deploy.
|
|
9
|
+
|
|
10
|
+
**Governance setup (hooks + telemetry): [docs/governance-setup.md](docs/governance-setup.md).**
|
|
4
11
|
|
|
5
12
|
## Setup
|
|
6
13
|
|
|
@@ -59,15 +66,28 @@ Claude reads these to understand everystack architecture and conventions.
|
|
|
59
66
|
- `everystack://events` — Real-time events via LISTEN/NOTIFY + WebSocket
|
|
60
67
|
- `everystack://cli` — CLI command reference
|
|
61
68
|
|
|
62
|
-
###
|
|
69
|
+
### Governance (hooks)
|
|
70
|
+
|
|
71
|
+
The teeth. Run as Claude Code hooks via the `everystack-mcp` bin — see
|
|
72
|
+
[docs/governance-setup.md](docs/governance-setup.md).
|
|
63
73
|
|
|
64
|
-
|
|
74
|
+
| Subcommand | Hook | Role |
|
|
75
|
+
|------------|------|------|
|
|
76
|
+
| `context` | SessionStart | inject the contract to read |
|
|
77
|
+
| `gate` | PreToolUse | block until grounded; block cheat gates |
|
|
78
|
+
| `mark` | PostToolUse(Read) | record a contract read |
|
|
79
|
+
| `validate` | PostToolUse(Write\|Edit) | surface a cheat the write landed |
|
|
80
|
+
| `report` | — | summarize the per-session telemetry |
|
|
81
|
+
|
|
82
|
+
### Tools (Project Introspection)
|
|
65
83
|
|
|
66
84
|
| Tool | Purpose |
|
|
67
85
|
|------|---------|
|
|
68
|
-
| `
|
|
69
|
-
|
|
70
|
-
|
|
86
|
+
| `check_environment` | Verify dev/deploy prerequisites (Node, pnpm, git, Expo, SST, AWS CLI, PostgreSQL) |
|
|
87
|
+
|
|
88
|
+
> The legacy regex tools (`project_status`, `schema_analyze`, `project_validate`) were removed:
|
|
89
|
+
> they predated the v3 Model/Module surface and returned wrong answers on Model-based apps. They are
|
|
90
|
+
> being rebuilt on `@everystack/model` (the pure compiler) so introspection matches reality.
|
|
71
91
|
|
|
72
92
|
### Prompts (Guided Workflows)
|
|
73
93
|
|
|
@@ -84,17 +104,32 @@ Structured prompts that guide Claude through multi-step tasks.
|
|
|
84
104
|
|
|
85
105
|
## Design
|
|
86
106
|
|
|
87
|
-
**
|
|
107
|
+
**Framework-aware.** Depends on `@everystack/model` and `@everystack/cli` (plus
|
|
108
|
+
`@modelcontextprotocol/sdk` and `zod`). An enforcement layer must track the framework version — it
|
|
109
|
+
cannot float free of it. The cheat detectors reuse the CLI's shipped scanners (e.g. the canonical
|
|
110
|
+
secret-shape patterns from `@everystack/cli/audit`) rather than duplicating them, loaded lazily so
|
|
111
|
+
the common tool call stays fast.
|
|
88
112
|
|
|
89
|
-
**Local-only.**
|
|
113
|
+
**Local-only.** No network, no AWS. The grounding gate and cheat gates observe tool-call metadata
|
|
114
|
+
and the proposed file content; they never write files themselves. Telemetry is a local JSONL under
|
|
115
|
+
`~/.everystack/governance`.
|
|
90
116
|
|
|
91
|
-
**
|
|
117
|
+
**Fail-open.** A governance bug never bricks tool use — only the explicit "ungrounded" and "cheat
|
|
118
|
+
detected" conditions fail closed.
|
|
92
119
|
|
|
93
120
|
**Curated resources.** The markdown files are optimized for Claude consumption — organized by task, not by package. Each follows a consistent structure: When to Use, Setup, API Reference, Common Patterns, Gotchas.
|
|
94
121
|
|
|
95
122
|
## Development
|
|
96
123
|
|
|
97
124
|
```bash
|
|
98
|
-
pnpm --filter @everystack/mcp test # Run tests (
|
|
125
|
+
pnpm --filter @everystack/mcp test # Run tests (206 passing)
|
|
99
126
|
pnpm --filter @everystack/mcp lint # Type check
|
|
100
127
|
```
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
[AGPL-3.0-only](https://www.gnu.org/licenses/agpl-3.0.html) © Scalable Technology, Inc.
|
|
132
|
+
|
|
133
|
+
A commercial license is available for organizations that cannot or do not wish to
|
|
134
|
+
comply with the AGPL-3.0 terms. For commercial licensing, contact
|
|
135
|
+
licensing@scalable.technology.
|
|
@@ -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
|
package/dist/admin.md
ADDED
|
@@ -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`
|
package/dist/auth.md
ADDED
|
@@ -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
|