@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
|
@@ -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.
|
package/dist/images.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
## S3 Origin Cache
|
|
69
|
+
|
|
70
|
+
CloudFront caches are per-region. Enable `s3Cache` to persist rendered images to S3 so the first Sharp render is the last, globally:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
export const handler = createImageHandler({
|
|
74
|
+
bucket: Resource.Media.name,
|
|
75
|
+
s3Cache: { enabled: true },
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Cache keys are deterministic from parsed params. Add a 30-day lifecycle rule on the `cache/` prefix to auto-expire stale renders. To clean up immediately when an original is deleted:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { deleteImageCache } from '@everystack/server/image';
|
|
83
|
+
await deleteImageCache(bucket, 'uploads/photo.jpg');
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
See `docs/caching.md` for full setup.
|
|
87
|
+
|
|
88
|
+
## Gotchas
|
|
89
|
+
|
|
90
|
+
- Sharp runs on Lambda ARM64 (uses Lambda layer or bundled binary)
|
|
91
|
+
- First request for a variant is slow (processing), subsequent are cached by CloudFront and S3
|
|
92
|
+
- With `s3Cache` enabled, Sharp runs once per variant globally (not once per CloudFront region)
|
|
93
|
+
- AVIF encoding is slower than WebP but produces smaller files
|