@friggframework/devtools 2.0.0--canary.454.726ab78.1 → 2.0.0--canary.454.cbce887.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.
@@ -191,11 +191,11 @@ async function runPrismaMigrate(command = 'dev', verbose = false) {
191
191
 
192
192
  /**
193
193
  * Runs Prisma db push for MongoDB
194
- * Interactive - will prompt user if data loss detected
195
194
  * @param {boolean} verbose - Enable verbose output
195
+ * @param {boolean} nonInteractive - Run in non-interactive mode (accepts data loss, for Lambda/CI)
196
196
  * @returns {Promise<Object>} { success: boolean, output?: string, error?: string }
197
197
  */
198
- async function runPrismaDbPush(verbose = false) {
198
+ async function runPrismaDbPush(verbose = false, nonInteractive = false) {
199
199
  return new Promise((resolve) => {
200
200
  try {
201
201
  const schemaPath = getPrismaSchemaPath('mongodb');
@@ -209,20 +209,52 @@ async function runPrismaDbPush(verbose = false) {
209
209
  '--skip-generate' // We generate separately
210
210
  ];
211
211
 
212
+ // Add non-interactive flag for Lambda/CI environments
213
+ if (nonInteractive) {
214
+ args.push('--accept-data-loss');
215
+ }
216
+
212
217
  if (verbose) {
213
218
  console.log(chalk.gray(`Running: npx ${args.join(' ')}`));
214
219
  }
215
220
 
216
- console.log(chalk.yellow('⚠️ Interactive mode: You may be prompted if schema changes cause data loss'));
221
+ if (nonInteractive) {
222
+ console.log(chalk.yellow('⚠️ Non-interactive mode: Data loss will be automatically accepted'));
223
+ } else {
224
+ console.log(chalk.yellow('⚠️ Interactive mode: You may be prompted if schema changes cause data loss'));
225
+ }
217
226
 
218
227
  const proc = spawn('npx', args, {
219
- stdio: 'inherit', // Interactive mode - user can respond to prompts
228
+ stdio: nonInteractive ? 'pipe' : 'inherit', // Use pipe for non-interactive to capture output
220
229
  env: {
221
230
  ...process.env,
222
231
  PRISMA_HIDE_UPDATE_MESSAGE: '1'
223
232
  }
224
233
  });
225
234
 
235
+ let stdout = '';
236
+ let stderr = '';
237
+
238
+ // Capture output in non-interactive mode
239
+ if (nonInteractive) {
240
+ if (proc.stdout) {
241
+ proc.stdout.on('data', (data) => {
242
+ stdout += data.toString();
243
+ if (verbose) {
244
+ process.stdout.write(data);
245
+ }
246
+ });
247
+ }
248
+ if (proc.stderr) {
249
+ proc.stderr.on('data', (data) => {
250
+ stderr += data.toString();
251
+ if (verbose) {
252
+ process.stderr.write(data);
253
+ }
254
+ });
255
+ }
256
+ }
257
+
226
258
  proc.on('error', (error) => {
227
259
  resolve({
228
260
  success: false,
@@ -234,12 +266,13 @@ async function runPrismaDbPush(verbose = false) {
234
266
  if (code === 0) {
235
267
  resolve({
236
268
  success: true,
237
- output: 'Database push completed successfully'
269
+ output: nonInteractive ? stdout || 'Database push completed successfully' : 'Database push completed successfully'
238
270
  });
239
271
  } else {
240
272
  resolve({
241
273
  success: false,
242
- error: `Database push process exited with code ${code}`
274
+ error: `Database push process exited with code ${code}`,
275
+ output: stderr || stdout
243
276
  });
244
277
  }
245
278
  });
@@ -613,6 +613,20 @@ const createBaseDefinition = (AppDefinition, appEnvironmentVars, discoveredResou
613
613
  { httpApi: { path: '/health/{proxy+}', method: 'GET' } },
614
614
  ],
615
615
  },
616
+ dbMigrate: {
617
+ handler: 'node_modules/@friggframework/core/handlers/workers/db-migration.handler',
618
+ timeout: 300, // 5 minutes for long-running migrations
619
+ memorySize: 512, // Extra memory for Prisma CLI operations
620
+ reservedConcurrency: 1, // Prevent concurrent migrations
621
+ description: 'Runs database migrations via Prisma (invoke manually from CI/CD)',
622
+ // No events - this function is invoked manually via AWS CLI
623
+ maximumEventAge: 60, // Don't retry old migration requests (60 seconds)
624
+ maximumRetryAttempts: 0, // Don't auto-retry failed migrations
625
+ tags: {
626
+ Purpose: 'DatabaseMigration',
627
+ ManagedBy: 'Frigg',
628
+ },
629
+ },
616
630
  },
617
631
  resources: {
618
632
  Resources: {
@@ -1762,6 +1762,97 @@ describe('composeServerlessDefinition', () => {
1762
1762
  });
1763
1763
  });
1764
1764
 
1765
+ describe('Database Migration Lambda', () => {
1766
+ it('should include dbMigrate function in all deployments', async () => {
1767
+ const appDefinition = {
1768
+ name: 'test-app',
1769
+ integrations: []
1770
+ };
1771
+
1772
+ const result = await composeServerlessDefinition(appDefinition);
1773
+
1774
+ // Check dbMigrate function exists
1775
+ expect(result.functions.dbMigrate).toBeDefined();
1776
+ expect(result.functions.dbMigrate.handler).toBe(
1777
+ 'node_modules/@friggframework/core/handlers/workers/db-migration.handler'
1778
+ );
1779
+ });
1780
+
1781
+ it('should configure dbMigrate with correct settings', async () => {
1782
+ const appDefinition = {
1783
+ integrations: []
1784
+ };
1785
+
1786
+ const result = await composeServerlessDefinition(appDefinition);
1787
+
1788
+ const dbMigrate = result.functions.dbMigrate;
1789
+
1790
+ // Check timeout (5 minutes for long migrations)
1791
+ expect(dbMigrate.timeout).toBe(300);
1792
+
1793
+ // Check memory allocation (extra for Prisma CLI)
1794
+ expect(dbMigrate.memorySize).toBe(512);
1795
+
1796
+ // Check description
1797
+ expect(dbMigrate.description).toContain('database migrations');
1798
+ expect(dbMigrate.description).toContain('Prisma');
1799
+ });
1800
+
1801
+ it('should not have HTTP events (manual invocation only)', async () => {
1802
+ const appDefinition = {
1803
+ integrations: []
1804
+ };
1805
+
1806
+ const result = await composeServerlessDefinition(appDefinition);
1807
+
1808
+ const dbMigrate = result.functions.dbMigrate;
1809
+
1810
+ // Should have no events (manually invoked via AWS CLI)
1811
+ expect(dbMigrate.events).toBeUndefined();
1812
+ });
1813
+
1814
+ it('should include dbMigrate even with VPC enabled', async () => {
1815
+ const appDefinition = {
1816
+ vpc: {
1817
+ enable: true,
1818
+ management: 'discover'
1819
+ },
1820
+ integrations: []
1821
+ };
1822
+
1823
+ const result = await composeServerlessDefinition(appDefinition);
1824
+
1825
+ // dbMigrate should exist with VPC configuration
1826
+ expect(result.functions.dbMigrate).toBeDefined();
1827
+
1828
+ // Should have same VPC access as other functions
1829
+ expect(result.provider.vpc).toBeDefined();
1830
+ });
1831
+
1832
+ it('should include dbMigrate with database configuration', async () => {
1833
+ const appDefinition = {
1834
+ vpc: {
1835
+ enable: true,
1836
+ management: 'discover'
1837
+ },
1838
+ database: {
1839
+ postgres: {
1840
+ enable: true,
1841
+ management: 'discover'
1842
+ }
1843
+ },
1844
+ integrations: []
1845
+ };
1846
+
1847
+ const result = await composeServerlessDefinition(appDefinition);
1848
+
1849
+ // dbMigrate should exist alongside database configuration
1850
+ expect(result.functions.dbMigrate).toBeDefined();
1851
+ expect(result.provider.environment.DB_TYPE).toBe('postgresql');
1852
+ expect(result.provider.environment.DATABASE_URL).toBeDefined();
1853
+ });
1854
+ });
1855
+
1765
1856
  describe('Edge Cases', () => {
1766
1857
  it('should handle empty app definition', async () => {
1767
1858
  const appDefinition = {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/devtools",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.454.726ab78.1",
4
+ "version": "2.0.0--canary.454.cbce887.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-ec2": "^3.835.0",
7
7
  "@aws-sdk/client-kms": "^3.835.0",
@@ -11,8 +11,8 @@
11
11
  "@babel/eslint-parser": "^7.18.9",
12
12
  "@babel/parser": "^7.25.3",
13
13
  "@babel/traverse": "^7.25.3",
14
- "@friggframework/schemas": "2.0.0--canary.454.726ab78.1",
15
- "@friggframework/test": "2.0.0--canary.454.726ab78.1",
14
+ "@friggframework/schemas": "2.0.0--canary.454.cbce887.0",
15
+ "@friggframework/test": "2.0.0--canary.454.cbce887.0",
16
16
  "@hapi/boom": "^10.0.1",
17
17
  "@inquirer/prompts": "^5.3.8",
18
18
  "axios": "^1.7.2",
@@ -34,8 +34,8 @@
34
34
  "serverless-http": "^2.7.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@friggframework/eslint-config": "2.0.0--canary.454.726ab78.1",
38
- "@friggframework/prettier-config": "2.0.0--canary.454.726ab78.1",
37
+ "@friggframework/eslint-config": "2.0.0--canary.454.cbce887.0",
38
+ "@friggframework/prettier-config": "2.0.0--canary.454.cbce887.0",
39
39
  "aws-sdk-client-mock": "^4.1.0",
40
40
  "aws-sdk-client-mock-jest": "^4.1.0",
41
41
  "jest": "^30.1.3",
@@ -70,5 +70,5 @@
70
70
  "publishConfig": {
71
71
  "access": "public"
72
72
  },
73
- "gitHead": "726ab78ba26d816f9aadab7e26c1e0495da5c2e7"
73
+ "gitHead": "cbce8872aea93a375c1088a0dcb8d05a5d48d8b7"
74
74
  }