@friggframework/devtools 2.0.0--canary.608.e6b65ff.0 → 2.0.0--canary.610.ca077d5.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.
@@ -196,8 +196,6 @@ class IntegrationBuilder extends InfrastructureBuilder {
196
196
  );
197
197
  }
198
198
 
199
- this.createUserActionQueue(result, functionPackageConfig, usePrismaLayer);
200
-
201
199
  for (const integration of appDefinition.integrations) {
202
200
  const integrationName = integration.Definition.name;
203
201
  const queueDecision = decisions.integrations[integrationName].queue;
@@ -474,99 +472,6 @@ class IntegrationBuilder extends InfrastructureBuilder {
474
472
  console.log(' ✓ Created InternalErrorQueue resource');
475
473
  }
476
474
 
477
- /**
478
- * App-level FIFO queue + DLQ + worker for `dispatch: 'queue'` events. One
479
- * queue serves all integrations; MessageGroupId = integrationId serializes
480
- * per integration. Always created, like the InternalErrorQueue.
481
- */
482
- createUserActionQueue(result, functionPackageConfig, usePrismaLayer = true) {
483
- const queueName =
484
- '${self:service}-${self:provider.stage}-FriggUserActionQueue.fifo';
485
- const dlqName =
486
- '${self:service}-${self:provider.stage}-FriggUserActionDLQ.fifo';
487
-
488
- result.custom.FriggUserActionQueue = queueName;
489
- result.custom.FriggUserActionDLQ = dlqName;
490
-
491
- // A FIFO source queue can only redrive to a FIFO DLQ.
492
- result.resources.FriggUserActionDLQ = {
493
- Type: 'AWS::SQS::Queue',
494
- Properties: {
495
- QueueName: '${self:custom.FriggUserActionDLQ}',
496
- FifoQueue: true,
497
- MessageRetentionPeriod: 1209600, // 14 days
498
- },
499
- };
500
-
501
- // No ContentBasedDeduplication: the producer sends a unique dedup id so
502
- // two distinct requests with identical bodies both run (not deduped).
503
- result.resources.FriggUserActionQueue = {
504
- Type: 'AWS::SQS::Queue',
505
- Properties: {
506
- QueueName: '${self:custom.FriggUserActionQueue}',
507
- FifoQueue: true,
508
- MessageRetentionPeriod: 345600, // 4 days
509
- VisibilityTimeout: 1800, // >= worker timeout (900s)
510
- RedrivePolicy: {
511
- maxReceiveCount: 2,
512
- deadLetterTargetArn: {
513
- 'Fn::GetAtt': ['FriggUserActionDLQ', 'Arn'],
514
- },
515
- },
516
- },
517
- };
518
-
519
- result.environment.USER_ACTION_QUEUE_URL = {
520
- Ref: 'FriggUserActionQueue',
521
- };
522
-
523
- result.resources.FriggUserActionDLQAlarm = {
524
- Type: 'AWS::CloudWatch::Alarm',
525
- Properties: {
526
- AlarmDescription:
527
- 'Messages in FriggUserActionDLQ — eventual (queued) integration event failures',
528
- Namespace: 'AWS/SQS',
529
- MetricName: 'ApproximateNumberOfMessagesVisible',
530
- Statistic: 'Maximum',
531
- Threshold: 0,
532
- ComparisonOperator: 'GreaterThanThreshold',
533
- EvaluationPeriods: 1,
534
- Period: 300,
535
- AlarmActions: [{ Ref: 'InternalErrorBridgeTopic' }],
536
- Dimensions: [
537
- {
538
- Name: 'QueueName',
539
- Value: {
540
- 'Fn::GetAtt': ['FriggUserActionDLQ', 'QueueName'],
541
- },
542
- },
543
- ],
544
- },
545
- };
546
-
547
- // No reservedConcurrency: FIFO already serializes per group; capping
548
- // would serialize across all integrations.
549
- result.functions.userActionQueueWorker = {
550
- handler:
551
- 'node_modules/@friggframework/core/handlers/workers/user-action-worker.userActionQueueWorker',
552
- skipEsbuild: true,
553
- package: functionPackageConfig,
554
- ...(usePrismaLayer && { layers: [{ Ref: 'PrismaLambdaLayer' }] }),
555
- timeout: 900,
556
- events: [
557
- {
558
- sqs: {
559
- arn: { 'Fn::GetAtt': ['FriggUserActionQueue', 'Arn'] },
560
- batchSize: 1,
561
- functionResponseType: 'ReportBatchItemFailures',
562
- },
563
- },
564
- ],
565
- };
566
-
567
- console.log(' ✓ Created FriggUserActionQueue (.fifo) + DLQ + worker');
568
- }
569
-
570
475
  /**
571
476
  * Use external InternalErrorQueue
572
477
  */
@@ -751,10 +751,9 @@ describe('IntegrationBuilder', () => {
751
751
 
752
752
  const functionKeys = Object.keys(result.functions);
753
753
 
754
- // App-level functions (dlqProcessor, userActionQueueWorker) come first.
754
+ // Expected order: dlqProcessor (from InternalErrorQueue), webhook, integration, queueWorker
755
755
  expect(functionKeys).toEqual([
756
756
  'dlqProcessor',
757
- 'userActionQueueWorker',
758
757
  'testWebhook',
759
758
  'test',
760
759
  'testQueueWorker',
@@ -936,122 +935,5 @@ describe('IntegrationBuilder', () => {
936
935
  );
937
936
  });
938
937
  });
939
-
940
- describe('User-Action FIFO queue', () => {
941
- const appDefinition = {
942
- integrations: [{ Definition: { name: 'test' } }],
943
- };
944
-
945
- it('creates a FIFO queue without ContentBasedDeduplication', async () => {
946
- const result = await integrationBuilder.build(appDefinition, {});
947
-
948
- const q = result.resources.FriggUserActionQueue;
949
- expect(q).toBeDefined();
950
- expect(q.Type).toBe('AWS::SQS::Queue');
951
- expect(q.Properties.FifoQueue).toBe(true);
952
- expect(q.Properties.ContentBasedDeduplication).toBeUndefined();
953
- expect(q.Properties.VisibilityTimeout).toBe(1800);
954
- expect(q.Properties.MessageRetentionPeriod).toBe(345600);
955
- });
956
-
957
- it('redrives to the FIFO DLQ with maxReceiveCount 2', async () => {
958
- const result = await integrationBuilder.build(appDefinition, {});
959
-
960
- expect(
961
- result.resources.FriggUserActionQueue.Properties.RedrivePolicy
962
- ).toEqual({
963
- maxReceiveCount: 2,
964
- deadLetterTargetArn: {
965
- 'Fn::GetAtt': ['FriggUserActionDLQ', 'Arn'],
966
- },
967
- });
968
- });
969
-
970
- it('creates a FIFO DLQ with 14-day retention', async () => {
971
- const result = await integrationBuilder.build(appDefinition, {});
972
-
973
- const dlq = result.resources.FriggUserActionDLQ;
974
- expect(dlq).toBeDefined();
975
- expect(dlq.Properties.FifoQueue).toBe(true);
976
- expect(dlq.Properties.MessageRetentionPeriod).toBe(1209600);
977
- });
978
-
979
- it('creates the worker bound to the FIFO queue ARN with no reservedConcurrency', async () => {
980
- const result = await integrationBuilder.build(appDefinition, {});
981
-
982
- const worker = result.functions.userActionQueueWorker;
983
- expect(worker).toBeDefined();
984
- expect(worker.handler).toBe(
985
- 'node_modules/@friggframework/core/handlers/workers/user-action-worker.userActionQueueWorker'
986
- );
987
- expect(worker.timeout).toBe(900);
988
- expect(worker.reservedConcurrency).toBeUndefined();
989
- expect(worker.events).toEqual([
990
- {
991
- sqs: {
992
- arn: { 'Fn::GetAtt': ['FriggUserActionQueue', 'Arn'] },
993
- batchSize: 1,
994
- functionResponseType: 'ReportBatchItemFailures',
995
- },
996
- },
997
- ]);
998
- });
999
-
1000
- it('exposes USER_ACTION_QUEUE_URL to all Lambdas', async () => {
1001
- const result = await integrationBuilder.build(appDefinition, {});
1002
-
1003
- expect(result.environment.USER_ACTION_QUEUE_URL).toEqual({
1004
- Ref: 'FriggUserActionQueue',
1005
- });
1006
- });
1007
-
1008
- it('alarms on the FIFO DLQ via the InternalErrorBridgeTopic', async () => {
1009
- const result = await integrationBuilder.build(appDefinition, {});
1010
-
1011
- const alarm = result.resources.FriggUserActionDLQAlarm;
1012
- expect(alarm).toBeDefined();
1013
- expect(alarm.Properties.AlarmActions).toEqual([
1014
- { Ref: 'InternalErrorBridgeTopic' },
1015
- ]);
1016
- });
1017
-
1018
- it('creates exactly one FIFO queue + worker regardless of integration count', async () => {
1019
- const result = await integrationBuilder.build(
1020
- {
1021
- integrations: [
1022
- { Definition: { name: 'hubspot' } },
1023
- { Definition: { name: 'salesforce' } },
1024
- { Definition: { name: 'slack' } },
1025
- ],
1026
- },
1027
- {}
1028
- );
1029
-
1030
- const fifoQueues = Object.keys(result.resources).filter(
1031
- (k) => k === 'FriggUserActionQueue'
1032
- );
1033
- expect(fifoQueues).toHaveLength(1);
1034
- expect(result.functions.userActionQueueWorker).toBeDefined();
1035
- });
1036
-
1037
- it('does not make per-integration queues FIFO', async () => {
1038
- const result = await integrationBuilder.build(appDefinition, {});
1039
-
1040
- expect(
1041
- result.resources.TestQueue.Properties.FifoQueue
1042
- ).toBeUndefined();
1043
- });
1044
-
1045
- it('omits the Prisma layer on the worker when usePrismaLambdaLayer=false', async () => {
1046
- const result = await integrationBuilder.build(
1047
- { usePrismaLambdaLayer: false, integrations: [{ Definition: { name: 'test' } }] },
1048
- {}
1049
- );
1050
-
1051
- expect(
1052
- result.functions.userActionQueueWorker.layers
1053
- ).toBeUndefined();
1054
- });
1055
- });
1056
938
  });
1057
939
 
@@ -426,8 +426,6 @@ function generateIAMCloudFormation(options = {}) {
426
426
  ],
427
427
  Resource: [
428
428
  { 'Fn::Sub': 'arn:aws:sqs:*:${AWS::AccountId}:*frigg*' },
429
- // Case-sensitive: lowercase "*frigg*" won't match "FriggUserActionQueue.fifo".
430
- { 'Fn::Sub': 'arn:aws:sqs:*:${AWS::AccountId}:*Frigg*' },
431
429
  {
432
430
  'Fn::Sub':
433
431
  'arn:aws:sqs:*:${AWS::AccountId}:internal-error-queue-*',
@@ -182,22 +182,6 @@ describe('IAM Generator', () => {
182
182
  expect(yaml).toContain('internal-error-queue-*');
183
183
  });
184
184
 
185
- it('should include a case-sensitive *Frigg* SQS resource for the FIFO queue', () => {
186
- const appDefinition = {
187
- name: 'test-app',
188
- integrations: [],
189
- };
190
-
191
- const summary = getFeatureSummary(appDefinition);
192
- const yaml = generateIAMCloudFormation({
193
- appName: summary.appName,
194
- features: summary.features,
195
- });
196
-
197
- // The lowercase "*frigg*" glob would not match "...-FriggUserActionQueue.fifo".
198
- expect(yaml).toContain(':*Frigg*');
199
- });
200
-
201
185
  it('should generate outputs section', () => {
202
186
  const appDefinition = {
203
187
  name: 'test-app',
@@ -205,8 +205,6 @@ Resources:
205
205
  - 'sqs:UntagQueue'
206
206
  Resource:
207
207
  - !Sub 'arn:aws:sqs:*:${AWS::AccountId}:*frigg*'
208
- # Case-sensitive: lowercase "*frigg*" won't match "FriggUserActionQueue.fifo".
209
- - !Sub 'arn:aws:sqs:*:${AWS::AccountId}:*Frigg*'
210
208
  - !Sub 'arn:aws:sqs:*:${AWS::AccountId}:internal-error-queue-*'
211
209
 
212
210
  # SNS permissions
@@ -196,8 +196,6 @@ function createBaseDefinition(
196
196
  ],
197
197
  Resource: [
198
198
  { 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'] },
199
- // Explicit: the "-*Queue" glob below doesn't match ".fifo".
200
- { 'Fn::GetAtt': ['FriggUserActionQueue', 'Arn'] },
201
199
  {
202
200
  'Fn::Join': [
203
201
  ':',
@@ -133,11 +133,6 @@ describe('Base Definition Factory', () => {
133
133
  stmt => stmt.Action.includes('sqs:SendMessage')
134
134
  );
135
135
  expect(sqsPermission).toBeDefined();
136
-
137
- // The "-*Queue" glob doesn't match ".fifo", so the ARN is explicit.
138
- expect(sqsPermission.Resource).toContainEqual({
139
- 'Fn::GetAtt': ['FriggUserActionQueue', 'Arn'],
140
- });
141
136
  });
142
137
 
143
138
  it('should include required plugins', () => {
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.608.e6b65ff.0",
4
+ "version": "2.0.0--canary.610.ca077d5.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.608.e6b65ff.0",
29
- "@friggframework/schemas": "2.0.0--canary.608.e6b65ff.0",
30
- "@friggframework/test": "2.0.0--canary.608.e6b65ff.0",
28
+ "@friggframework/core": "2.0.0--canary.610.ca077d5.0",
29
+ "@friggframework/schemas": "2.0.0--canary.610.ca077d5.0",
30
+ "@friggframework/test": "2.0.0--canary.610.ca077d5.0",
31
31
  "@hapi/boom": "^10.0.1",
32
32
  "@inquirer/prompts": "^5.3.8",
33
33
  "axios": "^1.18.0",
@@ -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.608.e6b65ff.0",
59
- "@friggframework/prettier-config": "2.0.0--canary.608.e6b65ff.0",
58
+ "@friggframework/eslint-config": "2.0.0--canary.610.ca077d5.0",
59
+ "@friggframework/prettier-config": "2.0.0--canary.610.ca077d5.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": "e6b65ff3bf4a3b3e7777a1f2a6cf1cecd24bedd7"
91
+ "gitHead": "ca077d5f47ea8b69880c3adeebbdbd3a6ac5abb5"
92
92
  }