@friggframework/devtools 2.0.0--canary.553.7a28e41.0 → 2.0.0--canary.553.4228f35.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.
|
@@ -145,20 +145,20 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
145
145
|
* Build integration resources based on ownership decisions
|
|
146
146
|
*/
|
|
147
147
|
async buildFromDecisions(decisions, appDefinition, result, usePrismaLayer = true) {
|
|
148
|
+
// Create package config first — needed by all Lambda functions including DLQ processor
|
|
149
|
+
const functionPackageConfig = this.createFunctionPackageConfig(usePrismaLayer);
|
|
150
|
+
|
|
148
151
|
// Create InternalErrorQueue if ownership = STACK
|
|
149
152
|
const shouldCreateInternalErrorQueue = decisions.internalErrorQueue.ownership === ResourceOwnership.STACK;
|
|
150
153
|
|
|
151
154
|
if (shouldCreateInternalErrorQueue) {
|
|
152
155
|
console.log(' → Creating InternalErrorQueue in stack');
|
|
153
|
-
this.createInternalErrorQueue(result);
|
|
156
|
+
this.createInternalErrorQueue(result, functionPackageConfig);
|
|
154
157
|
} else {
|
|
155
158
|
console.log(' → Using external InternalErrorQueue');
|
|
156
|
-
this.useExternalInternalErrorQueue(decisions.internalErrorQueue, result);
|
|
159
|
+
this.useExternalInternalErrorQueue(decisions.internalErrorQueue, result, functionPackageConfig);
|
|
157
160
|
}
|
|
158
161
|
|
|
159
|
-
// Create Lambda function definitions and queue resources for each integration
|
|
160
|
-
const functionPackageConfig = this.createFunctionPackageConfig(usePrismaLayer);
|
|
161
|
-
|
|
162
162
|
for (const integration of appDefinition.integrations) {
|
|
163
163
|
const integrationName = integration.Definition.name;
|
|
164
164
|
const queueDecision = decisions.integrations[integrationName].queue;
|
|
@@ -328,16 +328,46 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
328
328
|
/**
|
|
329
329
|
* Create InternalErrorQueue CloudFormation resource
|
|
330
330
|
*/
|
|
331
|
-
createInternalErrorQueue(result) {
|
|
331
|
+
createInternalErrorQueue(result, functionPackageConfig) {
|
|
332
332
|
result.resources.InternalErrorQueue = {
|
|
333
333
|
Type: 'AWS::SQS::Queue',
|
|
334
334
|
Properties: {
|
|
335
335
|
QueueName: '${self:service}-${self:provider.stage}-InternalErrorQueue',
|
|
336
336
|
MessageRetentionPeriod: 1209600, // 14 days
|
|
337
|
-
VisibilityTimeout: 60, // Must be >= DLQ processor Lambda timeout
|
|
337
|
+
VisibilityTimeout: 60, // Must be >= DLQ processor Lambda timeout (30s)
|
|
338
338
|
},
|
|
339
339
|
};
|
|
340
340
|
|
|
341
|
+
this.createDLQObservability(result, functionPackageConfig, {
|
|
342
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
343
|
+
}, {
|
|
344
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'QueueName'],
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
console.log(' ✓ Created InternalErrorQueue resource');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Use external InternalErrorQueue
|
|
352
|
+
*/
|
|
353
|
+
useExternalInternalErrorQueue(decision, result, functionPackageConfig) {
|
|
354
|
+
// Add ARN to environment for Lambda functions
|
|
355
|
+
result.environment.INTERNAL_ERROR_QUEUE_ARN = decision.physicalId;
|
|
356
|
+
|
|
357
|
+
// Extract queue name from ARN for CloudWatch dimensions
|
|
358
|
+
const arnParts = decision.physicalId.split(':');
|
|
359
|
+
const queueName = arnParts[arnParts.length - 1];
|
|
360
|
+
|
|
361
|
+
this.createDLQObservability(result, functionPackageConfig, decision.physicalId, queueName);
|
|
362
|
+
|
|
363
|
+
console.log(` ✓ Using external InternalErrorQueue: ${decision.physicalId}`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Create DLQ observability resources (alarm + processor Lambda).
|
|
368
|
+
* Called for both stack-owned and external InternalErrorQueues.
|
|
369
|
+
*/
|
|
370
|
+
createDLQObservability(result, functionPackageConfig, queueArn, queueName) {
|
|
341
371
|
// CloudWatch Alarm: fires when any message lands in the DLQ
|
|
342
372
|
result.resources.DLQMessageAlarm = {
|
|
343
373
|
Type: 'AWS::CloudWatch::Alarm',
|
|
@@ -350,11 +380,9 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
350
380
|
ComparisonOperator: 'GreaterThanThreshold',
|
|
351
381
|
EvaluationPeriods: 1,
|
|
352
382
|
Period: 60,
|
|
383
|
+
AlarmActions: [{ Ref: 'InternalErrorBridgeTopic' }],
|
|
353
384
|
Dimensions: [
|
|
354
|
-
{
|
|
355
|
-
Name: 'QueueName',
|
|
356
|
-
Value: { 'Fn::GetAtt': ['InternalErrorQueue', 'QueueName'] },
|
|
357
|
-
},
|
|
385
|
+
{ Name: 'QueueName', Value: queueName },
|
|
358
386
|
],
|
|
359
387
|
},
|
|
360
388
|
};
|
|
@@ -362,33 +390,25 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
362
390
|
// DLQ processor Lambda: logs failed messages with structured context
|
|
363
391
|
result.functions.dlqProcessor = {
|
|
364
392
|
handler: 'node_modules/@friggframework/core/handlers/workers/dlq-processor.dlqProcessor',
|
|
393
|
+
skipEsbuild: true,
|
|
394
|
+
package: functionPackageConfig,
|
|
365
395
|
reservedConcurrency: 1,
|
|
366
396
|
timeout: 30,
|
|
367
397
|
events: [
|
|
368
398
|
{
|
|
369
399
|
sqs: {
|
|
370
|
-
arn:
|
|
400
|
+
arn: queueArn,
|
|
371
401
|
batchSize: 10,
|
|
402
|
+
functionResponseType: 'ReportBatchItemFailures',
|
|
372
403
|
},
|
|
373
404
|
},
|
|
374
405
|
],
|
|
375
406
|
};
|
|
376
407
|
|
|
377
|
-
console.log(' ✓ Created InternalErrorQueue resource');
|
|
378
408
|
console.log(' ✓ Created DLQ CloudWatch alarm');
|
|
379
409
|
console.log(' ✓ Created DLQ processor Lambda');
|
|
380
410
|
}
|
|
381
411
|
|
|
382
|
-
/**
|
|
383
|
-
* Use external InternalErrorQueue
|
|
384
|
-
*/
|
|
385
|
-
useExternalInternalErrorQueue(decision, result) {
|
|
386
|
-
// Add ARN to environment for Lambda functions
|
|
387
|
-
result.environment.INTERNAL_ERROR_QUEUE_ARN = decision.physicalId;
|
|
388
|
-
|
|
389
|
-
console.log(` ✓ Using external InternalErrorQueue: ${decision.physicalId}`);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
412
|
/**
|
|
393
413
|
* Create integration-specific SQS queue CloudFormation resource
|
|
394
414
|
*/
|
|
@@ -412,6 +412,18 @@ describe('IntegrationBuilder', () => {
|
|
|
412
412
|
expect(result.resources.DLQMessageAlarm.Properties.Threshold).toBe(0);
|
|
413
413
|
});
|
|
414
414
|
|
|
415
|
+
it('should wire alarm to InternalErrorBridgeTopic for notifications', async () => {
|
|
416
|
+
const appDefinition = {
|
|
417
|
+
integrations: [{ Definition: { name: 'test' } }],
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
421
|
+
|
|
422
|
+
expect(result.resources.DLQMessageAlarm.Properties.AlarmActions).toEqual([
|
|
423
|
+
{ Ref: 'InternalErrorBridgeTopic' },
|
|
424
|
+
]);
|
|
425
|
+
});
|
|
426
|
+
|
|
415
427
|
it('should create a DLQ processor Lambda triggered by InternalErrorQueue', async () => {
|
|
416
428
|
const appDefinition = {
|
|
417
429
|
integrations: [{ Definition: { name: 'test' } }],
|
|
@@ -420,19 +432,21 @@ describe('IntegrationBuilder', () => {
|
|
|
420
432
|
const result = await integrationBuilder.build(appDefinition, {});
|
|
421
433
|
|
|
422
434
|
expect(result.functions.dlqProcessor).toBeDefined();
|
|
423
|
-
expect(result.functions.dlqProcessor.events[0].sqs).toBeDefined();
|
|
424
435
|
expect(result.functions.dlqProcessor.events[0].sqs.arn).toEqual({
|
|
425
436
|
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
426
437
|
});
|
|
438
|
+
expect(result.functions.dlqProcessor.events[0].sqs.functionResponseType).toBe('ReportBatchItemFailures');
|
|
427
439
|
});
|
|
428
440
|
|
|
429
|
-
it('DLQ processor should have short timeout and low concurrency', async () => {
|
|
441
|
+
it('DLQ processor should have skipEsbuild, short timeout, and low concurrency', async () => {
|
|
430
442
|
const appDefinition = {
|
|
431
443
|
integrations: [{ Definition: { name: 'test' } }],
|
|
432
444
|
};
|
|
433
445
|
|
|
434
446
|
const result = await integrationBuilder.build(appDefinition, {});
|
|
435
447
|
|
|
448
|
+
expect(result.functions.dlqProcessor.skipEsbuild).toBe(true);
|
|
449
|
+
expect(result.functions.dlqProcessor.package).toBeDefined();
|
|
436
450
|
expect(result.functions.dlqProcessor.timeout).toBeLessThanOrEqual(60);
|
|
437
451
|
expect(result.functions.dlqProcessor.reservedConcurrency).toBe(1);
|
|
438
452
|
});
|
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.553.
|
|
4
|
+
"version": "2.0.0--canary.553.4228f35.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"@babel/eslint-parser": "^7.18.9",
|
|
26
26
|
"@babel/parser": "^7.25.3",
|
|
27
27
|
"@babel/traverse": "^7.25.3",
|
|
28
|
-
"@friggframework/core": "2.0.0--canary.553.
|
|
29
|
-
"@friggframework/schemas": "2.0.0--canary.553.
|
|
30
|
-
"@friggframework/test": "2.0.0--canary.553.
|
|
28
|
+
"@friggframework/core": "2.0.0--canary.553.4228f35.0",
|
|
29
|
+
"@friggframework/schemas": "2.0.0--canary.553.4228f35.0",
|
|
30
|
+
"@friggframework/test": "2.0.0--canary.553.4228f35.0",
|
|
31
31
|
"@hapi/boom": "^10.0.1",
|
|
32
32
|
"@inquirer/prompts": "^5.3.8",
|
|
33
33
|
"axios": "^1.7.2",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"validate-npm-package-name": "^5.0.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@friggframework/eslint-config": "2.0.0--canary.553.
|
|
59
|
-
"@friggframework/prettier-config": "2.0.0--canary.553.
|
|
58
|
+
"@friggframework/eslint-config": "2.0.0--canary.553.4228f35.0",
|
|
59
|
+
"@friggframework/prettier-config": "2.0.0--canary.553.4228f35.0",
|
|
60
60
|
"aws-sdk-client-mock": "^4.1.0",
|
|
61
61
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
62
62
|
"jest": "^30.1.3",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "4228f350b711214a27e5d3229b2099243282035b"
|
|
92
92
|
}
|