@friggframework/devtools 2.0.0--canary.454.e2a280d.0 → 2.0.0--canary.459.51231dd.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.
@@ -0,0 +1,280 @@
1
+ const { execSync, spawn } = require('child_process');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const chalk = require('chalk');
5
+
6
+ /**
7
+ * Prisma Command Runner Utility
8
+ * Handles execution of Prisma CLI commands for database setup
9
+ */
10
+
11
+ /**
12
+ * Gets the path to the Prisma schema file for the database type
13
+ * @param {'mongodb'|'postgresql'} dbType - Database type
14
+ * @param {string} projectRoot - Project root directory
15
+ * @returns {string} Absolute path to schema file
16
+ * @throws {Error} If schema file doesn't exist
17
+ */
18
+ function getPrismaSchemaPath(dbType, projectRoot = process.cwd()) {
19
+ // Try multiple locations for the schema file
20
+ // Priority order:
21
+ // 1. Local node_modules (where @friggframework/core is installed - production scenario)
22
+ // 2. Parent node_modules (workspace/monorepo setup)
23
+ const possiblePaths = [
24
+ // Check where Frigg is installed via npm (production scenario)
25
+ path.join(projectRoot, 'node_modules', '@friggframework', 'core', `prisma-${dbType}`, 'schema.prisma'),
26
+ path.join(projectRoot, '..', 'node_modules', '@friggframework', 'core', `prisma-${dbType}`, 'schema.prisma')
27
+ ];
28
+
29
+ for (const schemaPath of possiblePaths) {
30
+ if (fs.existsSync(schemaPath)) {
31
+ return schemaPath;
32
+ }
33
+ }
34
+
35
+ // If not found in any location, throw error
36
+ throw new Error(
37
+ `Prisma schema not found at:\n${possiblePaths.join('\n')}\n\n` +
38
+ 'Ensure @friggframework/core is installed.'
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Runs prisma generate for the specified database type
44
+ * @param {'mongodb'|'postgresql'} dbType - Database type
45
+ * @param {boolean} verbose - Enable verbose output
46
+ * @returns {Promise<Object>} { success: boolean, output?: string, error?: string }
47
+ */
48
+ async function runPrismaGenerate(dbType, verbose = false) {
49
+ try {
50
+ const schemaPath = getPrismaSchemaPath(dbType);
51
+
52
+ if (verbose) {
53
+ console.log(chalk.gray(`Running: npx prisma generate --schema=${schemaPath}`));
54
+ }
55
+
56
+ const output = execSync(
57
+ `npx prisma generate --schema=${schemaPath}`,
58
+ {
59
+ encoding: 'utf8',
60
+ stdio: verbose ? 'inherit' : 'pipe',
61
+ env: {
62
+ ...process.env,
63
+ // Suppress Prisma telemetry prompts
64
+ PRISMA_HIDE_UPDATE_MESSAGE: '1'
65
+ }
66
+ }
67
+ );
68
+
69
+ return {
70
+ success: true,
71
+ output: verbose ? 'Generated successfully' : output
72
+ };
73
+
74
+ } catch (error) {
75
+ return {
76
+ success: false,
77
+ error: error.message,
78
+ output: error.stdout?.toString() || error.stderr?.toString()
79
+ };
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Checks database migration status
85
+ * @param {'mongodb'|'postgresql'} dbType - Database type
86
+ * @returns {Promise<Object>} { upToDate: boolean, pendingMigrations?: number, error?: string }
87
+ */
88
+ async function checkDatabaseState(dbType) {
89
+ try {
90
+ // Only applicable for PostgreSQL (MongoDB uses db push)
91
+ if (dbType !== 'postgresql') {
92
+ return { upToDate: true };
93
+ }
94
+
95
+ const schemaPath = getPrismaSchemaPath(dbType);
96
+
97
+ const output = execSync(
98
+ `npx prisma migrate status --schema=${schemaPath}`,
99
+ {
100
+ encoding: 'utf8',
101
+ stdio: 'pipe',
102
+ env: {
103
+ ...process.env,
104
+ PRISMA_HIDE_UPDATE_MESSAGE: '1'
105
+ }
106
+ }
107
+ );
108
+
109
+ if (output.includes('Database schema is up to date')) {
110
+ return { upToDate: true };
111
+ }
112
+
113
+ // Parse pending migrations count
114
+ const pendingMatch = output.match(/(\d+) migration/);
115
+ const pendingMigrations = pendingMatch ? parseInt(pendingMatch[1]) : 0;
116
+
117
+ return {
118
+ upToDate: false,
119
+ pendingMigrations
120
+ };
121
+
122
+ } catch (error) {
123
+ // If migrate status fails, database might not be initialized
124
+ return {
125
+ upToDate: false,
126
+ error: error.message
127
+ };
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Runs Prisma migrate for PostgreSQL
133
+ * @param {'dev'|'deploy'} command - Migration command (dev or deploy)
134
+ * @param {boolean} verbose - Enable verbose output
135
+ * @returns {Promise<Object>} { success: boolean, output?: string, error?: string }
136
+ */
137
+ async function runPrismaMigrate(command = 'dev', verbose = false) {
138
+ return new Promise((resolve) => {
139
+ try {
140
+ const schemaPath = getPrismaSchemaPath('postgresql');
141
+
142
+ const args = [
143
+ 'prisma',
144
+ 'migrate',
145
+ command,
146
+ '--schema',
147
+ schemaPath
148
+ ];
149
+
150
+ if (verbose) {
151
+ console.log(chalk.gray(`Running: npx ${args.join(' ')}`));
152
+ }
153
+
154
+ const proc = spawn('npx', args, {
155
+ stdio: 'inherit',
156
+ env: {
157
+ ...process.env,
158
+ PRISMA_HIDE_UPDATE_MESSAGE: '1'
159
+ }
160
+ });
161
+
162
+ proc.on('error', (error) => {
163
+ resolve({
164
+ success: false,
165
+ error: error.message
166
+ });
167
+ });
168
+
169
+ proc.on('close', (code) => {
170
+ if (code === 0) {
171
+ resolve({
172
+ success: true,
173
+ output: 'Migration completed successfully'
174
+ });
175
+ } else {
176
+ resolve({
177
+ success: false,
178
+ error: `Migration process exited with code ${code}`
179
+ });
180
+ }
181
+ });
182
+
183
+ } catch (error) {
184
+ resolve({
185
+ success: false,
186
+ error: error.message
187
+ });
188
+ }
189
+ });
190
+ }
191
+
192
+ /**
193
+ * Runs Prisma db push for MongoDB
194
+ * Interactive - will prompt user if data loss detected
195
+ * @param {boolean} verbose - Enable verbose output
196
+ * @returns {Promise<Object>} { success: boolean, output?: string, error?: string }
197
+ */
198
+ async function runPrismaDbPush(verbose = false) {
199
+ return new Promise((resolve) => {
200
+ try {
201
+ const schemaPath = getPrismaSchemaPath('mongodb');
202
+
203
+ const args = [
204
+ 'prisma',
205
+ 'db',
206
+ 'push',
207
+ '--schema',
208
+ schemaPath,
209
+ '--skip-generate' // We generate separately
210
+ ];
211
+
212
+ if (verbose) {
213
+ console.log(chalk.gray(`Running: npx ${args.join(' ')}`));
214
+ }
215
+
216
+ console.log(chalk.yellow('⚠️ Interactive mode: You may be prompted if schema changes cause data loss'));
217
+
218
+ const proc = spawn('npx', args, {
219
+ stdio: 'inherit', // Interactive mode - user can respond to prompts
220
+ env: {
221
+ ...process.env,
222
+ PRISMA_HIDE_UPDATE_MESSAGE: '1'
223
+ }
224
+ });
225
+
226
+ proc.on('error', (error) => {
227
+ resolve({
228
+ success: false,
229
+ error: error.message
230
+ });
231
+ });
232
+
233
+ proc.on('close', (code) => {
234
+ if (code === 0) {
235
+ resolve({
236
+ success: true,
237
+ output: 'Database push completed successfully'
238
+ });
239
+ } else {
240
+ resolve({
241
+ success: false,
242
+ error: `Database push process exited with code ${code}`
243
+ });
244
+ }
245
+ });
246
+
247
+ } catch (error) {
248
+ resolve({
249
+ success: false,
250
+ error: error.message
251
+ });
252
+ }
253
+ });
254
+ }
255
+
256
+ /**
257
+ * Determines migration command based on STAGE environment variable
258
+ * @param {string} stage - Stage from CLI option or environment
259
+ * @returns {'dev'|'deploy'}
260
+ */
261
+ function getMigrationCommand(stage) {
262
+ const normalizedStage = (stage || process.env.STAGE || 'development').toLowerCase();
263
+
264
+ const developmentStages = ['dev', 'local', 'test', 'development'];
265
+
266
+ if (developmentStages.includes(normalizedStage)) {
267
+ return 'dev';
268
+ }
269
+
270
+ return 'deploy';
271
+ }
272
+
273
+ module.exports = {
274
+ getPrismaSchemaPath,
275
+ runPrismaGenerate,
276
+ checkDatabaseState,
277
+ runPrismaMigrate,
278
+ runPrismaDbPush,
279
+ getMigrationCommand
280
+ };
@@ -207,56 +207,6 @@ STAGE=production
207
207
  SERVICE_NAME=my-frigg-app
208
208
  ```
209
209
 
210
- ## Lambda Layers
211
-
212
- ### Prisma Layer
213
-
214
- The Frigg infrastructure uses a Lambda Layer to optimize Prisma deployment, reducing function sizes by ~60%.
215
-
216
- **What's included:**
217
-
218
- - `@prisma/client` - Prisma Client runtime
219
- - `@prisma-mongodb/client` - MongoDB Prisma Client
220
- - `@prisma-postgresql/client` - PostgreSQL Prisma Client
221
- - `prisma` - Prisma CLI (for migrations)
222
-
223
- **Benefits:**
224
-
225
- - ✅ **Reduces function sizes**: From ~120MB → ~45MB per function (60% reduction)
226
- - ✅ **Faster deployments**: Layer cached between deployments
227
- - ✅ **Shared resources**: Prisma uploaded once (~70MB layer), shared by all functions
228
- - ✅ **Improved cold starts**: Smaller packages = faster initialization
229
-
230
- **Building the layer:**
231
-
232
- ```bash
233
- cd packages/devtools
234
- npm run build:prisma-layer
235
- ```
236
-
237
- **Expected output:**
238
-
239
- ```
240
- Building Prisma Lambda Layer...
241
- ✓ Layer built successfully (70MB)
242
- Layer location: infrastructure/layers/prisma
243
- ```
244
-
245
- **Automatic deployment:**
246
-
247
- The layer is automatically deployed when you run `frigg deploy`. All Lambda functions reference the layer via CloudFormation.
248
-
249
- **Troubleshooting:**
250
-
251
- If you encounter "Module not found" errors after deployment:
252
-
253
- ```bash
254
- # Verify layer is attached to function
255
- aws lambda get-function-configuration \
256
- --function-name your-app-dev-auth \
257
- --query 'Layers[*].Arn'
258
- ```
259
-
260
210
  ## Usage Examples
261
211
 
262
212
  ### Basic Deployment
@@ -485,7 +435,6 @@ npm run test:debug
485
435
 
486
436
  ## Related Documentation
487
437
 
488
- - [Lambda Layer for Prisma](./LAMBDA-LAYER-PRISMA.md) - Complete guide to Prisma Lambda Layer optimization
489
438
  - [Phase 3 Deployment Guide](./PHASE3-DEPLOYMENT-GUIDE.md)
490
439
  - [Testing Strategy](./README-TESTING.md)
491
440
  - [AWS Discovery Troubleshooting](./AWS-DISCOVERY-TROUBLESHOOTING.md)