stacktape 3.5.8 → 3.6.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.
Files changed (123) hide show
  1. package/.tsconfig.bun-build.json +1 -0
  2. package/ai-docs/cli-ref/aws-profile-create.md +22 -0
  3. package/ai-docs/cli-ref/aws-profile-delete.md +22 -0
  4. package/ai-docs/cli-ref/aws-profile-list.md +20 -0
  5. package/ai-docs/cli-ref/aws-profile-update.md +22 -0
  6. package/ai-docs/cli-ref/bastion-session.md +29 -0
  7. package/ai-docs/cli-ref/bastion-tunnel.md +30 -0
  8. package/ai-docs/cli-ref/bucket-sync.md +30 -0
  9. package/ai-docs/cli-ref/cf-module-update.md +26 -0
  10. package/ai-docs/cli-ref/cf-rollback.md +28 -0
  11. package/ai-docs/cli-ref/codebuild-deploy.md +34 -0
  12. package/ai-docs/cli-ref/compile-template.md +25 -0
  13. package/ai-docs/cli-ref/container-session.md +30 -0
  14. package/ai-docs/cli-ref/debug-alarms.md +28 -0
  15. package/ai-docs/cli-ref/debug-aws-sdk.md +33 -0
  16. package/ai-docs/cli-ref/debug-container-exec.md +36 -0
  17. package/ai-docs/cli-ref/debug-dynamodb.md +35 -0
  18. package/ai-docs/cli-ref/debug-logs.md +34 -0
  19. package/ai-docs/cli-ref/debug-metrics.md +33 -0
  20. package/ai-docs/cli-ref/debug-opensearch.md +35 -0
  21. package/ai-docs/cli-ref/debug-redis.md +36 -0
  22. package/ai-docs/cli-ref/debug-sql.md +35 -0
  23. package/ai-docs/cli-ref/defaults-configure.md +29 -0
  24. package/ai-docs/cli-ref/defaults-list.md +20 -0
  25. package/ai-docs/cli-ref/delete.md +24 -0
  26. package/ai-docs/cli-ref/deploy.md +25 -0
  27. package/ai-docs/cli-ref/deployment-script-run.md +28 -0
  28. package/ai-docs/cli-ref/dev-stop.md +26 -0
  29. package/ai-docs/cli-ref/dev.md +45 -0
  30. package/ai-docs/cli-ref/domain-add.md +26 -0
  31. package/ai-docs/cli-ref/help.md +18 -0
  32. package/ai-docs/cli-ref/info-operations.md +22 -0
  33. package/ai-docs/cli-ref/info-stack.md +30 -0
  34. package/ai-docs/cli-ref/info-stacks.md +26 -0
  35. package/ai-docs/cli-ref/info-whoami.md +22 -0
  36. package/ai-docs/cli-ref/init.md +30 -0
  37. package/ai-docs/cli-ref/login.md +20 -0
  38. package/ai-docs/cli-ref/logout.md +18 -0
  39. package/ai-docs/cli-ref/mcp-add.md +22 -0
  40. package/ai-docs/cli-ref/mcp.md +20 -0
  41. package/ai-docs/cli-ref/org-create.md +24 -0
  42. package/ai-docs/cli-ref/org-delete.md +24 -0
  43. package/ai-docs/cli-ref/org-list.md +22 -0
  44. package/ai-docs/cli-ref/package-workloads.md +25 -0
  45. package/ai-docs/cli-ref/param-get.md +26 -0
  46. package/ai-docs/cli-ref/preview-changes.md +23 -0
  47. package/ai-docs/cli-ref/project-create.md +22 -0
  48. package/ai-docs/cli-ref/projects-list.md +22 -0
  49. package/ai-docs/cli-ref/rollback.md +28 -0
  50. package/ai-docs/cli-ref/script-run.md +29 -0
  51. package/ai-docs/cli-ref/secret-create.md +28 -0
  52. package/ai-docs/cli-ref/secret-delete.md +26 -0
  53. package/ai-docs/cli-ref/secret-get.md +26 -0
  54. package/ai-docs/cli-ref/upgrade.md +20 -0
  55. package/ai-docs/cli-ref/version.md +18 -0
  56. package/ai-docs/concept/connecting-resources.md +369 -0
  57. package/ai-docs/concept/directives.md +371 -0
  58. package/ai-docs/concept/extending-cloudformation.md +315 -0
  59. package/ai-docs/concept/overrides-and-transforms.md +352 -0
  60. package/ai-docs/concept/stages-and-environments.md +347 -0
  61. package/ai-docs/concept/typescript-config.md +447 -0
  62. package/ai-docs/concept/yaml-config.md +338 -0
  63. package/ai-docs/config-ref/_root.md +131 -0
  64. package/ai-docs/config-ref/application-load-balancer.md +1109 -0
  65. package/ai-docs/config-ref/astro-web.md +115 -0
  66. package/ai-docs/config-ref/aws-cdk-construct.md +68 -0
  67. package/ai-docs/config-ref/bastion.md +93 -0
  68. package/ai-docs/config-ref/batch-job.md +179 -0
  69. package/ai-docs/config-ref/bucket.md +348 -0
  70. package/ai-docs/config-ref/cdn.md +496 -0
  71. package/ai-docs/config-ref/custom-resource.md +80 -0
  72. package/ai-docs/config-ref/deployment-script.md +79 -0
  73. package/ai-docs/config-ref/dynamo-db-table.md +202 -0
  74. package/ai-docs/config-ref/edge-lambda-function.md +87 -0
  75. package/ai-docs/config-ref/efs-filesystem.md +72 -0
  76. package/ai-docs/config-ref/event-bus.md +63 -0
  77. package/ai-docs/config-ref/function.md +409 -0
  78. package/ai-docs/config-ref/hosting-bucket.md +171 -0
  79. package/ai-docs/config-ref/http-api-gateway.md +149 -0
  80. package/ai-docs/config-ref/http-endpoint.md +92 -0
  81. package/ai-docs/config-ref/kinesis-stream.md +97 -0
  82. package/ai-docs/config-ref/mongo-db-atlas-cluster.md +254 -0
  83. package/ai-docs/config-ref/multi-container-workload.md +399 -0
  84. package/ai-docs/config-ref/network-load-balancer.md +118 -0
  85. package/ai-docs/config-ref/nextjs-web.md +147 -0
  86. package/ai-docs/config-ref/nuxt-web.md +81 -0
  87. package/ai-docs/config-ref/open-search.md +206 -0
  88. package/ai-docs/config-ref/private-service.md +75 -0
  89. package/ai-docs/config-ref/redis-cluster.md +223 -0
  90. package/ai-docs/config-ref/relational-database.md +525 -0
  91. package/ai-docs/config-ref/remix-web.md +74 -0
  92. package/ai-docs/config-ref/sns-topic.md +69 -0
  93. package/ai-docs/config-ref/solidstart-web.md +75 -0
  94. package/ai-docs/config-ref/sqs-queue-not-empty.md +414 -0
  95. package/ai-docs/config-ref/sqs-queue.md +232 -0
  96. package/ai-docs/config-ref/state-machine.md +235 -0
  97. package/ai-docs/config-ref/sveltekit-web.md +81 -0
  98. package/ai-docs/config-ref/tanstack-web.md +75 -0
  99. package/ai-docs/config-ref/upstash-redis.md +59 -0
  100. package/ai-docs/config-ref/user-auth-pool.md +876 -0
  101. package/ai-docs/config-ref/web-app-firewall.md +212 -0
  102. package/ai-docs/config-ref/web-service.md +178 -0
  103. package/ai-docs/config-ref/worker-service.md +41 -0
  104. package/ai-docs/getting-started/console.md +232 -0
  105. package/ai-docs/getting-started/deployment.md +434 -0
  106. package/ai-docs/getting-started/dev-mode.md +118 -0
  107. package/ai-docs/getting-started/how-it-works.md +119 -0
  108. package/ai-docs/getting-started/intro.md +157 -0
  109. package/ai-docs/getting-started/using-with-ai.md +228 -0
  110. package/ai-docs/getting-started/workflow.md +197 -0
  111. package/ai-docs/index.json +1514 -0
  112. package/ai-docs/recipe/background-jobs.md +183 -0
  113. package/ai-docs/recipe/database-migrations.md +240 -0
  114. package/ai-docs/recipe/graphql-api.md +211 -0
  115. package/ai-docs/recipe/monorepo-setup.md +183 -0
  116. package/ai-docs/recipe/nextjs-full-stack.md +188 -0
  117. package/ai-docs/recipe/rest-api-with-database.md +156 -0
  118. package/ai-docs/recipe/scheduled-tasks.md +186 -0
  119. package/ai-docs/recipe/static-website.md +241 -0
  120. package/ai-docs/troubleshooting/cloudformation-stack-states.md +189 -0
  121. package/bin/stacktape.js +0 -12
  122. package/package.json +1 -1
  123. package/plain.d.ts +372 -111
@@ -0,0 +1,183 @@
1
+ ---
2
+ docType: recipe
3
+ title: Monorepo Setup
4
+ tags:
5
+ - monorepo
6
+ - setup
7
+ - recipe
8
+ source: docs/_curated-docs/recipes/monorepo-setup.mdx
9
+ priority: 1
10
+ ---
11
+
12
+ # Monorepo Setup
13
+
14
+ Deploy multiple services from a single repository.
15
+
16
+ ## Project Structure
17
+
18
+ ## Shared Infrastructure Stack
19
+
20
+ ```typescript
21
+ // packages/infra/stacktape.ts
22
+ import { defineConfig, RelationalDatabase, RdsEnginePostgres, $Secret } from 'stacktape';
23
+
24
+ export default defineConfig(({ stage }) => {
25
+ const database = new RelationalDatabase({
26
+ engine: new RdsEnginePostgres({ version: '16' }),
27
+ credentials: {
28
+ masterUserPassword: $Secret(`db-password-${stage}`)
29
+ }
30
+ });
31
+
32
+ return {
33
+ resources: { database }
34
+ };
35
+ });
36
+ ```
37
+
38
+ ## API Service Stack
39
+
40
+ ```typescript
41
+ // packages/api/stacktape.ts
42
+ import { defineConfig, LambdaFunction, HttpApiGateway, $CfStackOutput } from 'stacktape';
43
+
44
+ export default defineConfig(({ stage }) => {
45
+ const api = new LambdaFunction({
46
+ packaging: {
47
+ type: 'stacktape-lambda-buildpack',
48
+ properties: {
49
+ entryfilePath: './src/handler.ts'
50
+ }
51
+ },
52
+ environment: {
53
+ // Reference the shared database from infra stack
54
+ DATABASE_URL: $CfStackOutput(`infra-${stage}`, 'database', 'connectionString')
55
+ }
56
+ });
57
+
58
+ const gateway = new HttpApiGateway({
59
+ routes: [{ path: '/{proxy+}', method: '*', integration: { type: 'function', properties: { function: api } } }]
60
+ });
61
+
62
+ return {
63
+ resources: { api, gateway }
64
+ };
65
+ });
66
+ ```
67
+
68
+ ## Web Service Stack
69
+
70
+ ```typescript
71
+ // packages/web/stacktape.ts
72
+ import { defineConfig, NextjsWeb, $CfStackOutput } from 'stacktape';
73
+
74
+ export default defineConfig(({ stage }) => {
75
+ const website = new NextjsWeb({
76
+ appDirectory: './',
77
+ environment: [
78
+ {
79
+ name: 'NEXT_PUBLIC_API_URL',
80
+ value: $CfStackOutput(`api-${stage}`, 'gateway', 'url')
81
+ }
82
+ ]
83
+ });
84
+
85
+ return {
86
+ resources: { website }
87
+ };
88
+ });
89
+ ```
90
+
91
+ ## Deployment Scripts
92
+
93
+ ```json
94
+ // package.json (root)
95
+ {
96
+ "scripts": {
97
+ "deploy:infra": "cd packages/infra && stacktape deploy",
98
+ "deploy:api": "cd packages/api && stacktape deploy",
99
+ "deploy:web": "cd packages/web && stacktape deploy",
100
+ "deploy:all": "npm run deploy:infra && npm run deploy:api && npm run deploy:web"
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## Deploy Order
106
+
107
+ Infrastructure must be deployed first since other stacks reference it:
108
+
109
+ ```bash
110
+ # 1. Deploy shared infrastructure
111
+ cd packages/infra
112
+ stacktape deploy --stage dev --region us-east-1
113
+
114
+ # 2. Deploy API (references infra)
115
+ cd packages/api
116
+ stacktape deploy --stage dev --region us-east-1
117
+
118
+ # 3. Deploy Web (references API)
119
+ cd packages/web
120
+ stacktape deploy --stage dev --region us-east-1
121
+ ```
122
+
123
+ ## CI/CD with GitHub Actions
124
+
125
+ ```yaml
126
+ # .github/workflows/deploy.yml
127
+ name: Deploy
128
+
129
+ on:
130
+ push:
131
+ branches: [main]
132
+
133
+ jobs:
134
+ deploy:
135
+ runs-on: ubuntu-latest
136
+ steps:
137
+ - uses: actions/checkout@v4
138
+
139
+ - uses: oven-sh/setup-bun@v1
140
+
141
+ - run: bun install
142
+
143
+ # Deploy in order
144
+ - name: Deploy Infrastructure
145
+ run: |
146
+ cd packages/infra
147
+ stacktape deploy --stage production --region us-east-1 --autoConfirmOperation
148
+ env:
149
+ STACKTAPE_API_KEY: ${{ secrets.STACKTAPE_API_KEY }}
150
+
151
+ - name: Deploy API
152
+ run: |
153
+ cd packages/api
154
+ stacktape deploy --stage production --region us-east-1 --autoConfirmOperation
155
+ env:
156
+ STACKTAPE_API_KEY: ${{ secrets.STACKTAPE_API_KEY }}
157
+
158
+ - name: Deploy Web
159
+ run: |
160
+ cd packages/web
161
+ stacktape deploy --stage production --region us-east-1 --autoConfirmOperation
162
+ env:
163
+ STACKTAPE_API_KEY: ${{ secrets.STACKTAPE_API_KEY }}
164
+ ```
165
+
166
+ ## With Turborepo
167
+
168
+ ```json
169
+ // turbo.json
170
+ {
171
+ "pipeline": {
172
+ "deploy": {
173
+ "dependsOn": ["^deploy"],
174
+ "cache": false
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ ```bash
181
+ # Deploy all in dependency order
182
+ turbo run deploy
183
+ ```
@@ -0,0 +1,188 @@
1
+ ---
2
+ docType: recipe
3
+ title: Next.js Full-Stack
4
+ tags:
5
+ - next.js
6
+ - full-stack
7
+ - recipe
8
+ source: docs/_curated-docs/recipes/nextjs-full-stack.mdx
9
+ priority: 1
10
+ ---
11
+
12
+ # Next.js Full-Stack Application
13
+
14
+ A complete Next.js application with database, authentication, and file uploads.
15
+
16
+ ## Configuration
17
+
18
+ ```typescript
19
+ import {
20
+ defineConfig,
21
+ NextjsWeb,
22
+ RelationalDatabase,
23
+ RdsEnginePostgres,
24
+ UserAuthPool,
25
+ Bucket,
26
+ $Secret,
27
+ $ResourceParam
28
+ } from 'stacktape';
29
+
30
+ export default defineConfig(({ stage }) => {
31
+ const isProduction = stage === 'production';
32
+
33
+ // PostgreSQL database
34
+ const database = new RelationalDatabase({
35
+ engine: new RdsEnginePostgres({
36
+ version: '16',
37
+ primaryInstance: {
38
+ instanceSize: isProduction ? 'db.t4g.small' : 'db.t4g.micro'
39
+ }
40
+ }),
41
+ credentials: {
42
+ masterUserPassword: $Secret(`db-password-${stage}`)
43
+ }
44
+ });
45
+
46
+ // User authentication
47
+ const auth = new UserAuthPool({
48
+ passwordPolicy: {
49
+ minimumLength: 8,
50
+ requireNumbers: true
51
+ }
52
+ });
53
+
54
+ // File uploads bucket
55
+ const uploads = new Bucket({
56
+ directoryUpload: {
57
+ directoryPath: './public/uploads'
58
+ }
59
+ });
60
+
61
+ // Next.js application
62
+ const website = new NextjsWeb({
63
+ appDirectory: './',
64
+ connectTo: [database, auth, uploads],
65
+ serverLambda: {
66
+ joinDefaultVpc: true, // Required for database access
67
+ memory: 1024
68
+ },
69
+ customDomains: isProduction ? [{ domainName: 'myapp.com' }, { domainName: 'www.myapp.com' }] : [],
70
+ environment: [
71
+ { name: 'NEXTAUTH_SECRET', value: $Secret('nextauth-secret') },
72
+ { name: 'NEXTAUTH_URL', value: isProduction ? 'https://myapp.com' : `https://${stage}.myapp.com` }
73
+ ]
74
+ });
75
+
76
+ return {
77
+ hooks: {
78
+ afterDeploy: [{ scriptName: 'migrate' }]
79
+ },
80
+ scripts: {
81
+ migrate: {
82
+ executeCommand: 'npx prisma migrate deploy',
83
+ environment: {
84
+ DATABASE_URL: $ResourceParam('database', 'connectionString')
85
+ }
86
+ }
87
+ },
88
+ resources: { database, auth, uploads, website }
89
+ };
90
+ });
91
+ ```
92
+
93
+ ## Project Structure
94
+
95
+ ## Database Access
96
+
97
+ ```typescript
98
+ // lib/db.ts
99
+ import { PrismaClient } from '@prisma/client';
100
+
101
+ const globalForPrisma = global as unknown as { prisma: PrismaClient };
102
+
103
+ export const prisma = globalForPrisma.prisma || new PrismaClient();
104
+
105
+ if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
106
+ ```
107
+
108
+ ```typescript
109
+ // app/api/users/route.ts
110
+ import { prisma } from '@/lib/db';
111
+ import { NextResponse } from 'next/server';
112
+
113
+ export async function GET() {
114
+ const users = await prisma.user.findMany();
115
+ return NextResponse.json(users);
116
+ }
117
+ ```
118
+
119
+ ## Authentication
120
+
121
+ ```typescript
122
+ // app/api/auth/[...nextauth]/route.ts
123
+ import NextAuth from 'next-auth';
124
+ import CognitoProvider from 'next-auth/providers/cognito';
125
+
126
+ const handler = NextAuth({
127
+ providers: [
128
+ CognitoProvider({
129
+ clientId: process.env.STP_AUTH_USER_POOL_CLIENT_ID!,
130
+ clientSecret: process.env.STP_AUTH_USER_POOL_CLIENT_SECRET!,
131
+ issuer: process.env.STP_AUTH_USER_POOL_ISSUER_URL!
132
+ })
133
+ ]
134
+ });
135
+
136
+ export { handler as GET, handler as POST };
137
+ ```
138
+
139
+ ## File Uploads
140
+
141
+ ```typescript
142
+ // app/api/upload/route.ts
143
+ import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
144
+ import { NextResponse } from 'next/server';
145
+
146
+ const s3 = new S3Client({});
147
+
148
+ export async function POST(request: Request) {
149
+ const formData = await request.formData();
150
+ const file = formData.get('file') as File;
151
+
152
+ const buffer = Buffer.from(await file.arrayBuffer());
153
+ const key = `uploads/${Date.now()}-${file.name}`;
154
+
155
+ await s3.send(
156
+ new PutObjectCommand({
157
+ Bucket: process.env.STP_UPLOADS_BUCKET_NAME,
158
+ Key: key,
159
+ Body: buffer,
160
+ ContentType: file.type
161
+ })
162
+ );
163
+
164
+ return NextResponse.json({ key });
165
+ }
166
+ ```
167
+
168
+ ## Development
169
+
170
+ ```bash
171
+ # Start dev mode
172
+ stacktape dev --stage dev --region us-east-1
173
+
174
+ # Opens: http://localhost:3000
175
+ # Database emulated locally
176
+ # Auth pool connected to AWS
177
+ ```
178
+
179
+ ## Deploy
180
+
181
+ ```bash
182
+ # Create secrets
183
+ stacktape secret:create --region us-east-1 # db-password-dev
184
+ stacktape secret:create --region us-east-1 # nextauth-secret
185
+
186
+ # Deploy
187
+ stacktape deploy --stage dev --region us-east-1
188
+ ```
@@ -0,0 +1,156 @@
1
+ ---
2
+ docType: recipe
3
+ title: REST API + Database
4
+ tags:
5
+ - rest
6
+ - api
7
+ - database
8
+ - recipe
9
+ source: docs/_curated-docs/recipes/rest-api-with-database.mdx
10
+ priority: 1
11
+ ---
12
+
13
+ # REST API with PostgreSQL
14
+
15
+ A complete REST API using Lambda functions connected to a PostgreSQL database.
16
+
17
+ ## Final Configuration
18
+
19
+ ```typescript
20
+ import {
21
+ defineConfig,
22
+ LambdaFunction,
23
+ RelationalDatabase,
24
+ RdsEnginePostgres,
25
+ HttpApiGateway,
26
+ $Secret
27
+ } from 'stacktape';
28
+
29
+ export default defineConfig(({ stage }) => {
30
+ const isProduction = stage === 'production';
31
+
32
+ // PostgreSQL database
33
+ const database = new RelationalDatabase({
34
+ engine: new RdsEnginePostgres({
35
+ version: '16',
36
+ primaryInstance: {
37
+ instanceSize: isProduction ? 'db.t4g.small' : 'db.t4g.micro'
38
+ }
39
+ }),
40
+ credentials: {
41
+ masterUserPassword: $Secret(`db-password-${stage}`)
42
+ }
43
+ });
44
+
45
+ // API handler
46
+ const api = new LambdaFunction({
47
+ packaging: {
48
+ type: 'stacktape-lambda-buildpack',
49
+ properties: {
50
+ entryfilePath: './src/handler.ts'
51
+ }
52
+ },
53
+ connectTo: [database],
54
+ environment: {
55
+ NODE_ENV: isProduction ? 'production' : 'development'
56
+ }
57
+ });
58
+
59
+ // HTTP Gateway
60
+ const gateway = new HttpApiGateway({
61
+ routes: [{ path: '/{proxy+}', method: '*', integration: { type: 'function', properties: { function: api } } }]
62
+ });
63
+
64
+ return {
65
+ resources: { database, api, gateway }
66
+ };
67
+ });
68
+ ```
69
+
70
+ ## Project Structure
71
+
72
+ ## Handler Code
73
+
74
+ ```typescript
75
+ // src/handler.ts
76
+ import { APIGatewayProxyHandlerV2 } from 'aws-lambda';
77
+ import { Pool } from 'pg';
78
+
79
+ // Connection pool (reused across invocations)
80
+ const pool = new Pool({
81
+ connectionString: process.env.STP_DATABASE_CONNECTION_STRING
82
+ });
83
+
84
+ export const handler: APIGatewayProxyHandlerV2 = async (event) => {
85
+ const { httpMethod, path } = event.requestContext.http;
86
+
87
+ if (path === '/users' && httpMethod === 'GET') {
88
+ const result = await pool.query('SELECT * FROM users LIMIT 100');
89
+ return {
90
+ statusCode: 200,
91
+ body: JSON.stringify(result.rows)
92
+ };
93
+ }
94
+
95
+ if (path === '/users' && httpMethod === 'POST') {
96
+ const body = JSON.parse(event.body || '{}');
97
+ const result = await pool.query('INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *', [
98
+ body.name,
99
+ body.email
100
+ ]);
101
+ return {
102
+ statusCode: 201,
103
+ body: JSON.stringify(result.rows[0])
104
+ };
105
+ }
106
+
107
+ return { statusCode: 404, body: 'Not found' };
108
+ };
109
+ ```
110
+
111
+ ## Adding Migrations
112
+
113
+ Run database migrations on every deployment:
114
+
115
+ ```typescript
116
+ export default defineConfig(({ stage }) => {
117
+ // ... resources ...
118
+
119
+ return {
120
+ hooks: {
121
+ afterDeploy: [{ scriptName: 'migrate' }]
122
+ },
123
+ scripts: {
124
+ migrate: {
125
+ executeCommand: 'npx prisma migrate deploy',
126
+ environment: {
127
+ DATABASE_URL: $ResourceParam('database', 'connectionString')
128
+ }
129
+ }
130
+ },
131
+ resources: { database, api, gateway }
132
+ };
133
+ });
134
+ ```
135
+
136
+ ## Development
137
+
138
+ ```bash
139
+ # Start local development
140
+ stacktape dev --stage dev --region us-east-1
141
+
142
+ # Database runs locally in Docker
143
+ # API runs locally with hot-reload
144
+ # Requests tunnel through AWS
145
+ ```
146
+
147
+ ## Deploy
148
+
149
+ ```bash
150
+ # Create the database password secret first
151
+ stacktape secret:create --region us-east-1
152
+ # name: db-password-dev
153
+
154
+ # Deploy
155
+ stacktape deploy --stage dev --region us-east-1
156
+ ```
@@ -0,0 +1,186 @@
1
+ ---
2
+ docType: recipe
3
+ title: Scheduled Tasks
4
+ tags:
5
+ - scheduled
6
+ - tasks
7
+ - recipe
8
+ source: docs/_curated-docs/recipes/scheduled-tasks.mdx
9
+ priority: 1
10
+ ---
11
+
12
+ # Scheduled Tasks (Cron Jobs)
13
+
14
+ Run Lambda functions on a schedule using CloudWatch Events.
15
+
16
+ ## Configuration
17
+
18
+ ```typescript
19
+ import { defineConfig, LambdaFunction, RelationalDatabase, RdsEnginePostgres, $Secret } from 'stacktape';
20
+
21
+ export default defineConfig(() => {
22
+ const database = new RelationalDatabase({
23
+ engine: new RdsEnginePostgres({ version: '16' }),
24
+ credentials: {
25
+ masterUserPassword: $Secret('db-password')
26
+ }
27
+ });
28
+
29
+ // Daily cleanup job - runs at 3 AM UTC
30
+ const dailyCleanup = new LambdaFunction({
31
+ packaging: {
32
+ type: 'stacktape-lambda-buildpack',
33
+ properties: {
34
+ entryfilePath: './src/jobs/cleanup.ts'
35
+ }
36
+ },
37
+ timeout: 900, // 15 minutes
38
+ connectTo: [database],
39
+ events: [
40
+ {
41
+ type: 'schedule',
42
+ properties: {
43
+ scheduleRate: 'cron(0 3 * * ? *)' // 3 AM UTC daily
44
+ }
45
+ }
46
+ ]
47
+ });
48
+
49
+ // Hourly metrics job
50
+ const hourlyMetrics = new LambdaFunction({
51
+ packaging: {
52
+ type: 'stacktape-lambda-buildpack',
53
+ properties: {
54
+ entryfilePath: './src/jobs/metrics.ts'
55
+ }
56
+ },
57
+ timeout: 300,
58
+ connectTo: [database],
59
+ events: [
60
+ {
61
+ type: 'schedule',
62
+ properties: {
63
+ scheduleRate: 'rate(1 hour)'
64
+ }
65
+ }
66
+ ]
67
+ });
68
+
69
+ // Weekly report - runs every Monday at 9 AM UTC
70
+ const weeklyReport = new LambdaFunction({
71
+ packaging: {
72
+ type: 'stacktape-lambda-buildpack',
73
+ properties: {
74
+ entryfilePath: './src/jobs/weekly-report.ts'
75
+ }
76
+ },
77
+ timeout: 900,
78
+ connectTo: [database],
79
+ events: [
80
+ {
81
+ type: 'schedule',
82
+ properties: {
83
+ scheduleRate: 'cron(0 9 ? * MON *)' // Monday 9 AM UTC
84
+ }
85
+ }
86
+ ]
87
+ });
88
+
89
+ return {
90
+ resources: { database, dailyCleanup, hourlyMetrics, weeklyReport }
91
+ };
92
+ });
93
+ ```
94
+
95
+ ## Schedule Expressions
96
+
97
+ ### Rate Expressions
98
+
99
+ ```
100
+ rate(1 minute)
101
+ rate(5 minutes)
102
+ rate(1 hour)
103
+ rate(12 hours)
104
+ rate(1 day)
105
+ rate(7 days)
106
+ ```
107
+
108
+ ### Cron Expressions
109
+
110
+ Format: `cron(minutes hours day-of-month month day-of-week year)`
111
+
112
+ ```
113
+ cron(0 3 * * ? *) # 3:00 AM UTC every day
114
+ cron(0 */2 * * ? *) # Every 2 hours
115
+ cron(0 9 ? * MON *) # 9 AM every Monday
116
+ cron(0 0 1 * ? *) # Midnight on the 1st of each month
117
+ cron(0 12 ? * MON-FRI *)# Noon on weekdays
118
+ ```
119
+
120
+ ## Job Handler
121
+
122
+ ```typescript
123
+ // src/jobs/cleanup.ts
124
+ import { ScheduledHandler } from 'aws-lambda';
125
+ import { Pool } from 'pg';
126
+
127
+ const pool = new Pool({
128
+ connectionString: process.env.STP_DATABASE_CONNECTION_STRING
129
+ });
130
+
131
+ export const handler: ScheduledHandler = async (event) => {
132
+ console.log('Starting cleanup job', event);
133
+
134
+ // Delete old sessions
135
+ const sessionsResult = await pool.query("DELETE FROM sessions WHERE expires_at < NOW() - INTERVAL '30 days'");
136
+ console.log(`Deleted ${sessionsResult.rowCount} expired sessions`);
137
+
138
+ // Delete old logs
139
+ const logsResult = await pool.query("DELETE FROM audit_logs WHERE created_at < NOW() - INTERVAL '90 days'");
140
+ console.log(`Deleted ${logsResult.rowCount} old audit logs`);
141
+
142
+ // Vacuum analyze for performance
143
+ await pool.query('VACUUM ANALYZE');
144
+
145
+ console.log('Cleanup complete');
146
+ };
147
+ ```
148
+
149
+ ## Weekly Report Example
150
+
151
+ ```typescript
152
+ // src/jobs/weekly-report.ts
153
+ import { ScheduledHandler } from 'aws-lambda';
154
+ import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';
155
+
156
+ const ses = new SESClient({});
157
+
158
+ export const handler: ScheduledHandler = async () => {
159
+ // Generate report data
160
+ const report = await generateWeeklyStats();
161
+
162
+ // Send email
163
+ await ses.send(
164
+ new SendEmailCommand({
165
+ Source: 'reports@myapp.com',
166
+ Destination: {
167
+ ToAddresses: ['team@myapp.com']
168
+ },
169
+ Message: {
170
+ Subject: { Data: `Weekly Report - ${new Date().toLocaleDateString()}` },
171
+ Body: {
172
+ Html: { Data: formatReportHtml(report) }
173
+ }
174
+ }
175
+ })
176
+ );
177
+ };
178
+ ```
179
+
180
+ ## Monitoring
181
+
182
+ View scheduled job logs:
183
+
184
+ ```bash
185
+ stacktape logs --stage dev --region us-east-1 --resourceName dailyCleanup --startTime 24h
186
+ ```