@friggframework/core 2.0.0--canary.627.9cf8622.0 → 2.0.0--canary.627.33970be.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,49 @@
1
+ /**
2
+ * Resolve Migration Via Worker Use Case
3
+ *
4
+ * Resolves a failed Prisma migration (P3009) by invoking the worker Lambda,
5
+ * which has the Prisma CLI installed. Keeps the router Lambda lightweight —
6
+ * same delegation pattern as GetDatabaseStateViaWorkerUseCase.
7
+ */
8
+ class ResolveMigrationViaWorkerUseCase {
9
+ /**
10
+ * @param {Object} dependencies
11
+ * @param {LambdaInvoker} dependencies.lambdaInvoker - Lambda invocation adapter
12
+ * @param {string} dependencies.workerFunctionName - Worker Lambda function name
13
+ */
14
+ constructor({ lambdaInvoker, workerFunctionName }) {
15
+ if (!lambdaInvoker) {
16
+ throw new Error('lambdaInvoker dependency is required');
17
+ }
18
+ if (!workerFunctionName) {
19
+ throw new Error('workerFunctionName is required');
20
+ }
21
+ this.lambdaInvoker = lambdaInvoker;
22
+ this.workerFunctionName = workerFunctionName;
23
+ }
24
+
25
+ /**
26
+ * @param {Object} params
27
+ * @param {string} params.migrationName - Migration to resolve
28
+ * @param {'applied'|'rolled-back'} [params.action] - Resolution mode
29
+ * @param {string} [params.stage] - Deployment stage
30
+ * @returns {Promise<Object>} Worker result body
31
+ */
32
+ async execute({ migrationName, action = 'applied', stage }) {
33
+ const dbType = process.env.DB_TYPE || 'postgresql';
34
+
35
+ console.log(
36
+ `Invoking worker Lambda to resolve migration "${migrationName}" as ${action}: ${this.workerFunctionName}`
37
+ );
38
+
39
+ return this.lambdaInvoker.invoke(this.workerFunctionName, {
40
+ action: 'resolve',
41
+ migrationName,
42
+ resolveAction: action,
43
+ dbType,
44
+ stage,
45
+ });
46
+ }
47
+ }
48
+
49
+ module.exports = { ResolveMigrationViaWorkerUseCase };
@@ -35,6 +35,9 @@ const { LambdaInvoker } = require('../../database/adapters/lambda-invoker');
35
35
  const {
36
36
  GetDatabaseStateViaWorkerUseCase,
37
37
  } = require('../../database/use-cases/get-database-state-via-worker-use-case');
38
+ const {
39
+ ResolveMigrationViaWorkerUseCase,
40
+ } = require('../../database/use-cases/resolve-migration-via-worker-use-case');
38
41
 
39
42
  const router = Router();
40
43
 
@@ -58,6 +61,10 @@ const getDatabaseStateUseCase = new GetDatabaseStateViaWorkerUseCase({
58
61
  lambdaInvoker,
59
62
  workerFunctionName,
60
63
  });
64
+ const resolveMigrationUseCase = new ResolveMigrationViaWorkerUseCase({
65
+ lambdaInvoker,
66
+ workerFunctionName,
67
+ });
61
68
 
62
69
  // Apply admin API key validation to all routes (shared middleware)
63
70
  router.use(validateAdminApiKey);
@@ -262,30 +269,24 @@ router.post(
262
269
  });
263
270
  }
264
271
 
265
- try {
266
- // Import prismaRunner here to avoid circular dependencies
267
- const prismaRunner = require('../../database/utils/prisma-runner');
268
-
269
- const result = await prismaRunner.runPrismaMigrateResolve(migrationName, action, true);
270
-
271
- if (!result.success) {
272
- return res.status(500).json({
273
- success: false,
274
- error: `Failed to resolve migration: ${result.error}`
275
- });
276
- }
272
+ const stage = req.body.stage || process.env.STAGE || 'production';
277
273
 
278
- res.status(200).json({
279
- success: true,
280
- message: `Migration ${migrationName} marked as ${action}`,
274
+ try {
275
+ // Delegate to the worker Lambda (which has the Prisma CLI); the
276
+ // router Lambda is packaged without Prisma.
277
+ const result = await resolveMigrationUseCase.execute({
281
278
  migrationName,
282
- action
279
+ action,
280
+ stage,
283
281
  });
282
+
283
+ res.status(200).json(result);
284
284
  } catch (error) {
285
285
  console.error('Migration resolve failed:', error);
286
286
  return res.status(500).json({
287
287
  success: false,
288
- error: error.message
288
+ error: 'Failed to resolve migration',
289
+ details: error.message,
289
290
  });
290
291
  }
291
292
  })
@@ -188,6 +188,65 @@ exports.handler = async (event, context) => {
188
188
  }
189
189
  }
190
190
 
191
+ // Handle resolve action (P3009 recovery — router delegates here because the
192
+ // worker has the Prisma CLI; the router does not).
193
+ if (action === 'resolve') {
194
+ const { migrationName, resolveAction = 'applied' } = event;
195
+ console.log(`\n========================================`);
196
+ console.log(
197
+ `Action: resolve (migration=${migrationName}, mode=${resolveAction})`
198
+ );
199
+ console.log(`========================================`);
200
+
201
+ if (!migrationName) {
202
+ return {
203
+ statusCode: 400,
204
+ body: { success: false, error: 'migrationName is required' },
205
+ };
206
+ }
207
+ if (!['applied', 'rolled-back'].includes(resolveAction)) {
208
+ return {
209
+ statusCode: 400,
210
+ body: {
211
+ success: false,
212
+ error: 'resolveAction must be "applied" or "rolled-back"',
213
+ },
214
+ };
215
+ }
216
+
217
+ try {
218
+ const result = await prismaRunner.runPrismaMigrateResolve(
219
+ migrationName,
220
+ resolveAction,
221
+ true
222
+ );
223
+ if (!result.success) {
224
+ return {
225
+ statusCode: 500,
226
+ body: {
227
+ success: false,
228
+ error: sanitizeError(result.error),
229
+ },
230
+ };
231
+ }
232
+ return {
233
+ statusCode: 200,
234
+ body: {
235
+ success: true,
236
+ message: `Migration ${migrationName} marked as ${resolveAction}`,
237
+ migrationName,
238
+ action: resolveAction,
239
+ },
240
+ };
241
+ } catch (error) {
242
+ console.error('❌ Migration resolve failed:', error.message);
243
+ return {
244
+ statusCode: 500,
245
+ body: { success: false, error: sanitizeError(error.message) },
246
+ };
247
+ }
248
+ }
249
+
191
250
  // Otherwise, handle migration (existing code)
192
251
  console.log(`\n========================================`);
193
252
  console.log(`Action: migrate (migrationId=${migrationId || 'new'})`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.627.9cf8622.0",
4
+ "version": "2.0.0--canary.627.33970be.0",
5
5
  "dependencies": {
6
6
  "@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
7
7
  "@aws-sdk/client-kms": "^3.588.0",
@@ -46,9 +46,9 @@
46
46
  }
47
47
  },
48
48
  "devDependencies": {
49
- "@friggframework/eslint-config": "2.0.0--canary.627.9cf8622.0",
50
- "@friggframework/prettier-config": "2.0.0--canary.627.9cf8622.0",
51
- "@friggframework/test": "2.0.0--canary.627.9cf8622.0",
49
+ "@friggframework/eslint-config": "2.0.0--canary.627.33970be.0",
50
+ "@friggframework/prettier-config": "2.0.0--canary.627.33970be.0",
51
+ "@friggframework/test": "2.0.0--canary.627.33970be.0",
52
52
  "@prisma/client": "^6.19.3",
53
53
  "@types/lodash": "4.17.15",
54
54
  "@typescript-eslint/eslint-plugin": "^8.0.0",
@@ -88,5 +88,5 @@
88
88
  "publishConfig": {
89
89
  "access": "public"
90
90
  },
91
- "gitHead": "9cf8622beb42a7a630438459adc973dccbc54c3e"
91
+ "gitHead": "33970be6bc4ffa8e60d4c2799d6c24da4409bf5e"
92
92
  }