@hivehub/rulebook 4.2.1 → 4.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/.claude/commands/continue.md +33 -33
- package/.claude/commands/ralph-config.md +112 -112
- package/.claude/commands/ralph-history.md +110 -110
- package/.claude/commands/ralph-init.md +72 -72
- package/.claude/commands/ralph-pause-resume.md +105 -105
- package/.claude/commands/ralph-run.md +101 -101
- package/.claude/commands/ralph-status.md +76 -76
- package/.claude/commands/rulebook-memory-save.md +48 -48
- package/.claude/commands/rulebook-memory-search.md +47 -47
- package/.claude/commands/rulebook-task-apply.md +67 -67
- package/.claude/commands/rulebook-task-archive.md +70 -70
- package/.claude/commands/rulebook-task-create.md +93 -93
- package/.claude/commands/rulebook-task-list.md +42 -42
- package/.claude/commands/rulebook-task-show.md +52 -52
- package/.claude/commands/rulebook-task-validate.md +53 -53
- package/.claude-plugin/marketplace.json +28 -28
- package/.claude-plugin/plugin.json +8 -8
- package/README.md +8 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +4 -4
- package/dist/cli/commands.js.map +1 -1
- package/dist/core/claude-mcp.d.ts +8 -1
- package/dist/core/claude-mcp.d.ts.map +1 -1
- package/dist/core/claude-mcp.js +32 -1
- package/dist/core/claude-mcp.js.map +1 -1
- package/dist/core/generator.d.ts +13 -0
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +283 -28
- package/dist/core/generator.js.map +1 -1
- package/dist/core/workspace/project-worker.d.ts.map +1 -1
- package/dist/core/workspace/project-worker.js +3 -0
- package/dist/core/workspace/project-worker.js.map +1 -1
- package/dist/core/workspace/workspace-manager.d.ts.map +1 -1
- package/dist/core/workspace/workspace-manager.js +2 -6
- package/dist/core/workspace/workspace-manager.js.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/rulebook-server.d.ts.map +1 -1
- package/dist/mcp/rulebook-server.js +6 -5
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/package.json +21 -22
- package/templates/agents/accessibility-reviewer.md +43 -0
- package/templates/agents/api-designer.md +42 -0
- package/templates/agents/architect.md +51 -0
- package/templates/agents/build-engineer.md +36 -0
- package/templates/agents/code-reviewer.md +47 -0
- package/templates/agents/database-architect.md +41 -0
- package/templates/agents/devops-engineer.md +42 -0
- package/templates/agents/docs-writer.md +38 -0
- package/templates/agents/i18n-engineer.md +42 -0
- package/templates/agents/implementer.md +38 -35
- package/templates/agents/migration-engineer.md +42 -0
- package/templates/agents/performance-engineer.md +49 -0
- package/templates/agents/refactoring-agent.md +41 -0
- package/templates/agents/researcher.md +38 -34
- package/templates/agents/security-reviewer.md +40 -0
- package/templates/agents/team-lead.md +37 -34
- package/templates/agents/tester.md +45 -42
- package/templates/agents/ux-reviewer.md +43 -0
- package/templates/ci/rulebook-review.yml +26 -26
- package/templates/cli/AIDER.md +49 -49
- package/templates/cli/AMAZON_Q.md +25 -25
- package/templates/cli/AUGGIE.md +32 -32
- package/templates/cli/CLAUDE.md +117 -117
- package/templates/cli/CLINE.md +99 -99
- package/templates/cli/CODEBUDDY.md +20 -20
- package/templates/cli/CODEIUM.md +20 -20
- package/templates/cli/CODEX.md +21 -21
- package/templates/cli/CONTINUE.md +34 -34
- package/templates/cli/CURSOR_CLI.md +62 -62
- package/templates/cli/FACTORY.md +18 -18
- package/templates/cli/GEMINI.md +35 -35
- package/templates/cli/KILOCODE.md +18 -18
- package/templates/cli/OPENCODE.md +18 -18
- package/templates/cli/_GENERIC_TEMPLATE.md +29 -29
- package/templates/commands/rulebook-memory-save.md +48 -48
- package/templates/commands/rulebook-memory-search.md +47 -47
- package/templates/commands/rulebook-task-apply.md +67 -67
- package/templates/commands/rulebook-task-archive.md +94 -94
- package/templates/commands/rulebook-task-create.md +93 -93
- package/templates/commands/rulebook-task-list.md +42 -42
- package/templates/commands/rulebook-task-show.md +52 -52
- package/templates/commands/rulebook-task-validate.md +53 -53
- package/templates/core/AGENTS_LEAN.md +25 -25
- package/templates/core/AGENTS_OVERRIDE.md +16 -16
- package/templates/core/AGENT_AUTOMATION.md +288 -288
- package/templates/core/DAG.md +304 -304
- package/templates/core/DOCUMENTATION_RULES.md +36 -36
- package/templates/core/MULTI_AGENT.md +74 -74
- package/templates/core/PLANS.md +28 -28
- package/templates/core/QUALITY_ENFORCEMENT.md +68 -68
- package/templates/core/RALPH.md +471 -471
- package/templates/core/RULEBOOK.md +1935 -1935
- package/templates/frameworks/ANGULAR.md +36 -36
- package/templates/frameworks/DJANGO.md +83 -83
- package/templates/frameworks/ELECTRON.md +147 -147
- package/templates/frameworks/FLASK.md +38 -38
- package/templates/frameworks/FLUTTER.md +55 -55
- package/templates/frameworks/JQUERY.md +32 -32
- package/templates/frameworks/LARAVEL.md +38 -38
- package/templates/frameworks/NESTJS.md +43 -43
- package/templates/frameworks/NEXTJS.md +127 -127
- package/templates/frameworks/NUXT.md +40 -40
- package/templates/frameworks/RAILS.md +66 -66
- package/templates/frameworks/REACT.md +38 -38
- package/templates/frameworks/REACT_NATIVE.md +47 -47
- package/templates/frameworks/SPRING.md +39 -39
- package/templates/frameworks/SYMFONY.md +36 -36
- package/templates/frameworks/VUE.md +36 -36
- package/templates/frameworks/ZEND.md +35 -35
- package/templates/git/CI_CD_PATTERNS.md +661 -661
- package/templates/git/GITHUB_ACTIONS.md +728 -728
- package/templates/git/GITLAB_CI.md +730 -730
- package/templates/git/GIT_WORKFLOW.md +1157 -1157
- package/templates/git/SECRETS_MANAGEMENT.md +585 -585
- package/templates/hooks/COMMIT_MSG.md +530 -530
- package/templates/hooks/POST_CHECKOUT.md +546 -546
- package/templates/hooks/PREPARE_COMMIT_MSG.md +619 -619
- package/templates/hooks/PRE_COMMIT.md +414 -414
- package/templates/hooks/PRE_PUSH.md +601 -601
- package/templates/ides/CONTINUE_RULES.md +16 -16
- package/templates/ides/COPILOT.md +37 -37
- package/templates/ides/COPILOT_INSTRUCTIONS.md +23 -23
- package/templates/ides/CURSOR.md +43 -43
- package/templates/ides/GEMINI_RULES.md +17 -17
- package/templates/ides/JETBRAINS_AI.md +35 -35
- package/templates/ides/REPLIT.md +36 -36
- package/templates/ides/TABNINE.md +29 -29
- package/templates/ides/VSCODE.md +40 -40
- package/templates/ides/WINDSURF.md +36 -36
- package/templates/ides/WINDSURF_RULES.md +14 -14
- package/templates/ides/ZED.md +32 -32
- package/templates/ides/cursor-mdc/go.mdc +24 -24
- package/templates/ides/cursor-mdc/python.mdc +24 -24
- package/templates/ides/cursor-mdc/quality.mdc +25 -25
- package/templates/ides/cursor-mdc/ralph.mdc +39 -39
- package/templates/ides/cursor-mdc/rulebook.mdc +38 -38
- package/templates/ides/cursor-mdc/rust.mdc +24 -24
- package/templates/ides/cursor-mdc/typescript.mdc +25 -25
- package/templates/languages/C.md +333 -333
- package/templates/languages/CPP.md +743 -743
- package/templates/languages/CSHARP.md +417 -417
- package/templates/languages/ELIXIR.md +454 -454
- package/templates/languages/ERLANG.md +361 -361
- package/templates/languages/GO.md +645 -645
- package/templates/languages/HASKELL.md +177 -177
- package/templates/languages/JAVA.md +607 -607
- package/templates/languages/JAVASCRIPT.md +631 -631
- package/templates/languages/JULIA.md +97 -97
- package/templates/languages/KOTLIN.md +511 -511
- package/templates/languages/LISP.md +100 -100
- package/templates/languages/LUA.md +74 -74
- package/templates/languages/OBJECTIVEC.md +90 -90
- package/templates/languages/PHP.md +416 -416
- package/templates/languages/PYTHON.md +682 -682
- package/templates/languages/RUBY.md +421 -421
- package/templates/languages/RUST.md +477 -477
- package/templates/languages/SAS.md +73 -73
- package/templates/languages/SCALA.md +348 -348
- package/templates/languages/SOLIDITY.md +580 -580
- package/templates/languages/SQL.md +137 -137
- package/templates/languages/SWIFT.md +466 -466
- package/templates/languages/TYPESCRIPT.md +591 -591
- package/templates/languages/ZIG.md +265 -265
- package/templates/modules/ATLASSIAN.md +255 -255
- package/templates/modules/CONTEXT7.md +54 -54
- package/templates/modules/FIGMA.md +267 -267
- package/templates/modules/GITHUB_MCP.md +64 -64
- package/templates/modules/GRAFANA.md +328 -328
- package/templates/modules/MEMORY.md +126 -126
- package/templates/modules/NOTION.md +247 -247
- package/templates/modules/PLAYWRIGHT.md +90 -90
- package/templates/modules/RULEBOOK_MCP.md +156 -156
- package/templates/modules/SERENA.md +337 -337
- package/templates/modules/SUPABASE.md +223 -223
- package/templates/modules/SYNAP.md +69 -69
- package/templates/modules/VECTORIZER.md +63 -63
- package/templates/modules/sequential-thinking.md +42 -42
- package/templates/ralph/ralph-history.bat +4 -4
- package/templates/ralph/ralph-history.sh +5 -5
- package/templates/ralph/ralph-init.bat +5 -5
- package/templates/ralph/ralph-init.sh +5 -5
- package/templates/ralph/ralph-pause.bat +5 -5
- package/templates/ralph/ralph-pause.sh +5 -5
- package/templates/ralph/ralph-run.bat +5 -5
- package/templates/ralph/ralph-run.sh +5 -5
- package/templates/ralph/ralph-status.bat +4 -4
- package/templates/ralph/ralph-status.sh +5 -5
- package/templates/services/AZURE_BLOB.md +184 -184
- package/templates/services/CASSANDRA.md +239 -239
- package/templates/services/DATADOG.md +26 -26
- package/templates/services/DOCKER.md +124 -124
- package/templates/services/DOCKER_COMPOSE.md +168 -168
- package/templates/services/DYNAMODB.md +308 -308
- package/templates/services/ELASTICSEARCH.md +347 -347
- package/templates/services/GCS.md +178 -178
- package/templates/services/HELM.md +194 -194
- package/templates/services/INFLUXDB.md +265 -265
- package/templates/services/KAFKA.md +341 -341
- package/templates/services/KUBERNETES.md +208 -208
- package/templates/services/MARIADB.md +183 -183
- package/templates/services/MEMCACHED.md +242 -242
- package/templates/services/MINIO.md +201 -201
- package/templates/services/MONGODB.md +268 -268
- package/templates/services/MYSQL.md +358 -358
- package/templates/services/NEO4J.md +247 -247
- package/templates/services/OPENTELEMETRY.md +25 -25
- package/templates/services/ORACLE.md +290 -290
- package/templates/services/PINO.md +24 -24
- package/templates/services/POSTGRESQL.md +326 -326
- package/templates/services/PROMETHEUS.md +33 -33
- package/templates/services/RABBITMQ.md +286 -286
- package/templates/services/REDIS.md +292 -292
- package/templates/services/S3.md +298 -298
- package/templates/services/SENTRY.md +23 -23
- package/templates/services/SQLITE.md +294 -294
- package/templates/services/SQLSERVER.md +294 -294
- package/templates/services/WINSTON.md +30 -30
- package/templates/skills/cli/aider/SKILL.md +59 -59
- package/templates/skills/cli/amazon-q/SKILL.md +35 -35
- package/templates/skills/cli/auggie/SKILL.md +42 -42
- package/templates/skills/cli/claude/SKILL.md +42 -42
- package/templates/skills/cli/cline/SKILL.md +42 -42
- package/templates/skills/cli/codebuddy/SKILL.md +30 -30
- package/templates/skills/cli/codeium/SKILL.md +30 -30
- package/templates/skills/cli/codex/SKILL.md +31 -31
- package/templates/skills/cli/continue/SKILL.md +44 -44
- package/templates/skills/cli/cursor-cli/SKILL.md +38 -38
- package/templates/skills/cli/factory/SKILL.md +28 -28
- package/templates/skills/cli/gemini/SKILL.md +45 -45
- package/templates/skills/cli/kilocode/SKILL.md +28 -28
- package/templates/skills/cli/opencode/SKILL.md +28 -28
- package/templates/skills/core/agent-automation/SKILL.md +194 -194
- package/templates/skills/core/dag/SKILL.md +314 -314
- package/templates/skills/core/documentation-rules/SKILL.md +46 -46
- package/templates/skills/core/quality-enforcement/SKILL.md +78 -78
- package/templates/skills/core/rulebook/SKILL.md +176 -176
- package/templates/skills/dev/accessibility/SKILL.md +17 -0
- package/templates/skills/dev/api-design/SKILL.md +15 -0
- package/templates/skills/dev/architect/SKILL.md +17 -0
- package/templates/skills/dev/build-fix/SKILL.md +17 -0
- package/templates/skills/dev/db-design/SKILL.md +15 -0
- package/templates/skills/dev/debug/SKILL.md +16 -0
- package/templates/skills/dev/deploy/SKILL.md +17 -0
- package/templates/skills/dev/docs/SKILL.md +17 -0
- package/templates/skills/dev/migrate/SKILL.md +15 -0
- package/templates/skills/dev/perf/SKILL.md +17 -0
- package/templates/skills/dev/refactor/SKILL.md +17 -0
- package/templates/skills/dev/research/SKILL.md +14 -0
- package/templates/skills/dev/review/SKILL.md +18 -0
- package/templates/skills/dev/security-audit/SKILL.md +17 -0
- package/templates/skills/frameworks/angular/SKILL.md +46 -46
- package/templates/skills/frameworks/django/SKILL.md +93 -93
- package/templates/skills/frameworks/electron/SKILL.md +157 -157
- package/templates/skills/frameworks/flask/SKILL.md +48 -48
- package/templates/skills/frameworks/flutter/SKILL.md +65 -65
- package/templates/skills/frameworks/jquery/SKILL.md +42 -42
- package/templates/skills/frameworks/laravel/SKILL.md +48 -48
- package/templates/skills/frameworks/nestjs/SKILL.md +53 -53
- package/templates/skills/frameworks/nextjs/SKILL.md +137 -137
- package/templates/skills/frameworks/nuxt/SKILL.md +50 -50
- package/templates/skills/frameworks/rails/SKILL.md +76 -76
- package/templates/skills/frameworks/react/SKILL.md +48 -48
- package/templates/skills/frameworks/react-native/SKILL.md +57 -57
- package/templates/skills/frameworks/spring/SKILL.md +49 -49
- package/templates/skills/frameworks/symfony/SKILL.md +46 -46
- package/templates/skills/frameworks/vue/SKILL.md +46 -46
- package/templates/skills/frameworks/zend/SKILL.md +45 -45
- package/templates/skills/ides/copilot/SKILL.md +47 -47
- package/templates/skills/ides/cursor/SKILL.md +53 -53
- package/templates/skills/ides/jetbrains-ai/SKILL.md +45 -45
- package/templates/skills/ides/replit/SKILL.md +46 -46
- package/templates/skills/ides/tabnine/SKILL.md +39 -39
- package/templates/skills/ides/vscode/SKILL.md +50 -50
- package/templates/skills/ides/windsurf/SKILL.md +46 -46
- package/templates/skills/ides/zed/SKILL.md +42 -42
- package/templates/skills/languages/c/SKILL.md +343 -343
- package/templates/skills/languages/cpp/SKILL.md +753 -753
- package/templates/skills/languages/csharp/SKILL.md +427 -427
- package/templates/skills/languages/elixir/SKILL.md +464 -464
- package/templates/skills/languages/erlang/SKILL.md +371 -371
- package/templates/skills/languages/go/SKILL.md +655 -655
- package/templates/skills/languages/haskell/SKILL.md +187 -187
- package/templates/skills/languages/java/SKILL.md +617 -617
- package/templates/skills/languages/javascript/SKILL.md +641 -641
- package/templates/skills/languages/julia/SKILL.md +107 -107
- package/templates/skills/languages/kotlin/SKILL.md +521 -521
- package/templates/skills/languages/lisp/SKILL.md +110 -110
- package/templates/skills/languages/lua/SKILL.md +84 -84
- package/templates/skills/languages/objectivec/SKILL.md +100 -100
- package/templates/skills/languages/php/SKILL.md +426 -426
- package/templates/skills/languages/python/SKILL.md +692 -692
- package/templates/skills/languages/ruby/SKILL.md +431 -431
- package/templates/skills/languages/rust/SKILL.md +487 -487
- package/templates/skills/languages/sas/SKILL.md +83 -83
- package/templates/skills/languages/scala/SKILL.md +358 -358
- package/templates/skills/languages/solidity/SKILL.md +590 -590
- package/templates/skills/languages/sql/SKILL.md +147 -147
- package/templates/skills/languages/swift/SKILL.md +476 -476
- package/templates/skills/languages/typescript/SKILL.md +302 -302
- package/templates/skills/languages/zig/SKILL.md +275 -275
- package/templates/skills/modules/atlassian/SKILL.md +265 -265
- package/templates/skills/modules/context7/SKILL.md +64 -64
- package/templates/skills/modules/figma/SKILL.md +277 -277
- package/templates/skills/modules/github-mcp/SKILL.md +74 -74
- package/templates/skills/modules/grafana/SKILL.md +338 -338
- package/templates/skills/modules/memory/SKILL.md +73 -73
- package/templates/skills/modules/notion/SKILL.md +257 -257
- package/templates/skills/modules/playwright/SKILL.md +100 -100
- package/templates/skills/modules/rulebook-mcp/SKILL.md +166 -166
- package/templates/skills/modules/serena/SKILL.md +347 -347
- package/templates/skills/modules/supabase/SKILL.md +233 -233
- package/templates/skills/modules/synap/SKILL.md +79 -79
- package/templates/skills/modules/vectorizer/SKILL.md +73 -73
- package/templates/skills/services/azure-blob/SKILL.md +194 -194
- package/templates/skills/services/cassandra/SKILL.md +249 -249
- package/templates/skills/services/dynamodb/SKILL.md +318 -318
- package/templates/skills/services/elasticsearch/SKILL.md +357 -357
- package/templates/skills/services/gcs/SKILL.md +188 -188
- package/templates/skills/services/influxdb/SKILL.md +275 -275
- package/templates/skills/services/kafka/SKILL.md +351 -351
- package/templates/skills/services/mariadb/SKILL.md +193 -193
- package/templates/skills/services/memcached/SKILL.md +252 -252
- package/templates/skills/services/minio/SKILL.md +211 -211
- package/templates/skills/services/mongodb/SKILL.md +278 -278
- package/templates/skills/services/mysql/SKILL.md +368 -368
- package/templates/skills/services/neo4j/SKILL.md +257 -257
- package/templates/skills/services/oracle/SKILL.md +300 -300
- package/templates/skills/services/postgresql/SKILL.md +336 -336
- package/templates/skills/services/rabbitmq/SKILL.md +296 -296
- package/templates/skills/services/redis/SKILL.md +302 -302
- package/templates/skills/services/s3/SKILL.md +308 -308
- package/templates/skills/services/sqlite/SKILL.md +304 -304
- package/templates/skills/services/sqlserver/SKILL.md +304 -304
- package/templates/skills/workflows/ralph/SKILL.md +309 -309
- package/templates/skills/workflows/ralph/install.sh +87 -87
- package/templates/skills/workflows/ralph/manifest.json +158 -158
package/templates/services/S3.md
CHANGED
|
@@ -1,298 +1,298 @@
|
|
|
1
|
-
<!-- S3:START -->
|
|
2
|
-
# AWS S3 Storage Instructions
|
|
3
|
-
|
|
4
|
-
**CRITICAL**: Use AWS S3 for object storage, file uploads, static assets, and backup storage with high availability.
|
|
5
|
-
|
|
6
|
-
## Core Features
|
|
7
|
-
|
|
8
|
-
### Connection
|
|
9
|
-
```typescript
|
|
10
|
-
// Using @aws-sdk/client-s3
|
|
11
|
-
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'
|
|
12
|
-
|
|
13
|
-
const s3Client = new S3Client({
|
|
14
|
-
region: process.env.AWS_REGION || 'us-east-1',
|
|
15
|
-
credentials: {
|
|
16
|
-
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
|
17
|
-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '',
|
|
18
|
-
},
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
// Using AWS SDK v2
|
|
22
|
-
import AWS from 'aws-sdk'
|
|
23
|
-
|
|
24
|
-
const s3 = new AWS.S3({
|
|
25
|
-
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
26
|
-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
27
|
-
region: process.env.AWS_REGION || 'us-east-1',
|
|
28
|
-
})
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Basic Operations
|
|
32
|
-
```typescript
|
|
33
|
-
// Upload file
|
|
34
|
-
const uploadParams = {
|
|
35
|
-
Bucket: process.env.S3_BUCKET || 'my-bucket',
|
|
36
|
-
Key: 'path/to/file.jpg',
|
|
37
|
-
Body: fileBuffer,
|
|
38
|
-
ContentType: 'image/jpeg',
|
|
39
|
-
ACL: 'private', // or 'public-read'
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await s3Client.send(new PutObjectCommand(uploadParams))
|
|
43
|
-
|
|
44
|
-
// Upload with metadata
|
|
45
|
-
await s3Client.send(new PutObjectCommand({
|
|
46
|
-
...uploadParams,
|
|
47
|
-
Metadata: {
|
|
48
|
-
userId: '123',
|
|
49
|
-
originalName: 'photo.jpg',
|
|
50
|
-
},
|
|
51
|
-
TagSet: [
|
|
52
|
-
{ Key: 'category', Value: 'profile' },
|
|
53
|
-
],
|
|
54
|
-
}))
|
|
55
|
-
|
|
56
|
-
// Get file
|
|
57
|
-
const getParams = {
|
|
58
|
-
Bucket: process.env.S3_BUCKET,
|
|
59
|
-
Key: 'path/to/file.jpg',
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const response = await s3Client.send(new GetObjectCommand(getParams))
|
|
63
|
-
const fileContent = await response.Body?.transformToByteArray()
|
|
64
|
-
|
|
65
|
-
// Delete file
|
|
66
|
-
await s3Client.send(new DeleteObjectCommand({
|
|
67
|
-
Bucket: process.env.S3_BUCKET,
|
|
68
|
-
Key: 'path/to/file.jpg',
|
|
69
|
-
}))
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Advanced Features
|
|
73
|
-
```typescript
|
|
74
|
-
// Presigned URL for upload
|
|
75
|
-
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
|
|
76
|
-
|
|
77
|
-
const command = new PutObjectCommand({
|
|
78
|
-
Bucket: process.env.S3_BUCKET,
|
|
79
|
-
Key: 'uploads/file.jpg',
|
|
80
|
-
ContentType: 'image/jpeg',
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const presignedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 })
|
|
84
|
-
|
|
85
|
-
// Presigned URL for download
|
|
86
|
-
const getCommand = new GetObjectCommand({
|
|
87
|
-
Bucket: process.env.S3_BUCKET,
|
|
88
|
-
Key: 'path/to/file.jpg',
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
const downloadUrl = await getSignedUrl(s3Client, getCommand, { expiresIn: 3600 })
|
|
92
|
-
|
|
93
|
-
// Multipart upload (for large files)
|
|
94
|
-
import { CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3'
|
|
95
|
-
|
|
96
|
-
const createCommand = new CreateMultipartUploadCommand({
|
|
97
|
-
Bucket: process.env.S3_BUCKET,
|
|
98
|
-
Key: 'large-file.zip',
|
|
99
|
-
ContentType: 'application/zip',
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
const { UploadId } = await s3Client.send(createCommand)
|
|
103
|
-
|
|
104
|
-
// Upload parts
|
|
105
|
-
const part1 = await s3Client.send(new UploadPartCommand({
|
|
106
|
-
Bucket: process.env.S3_BUCKET,
|
|
107
|
-
Key: 'large-file.zip',
|
|
108
|
-
PartNumber: 1,
|
|
109
|
-
UploadId,
|
|
110
|
-
Body: part1Buffer,
|
|
111
|
-
}))
|
|
112
|
-
|
|
113
|
-
// Complete upload
|
|
114
|
-
await s3Client.send(new CompleteMultipartUploadCommand({
|
|
115
|
-
Bucket: process.env.S3_BUCKET,
|
|
116
|
-
Key: 'large-file.zip',
|
|
117
|
-
UploadId,
|
|
118
|
-
MultipartUpload: {
|
|
119
|
-
Parts: [
|
|
120
|
-
{ PartNumber: 1, ETag: part1.ETag },
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
}))
|
|
124
|
-
|
|
125
|
-
// List objects
|
|
126
|
-
import { ListObjectsV2Command } from '@aws-sdk/client-s3'
|
|
127
|
-
|
|
128
|
-
const listCommand = new ListObjectsV2Command({
|
|
129
|
-
Bucket: process.env.S3_BUCKET,
|
|
130
|
-
Prefix: 'uploads/',
|
|
131
|
-
MaxKeys: 100,
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
const { Contents } = await s3Client.send(listCommand)
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Common Patterns
|
|
138
|
-
|
|
139
|
-
### File Upload Handler
|
|
140
|
-
```typescript
|
|
141
|
-
async function uploadFile(file: Buffer, filename: string, userId: string) {
|
|
142
|
-
const key = `users/${userId}/${Date.now()}-${filename}`
|
|
143
|
-
|
|
144
|
-
await s3Client.send(new PutObjectCommand({
|
|
145
|
-
Bucket: process.env.S3_BUCKET,
|
|
146
|
-
Key: key,
|
|
147
|
-
Body: file,
|
|
148
|
-
ContentType: getContentType(filename),
|
|
149
|
-
Metadata: {
|
|
150
|
-
userId,
|
|
151
|
-
originalName: filename,
|
|
152
|
-
uploadedAt: new Date().toISOString(),
|
|
153
|
-
},
|
|
154
|
-
}))
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
key,
|
|
158
|
-
url: `https://${process.env.S3_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`,
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Temporary File Access
|
|
164
|
-
```typescript
|
|
165
|
-
async function generateTemporaryDownloadUrl(key: string, expiresIn: number = 3600) {
|
|
166
|
-
const command = new GetObjectCommand({
|
|
167
|
-
Bucket: process.env.S3_BUCKET,
|
|
168
|
-
Key: key,
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
return await getSignedUrl(s3Client, command, { expiresIn })
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### File Cleanup
|
|
176
|
-
```typescript
|
|
177
|
-
async function deleteFilesByPrefix(prefix: string) {
|
|
178
|
-
const listCommand = new ListObjectsV2Command({
|
|
179
|
-
Bucket: process.env.S3_BUCKET,
|
|
180
|
-
Prefix: prefix,
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
let continuationToken: string | undefined
|
|
184
|
-
|
|
185
|
-
do {
|
|
186
|
-
const response = await s3Client.send({
|
|
187
|
-
...listCommand,
|
|
188
|
-
ContinuationToken: continuationToken,
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
if (response.Contents) {
|
|
192
|
-
for (const object of response.Contents) {
|
|
193
|
-
if (object.Key) {
|
|
194
|
-
await s3Client.send(new DeleteObjectCommand({
|
|
195
|
-
Bucket: process.env.S3_BUCKET,
|
|
196
|
-
Key: object.Key,
|
|
197
|
-
}))
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
continuationToken = response.NextContinuationToken
|
|
203
|
-
} while (continuationToken)
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
## Best Practices
|
|
208
|
-
|
|
209
|
-
✅ **DO:**
|
|
210
|
-
- Use presigned URLs for client uploads
|
|
211
|
-
- Set appropriate Content-Type headers
|
|
212
|
-
- Use versioning for important files
|
|
213
|
-
- Implement lifecycle policies for cleanup
|
|
214
|
-
- Use multipart upload for files > 5MB
|
|
215
|
-
- Enable encryption (SSE-S3 or SSE-KMS)
|
|
216
|
-
- Use appropriate storage classes (Standard, IA, Glacier)
|
|
217
|
-
- Implement proper error handling
|
|
218
|
-
- Use bucket policies for access control
|
|
219
|
-
- Monitor bucket usage and costs
|
|
220
|
-
|
|
221
|
-
❌ **DON'T:**
|
|
222
|
-
- Store sensitive data without encryption
|
|
223
|
-
- Use public-read ACL unnecessarily
|
|
224
|
-
- Hardcode credentials
|
|
225
|
-
- Ignore error handling
|
|
226
|
-
- Skip content-type validation
|
|
227
|
-
- Store large files without multipart upload
|
|
228
|
-
- Ignore lifecycle policies
|
|
229
|
-
- Skip access logging
|
|
230
|
-
- Use default bucket policies
|
|
231
|
-
- Ignore cost optimization
|
|
232
|
-
|
|
233
|
-
## Configuration
|
|
234
|
-
|
|
235
|
-
### Environment Variables
|
|
236
|
-
```bash
|
|
237
|
-
AWS_REGION=us-east-1
|
|
238
|
-
AWS_ACCESS_KEY_ID=your-access-key
|
|
239
|
-
AWS_SECRET_ACCESS_KEY=your-secret-key
|
|
240
|
-
S3_BUCKET=my-bucket
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### IAM Policy
|
|
244
|
-
```json
|
|
245
|
-
{
|
|
246
|
-
"Version": "2012-10-17",
|
|
247
|
-
"Statement": [
|
|
248
|
-
{
|
|
249
|
-
"Effect": "Allow",
|
|
250
|
-
"Action": [
|
|
251
|
-
"s3:PutObject",
|
|
252
|
-
"s3:GetObject",
|
|
253
|
-
"s3:DeleteObject"
|
|
254
|
-
],
|
|
255
|
-
"Resource": "arn:aws:s3:::my-bucket/*"
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
## Integration with Development
|
|
262
|
-
|
|
263
|
-
### Testing
|
|
264
|
-
```typescript
|
|
265
|
-
// Use test bucket or LocalStack
|
|
266
|
-
const testS3Client = new S3Client({
|
|
267
|
-
endpoint: 'http://localhost:4566', // LocalStack
|
|
268
|
-
region: 'us-east-1',
|
|
269
|
-
credentials: {
|
|
270
|
-
accessKeyId: 'test',
|
|
271
|
-
secretAccessKey: 'test',
|
|
272
|
-
},
|
|
273
|
-
forcePathStyle: true,
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
// Clean up after tests
|
|
277
|
-
afterEach(async () => {
|
|
278
|
-
// Delete test files
|
|
279
|
-
})
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### Health Checks
|
|
283
|
-
```typescript
|
|
284
|
-
async function checkS3Health(): Promise<boolean> {
|
|
285
|
-
try {
|
|
286
|
-
await s3Client.send(new ListObjectsV2Command({
|
|
287
|
-
Bucket: process.env.S3_BUCKET,
|
|
288
|
-
MaxKeys: 1,
|
|
289
|
-
}))
|
|
290
|
-
return true
|
|
291
|
-
} catch {
|
|
292
|
-
return false
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
<!-- S3:END -->
|
|
298
|
-
|
|
1
|
+
<!-- S3:START -->
|
|
2
|
+
# AWS S3 Storage Instructions
|
|
3
|
+
|
|
4
|
+
**CRITICAL**: Use AWS S3 for object storage, file uploads, static assets, and backup storage with high availability.
|
|
5
|
+
|
|
6
|
+
## Core Features
|
|
7
|
+
|
|
8
|
+
### Connection
|
|
9
|
+
```typescript
|
|
10
|
+
// Using @aws-sdk/client-s3
|
|
11
|
+
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'
|
|
12
|
+
|
|
13
|
+
const s3Client = new S3Client({
|
|
14
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
15
|
+
credentials: {
|
|
16
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
|
|
17
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '',
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// Using AWS SDK v2
|
|
22
|
+
import AWS from 'aws-sdk'
|
|
23
|
+
|
|
24
|
+
const s3 = new AWS.S3({
|
|
25
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
26
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
27
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Basic Operations
|
|
32
|
+
```typescript
|
|
33
|
+
// Upload file
|
|
34
|
+
const uploadParams = {
|
|
35
|
+
Bucket: process.env.S3_BUCKET || 'my-bucket',
|
|
36
|
+
Key: 'path/to/file.jpg',
|
|
37
|
+
Body: fileBuffer,
|
|
38
|
+
ContentType: 'image/jpeg',
|
|
39
|
+
ACL: 'private', // or 'public-read'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await s3Client.send(new PutObjectCommand(uploadParams))
|
|
43
|
+
|
|
44
|
+
// Upload with metadata
|
|
45
|
+
await s3Client.send(new PutObjectCommand({
|
|
46
|
+
...uploadParams,
|
|
47
|
+
Metadata: {
|
|
48
|
+
userId: '123',
|
|
49
|
+
originalName: 'photo.jpg',
|
|
50
|
+
},
|
|
51
|
+
TagSet: [
|
|
52
|
+
{ Key: 'category', Value: 'profile' },
|
|
53
|
+
],
|
|
54
|
+
}))
|
|
55
|
+
|
|
56
|
+
// Get file
|
|
57
|
+
const getParams = {
|
|
58
|
+
Bucket: process.env.S3_BUCKET,
|
|
59
|
+
Key: 'path/to/file.jpg',
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const response = await s3Client.send(new GetObjectCommand(getParams))
|
|
63
|
+
const fileContent = await response.Body?.transformToByteArray()
|
|
64
|
+
|
|
65
|
+
// Delete file
|
|
66
|
+
await s3Client.send(new DeleteObjectCommand({
|
|
67
|
+
Bucket: process.env.S3_BUCKET,
|
|
68
|
+
Key: 'path/to/file.jpg',
|
|
69
|
+
}))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Advanced Features
|
|
73
|
+
```typescript
|
|
74
|
+
// Presigned URL for upload
|
|
75
|
+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
|
|
76
|
+
|
|
77
|
+
const command = new PutObjectCommand({
|
|
78
|
+
Bucket: process.env.S3_BUCKET,
|
|
79
|
+
Key: 'uploads/file.jpg',
|
|
80
|
+
ContentType: 'image/jpeg',
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const presignedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 })
|
|
84
|
+
|
|
85
|
+
// Presigned URL for download
|
|
86
|
+
const getCommand = new GetObjectCommand({
|
|
87
|
+
Bucket: process.env.S3_BUCKET,
|
|
88
|
+
Key: 'path/to/file.jpg',
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const downloadUrl = await getSignedUrl(s3Client, getCommand, { expiresIn: 3600 })
|
|
92
|
+
|
|
93
|
+
// Multipart upload (for large files)
|
|
94
|
+
import { CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3'
|
|
95
|
+
|
|
96
|
+
const createCommand = new CreateMultipartUploadCommand({
|
|
97
|
+
Bucket: process.env.S3_BUCKET,
|
|
98
|
+
Key: 'large-file.zip',
|
|
99
|
+
ContentType: 'application/zip',
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const { UploadId } = await s3Client.send(createCommand)
|
|
103
|
+
|
|
104
|
+
// Upload parts
|
|
105
|
+
const part1 = await s3Client.send(new UploadPartCommand({
|
|
106
|
+
Bucket: process.env.S3_BUCKET,
|
|
107
|
+
Key: 'large-file.zip',
|
|
108
|
+
PartNumber: 1,
|
|
109
|
+
UploadId,
|
|
110
|
+
Body: part1Buffer,
|
|
111
|
+
}))
|
|
112
|
+
|
|
113
|
+
// Complete upload
|
|
114
|
+
await s3Client.send(new CompleteMultipartUploadCommand({
|
|
115
|
+
Bucket: process.env.S3_BUCKET,
|
|
116
|
+
Key: 'large-file.zip',
|
|
117
|
+
UploadId,
|
|
118
|
+
MultipartUpload: {
|
|
119
|
+
Parts: [
|
|
120
|
+
{ PartNumber: 1, ETag: part1.ETag },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
}))
|
|
124
|
+
|
|
125
|
+
// List objects
|
|
126
|
+
import { ListObjectsV2Command } from '@aws-sdk/client-s3'
|
|
127
|
+
|
|
128
|
+
const listCommand = new ListObjectsV2Command({
|
|
129
|
+
Bucket: process.env.S3_BUCKET,
|
|
130
|
+
Prefix: 'uploads/',
|
|
131
|
+
MaxKeys: 100,
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
const { Contents } = await s3Client.send(listCommand)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Common Patterns
|
|
138
|
+
|
|
139
|
+
### File Upload Handler
|
|
140
|
+
```typescript
|
|
141
|
+
async function uploadFile(file: Buffer, filename: string, userId: string) {
|
|
142
|
+
const key = `users/${userId}/${Date.now()}-${filename}`
|
|
143
|
+
|
|
144
|
+
await s3Client.send(new PutObjectCommand({
|
|
145
|
+
Bucket: process.env.S3_BUCKET,
|
|
146
|
+
Key: key,
|
|
147
|
+
Body: file,
|
|
148
|
+
ContentType: getContentType(filename),
|
|
149
|
+
Metadata: {
|
|
150
|
+
userId,
|
|
151
|
+
originalName: filename,
|
|
152
|
+
uploadedAt: new Date().toISOString(),
|
|
153
|
+
},
|
|
154
|
+
}))
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
key,
|
|
158
|
+
url: `https://${process.env.S3_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`,
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Temporary File Access
|
|
164
|
+
```typescript
|
|
165
|
+
async function generateTemporaryDownloadUrl(key: string, expiresIn: number = 3600) {
|
|
166
|
+
const command = new GetObjectCommand({
|
|
167
|
+
Bucket: process.env.S3_BUCKET,
|
|
168
|
+
Key: key,
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return await getSignedUrl(s3Client, command, { expiresIn })
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### File Cleanup
|
|
176
|
+
```typescript
|
|
177
|
+
async function deleteFilesByPrefix(prefix: string) {
|
|
178
|
+
const listCommand = new ListObjectsV2Command({
|
|
179
|
+
Bucket: process.env.S3_BUCKET,
|
|
180
|
+
Prefix: prefix,
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
let continuationToken: string | undefined
|
|
184
|
+
|
|
185
|
+
do {
|
|
186
|
+
const response = await s3Client.send({
|
|
187
|
+
...listCommand,
|
|
188
|
+
ContinuationToken: continuationToken,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
if (response.Contents) {
|
|
192
|
+
for (const object of response.Contents) {
|
|
193
|
+
if (object.Key) {
|
|
194
|
+
await s3Client.send(new DeleteObjectCommand({
|
|
195
|
+
Bucket: process.env.S3_BUCKET,
|
|
196
|
+
Key: object.Key,
|
|
197
|
+
}))
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
continuationToken = response.NextContinuationToken
|
|
203
|
+
} while (continuationToken)
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Best Practices
|
|
208
|
+
|
|
209
|
+
✅ **DO:**
|
|
210
|
+
- Use presigned URLs for client uploads
|
|
211
|
+
- Set appropriate Content-Type headers
|
|
212
|
+
- Use versioning for important files
|
|
213
|
+
- Implement lifecycle policies for cleanup
|
|
214
|
+
- Use multipart upload for files > 5MB
|
|
215
|
+
- Enable encryption (SSE-S3 or SSE-KMS)
|
|
216
|
+
- Use appropriate storage classes (Standard, IA, Glacier)
|
|
217
|
+
- Implement proper error handling
|
|
218
|
+
- Use bucket policies for access control
|
|
219
|
+
- Monitor bucket usage and costs
|
|
220
|
+
|
|
221
|
+
❌ **DON'T:**
|
|
222
|
+
- Store sensitive data without encryption
|
|
223
|
+
- Use public-read ACL unnecessarily
|
|
224
|
+
- Hardcode credentials
|
|
225
|
+
- Ignore error handling
|
|
226
|
+
- Skip content-type validation
|
|
227
|
+
- Store large files without multipart upload
|
|
228
|
+
- Ignore lifecycle policies
|
|
229
|
+
- Skip access logging
|
|
230
|
+
- Use default bucket policies
|
|
231
|
+
- Ignore cost optimization
|
|
232
|
+
|
|
233
|
+
## Configuration
|
|
234
|
+
|
|
235
|
+
### Environment Variables
|
|
236
|
+
```bash
|
|
237
|
+
AWS_REGION=us-east-1
|
|
238
|
+
AWS_ACCESS_KEY_ID=your-access-key
|
|
239
|
+
AWS_SECRET_ACCESS_KEY=your-secret-key
|
|
240
|
+
S3_BUCKET=my-bucket
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### IAM Policy
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"Version": "2012-10-17",
|
|
247
|
+
"Statement": [
|
|
248
|
+
{
|
|
249
|
+
"Effect": "Allow",
|
|
250
|
+
"Action": [
|
|
251
|
+
"s3:PutObject",
|
|
252
|
+
"s3:GetObject",
|
|
253
|
+
"s3:DeleteObject"
|
|
254
|
+
],
|
|
255
|
+
"Resource": "arn:aws:s3:::my-bucket/*"
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Integration with Development
|
|
262
|
+
|
|
263
|
+
### Testing
|
|
264
|
+
```typescript
|
|
265
|
+
// Use test bucket or LocalStack
|
|
266
|
+
const testS3Client = new S3Client({
|
|
267
|
+
endpoint: 'http://localhost:4566', // LocalStack
|
|
268
|
+
region: 'us-east-1',
|
|
269
|
+
credentials: {
|
|
270
|
+
accessKeyId: 'test',
|
|
271
|
+
secretAccessKey: 'test',
|
|
272
|
+
},
|
|
273
|
+
forcePathStyle: true,
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
// Clean up after tests
|
|
277
|
+
afterEach(async () => {
|
|
278
|
+
// Delete test files
|
|
279
|
+
})
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Health Checks
|
|
283
|
+
```typescript
|
|
284
|
+
async function checkS3Health(): Promise<boolean> {
|
|
285
|
+
try {
|
|
286
|
+
await s3Client.send(new ListObjectsV2Command({
|
|
287
|
+
Bucket: process.env.S3_BUCKET,
|
|
288
|
+
MaxKeys: 1,
|
|
289
|
+
}))
|
|
290
|
+
return true
|
|
291
|
+
} catch {
|
|
292
|
+
return false
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
<!-- S3:END -->
|
|
298
|
+
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
<!-- SENTRY:START -->
|
|
2
|
-
# Sentry — Error Tracking
|
|
3
|
-
|
|
4
|
-
## Configuration
|
|
5
|
-
- Initialize Sentry at application entry point BEFORE other imports
|
|
6
|
-
- Set `dsn` from environment variable: `process.env.SENTRY_DSN`
|
|
7
|
-
- Configure `environment` from `NODE_ENV`
|
|
8
|
-
- Enable `tracesSampleRate: 0.1` in production (not 1.0)
|
|
9
|
-
|
|
10
|
-
## Error Capture
|
|
11
|
-
- Wrap route handlers with Sentry error middleware
|
|
12
|
-
- Use `Sentry.captureException(err)` in catch blocks for unexpected errors
|
|
13
|
-
- Add custom context: `Sentry.setContext('user', { id, email })`
|
|
14
|
-
- Never log sensitive data (passwords, tokens) in Sentry context
|
|
15
|
-
|
|
16
|
-
## Release Tracking
|
|
17
|
-
- Set `release` using git commit SHA: `process.env.SENTRY_RELEASE`
|
|
18
|
-
- Run `sentry-cli releases` in CI to associate commits with releases
|
|
19
|
-
|
|
20
|
-
## Performance
|
|
21
|
-
- Use `Sentry.startTransaction()` for tracking custom operations
|
|
22
|
-
- Add distributed tracing headers to internal service calls
|
|
23
|
-
<!-- SENTRY:END -->
|
|
1
|
+
<!-- SENTRY:START -->
|
|
2
|
+
# Sentry — Error Tracking
|
|
3
|
+
|
|
4
|
+
## Configuration
|
|
5
|
+
- Initialize Sentry at application entry point BEFORE other imports
|
|
6
|
+
- Set `dsn` from environment variable: `process.env.SENTRY_DSN`
|
|
7
|
+
- Configure `environment` from `NODE_ENV`
|
|
8
|
+
- Enable `tracesSampleRate: 0.1` in production (not 1.0)
|
|
9
|
+
|
|
10
|
+
## Error Capture
|
|
11
|
+
- Wrap route handlers with Sentry error middleware
|
|
12
|
+
- Use `Sentry.captureException(err)` in catch blocks for unexpected errors
|
|
13
|
+
- Add custom context: `Sentry.setContext('user', { id, email })`
|
|
14
|
+
- Never log sensitive data (passwords, tokens) in Sentry context
|
|
15
|
+
|
|
16
|
+
## Release Tracking
|
|
17
|
+
- Set `release` using git commit SHA: `process.env.SENTRY_RELEASE`
|
|
18
|
+
- Run `sentry-cli releases` in CI to associate commits with releases
|
|
19
|
+
|
|
20
|
+
## Performance
|
|
21
|
+
- Use `Sentry.startTransaction()` for tracking custom operations
|
|
22
|
+
- Add distributed tracing headers to internal service calls
|
|
23
|
+
<!-- SENTRY:END -->
|