@mapbox/cloudfriend 8.1.0-dev → 8.1.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.
@@ -394,7 +394,6 @@ Log Group, a Role, an Alarm on function errors, and the Lambda Function itself.
394
394
  | [options.DeadLetterConfig] | <code>Object</code> | | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-deadletterconfig). |
395
395
  | [options.Description] | <code>String</code> | <code>&#x27;${logical name} in the ${stack name} stack&#x27;</code> | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-description). |
396
396
  | [options.Environment] | <code>Object</code> | | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-environment). |
397
- | [options.FilterCriteria] | <code>Object</code> | | See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) |
398
397
  | [options.FunctionName] | <code>String</code> | <code>&#x27;${stack name}-${logical name}&#x27;</code> | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-functionname). |
399
398
  | [options.Handler] | <code>String</code> | <code>&#x27;index.handler&#x27;</code> | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-handler). |
400
399
  | [options.KmsKeyArn] | <code>String</code> | | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-kmskeyarn). |
@@ -783,6 +782,7 @@ source mapping.
783
782
  | [options.MaximumBatchingWindowInSeconds] | <code>Number</code> | | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-maximumbatchingwindowinseconds). |
784
783
  | [options.Enabled] | <code>Boolean</code> | <code>true</code> | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-enabled). |
785
784
  | [options.StartingPosition] | <code>String</code> | <code>&#x27;LATEST&#x27;</code> | See [AWS documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-eventsourcemapping.html#cfn-lambda-eventsourcemapping-startingposition). |
785
+ | [options.FilterCriteria] | <code>Object</code> | | See [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html). |
786
786
 
787
787
  **Example**
788
788
  ```js
@@ -796,8 +796,25 @@ const lambda = new cf.shortcuts.StreamLambda({
796
796
  S3Bucket: 'my-code-bucket',
797
797
  S3Key: 'path/to/code.zip'
798
798
  },
799
- EventSourceArn: cf.getAtt('MyStream', 'Arn')
799
+ EventSourceArn: cf.getAtt('MyStream', 'Arn'),
800
800
  });
801
801
 
802
- module.exports = cf.merge(myTemplate, lambda);
802
+ // This lambda only gets invoked for 'INSERT' events for the DynamoDb event source
803
+ const lambdaWithFilterCriteria = new cf.shortcuts.StreamLambda({
804
+ LogicalName: 'MyLambdaWithFilterCriteria',
805
+ Code: {
806
+ S3Bucket: 'my-code-bucket',
807
+ S3Key: 'path/to/code.zip'
808
+ },
809
+ EventSourceArn: cf.getAtt('MyDynamoDbStream', 'Arn'),
810
+ FilterCriteria: {
811
+ Filters: [
812
+ {
813
+ Pattern: JSON.stringify({ eventName: ['INSERT'] }),
814
+ }
815
+ ]
816
+ }
817
+ });
818
+
819
+ module.exports = cf.merge(myTemplate, lambda, lambdaWithFilterCriteria);
803
820
  ```
@@ -26,10 +26,27 @@ const Lambda = require('./lambda');
26
26
  * S3Bucket: 'my-code-bucket',
27
27
  * S3Key: 'path/to/code.zip'
28
28
  * },
29
- * EventSourceArn: cf.getAtt('MyStream', 'Arn')
29
+ * EventSourceArn: cf.getAtt('MyStream', 'Arn'),
30
30
  * });
31
31
  *
32
- * module.exports = cf.merge(myTemplate, lambda);
32
+ * // This lambda only gets invoked for 'INSERT' events for the DynamoDb event source
33
+ * const lambdaWithFilterCriteria = new cf.shortcuts.StreamLambda({
34
+ * LogicalName: 'MyLambdaWithFilterCriteria',
35
+ * Code: {
36
+ * S3Bucket: 'my-code-bucket',
37
+ * S3Key: 'path/to/code.zip'
38
+ * },
39
+ * EventSourceArn: cf.getAtt('MyDynamoDbStream', 'Arn'),
40
+ * FilterCriteria: {
41
+ * Filters: [
42
+ * {
43
+ * Pattern: JSON.stringify({ eventName: ['INSERT'] }),
44
+ * }
45
+ * ]
46
+ * }
47
+ * });
48
+ *
49
+ * module.exports = cf.merge(myTemplate, lambda, lambdaWithFilterCriteria);
33
50
  */
34
51
  class StreamLambda extends Lambda {
35
52
  constructor(options) {
@@ -61,8 +78,23 @@ class StreamLambda extends Lambda {
61
78
  StartingPosition
62
79
  }
63
80
  };
64
-
65
81
  if (FilterCriteria) {
82
+ if (Object.prototype.toString.call(FilterCriteria) !== '[object Object]'){
83
+ throw new Error('`FilterCriteria` must be a JSON-like object');
84
+ }
85
+ if (!(FilterCriteria.Filters && Array.isArray(FilterCriteria.Filters))){
86
+ throw new Error('`FilterCriteria` must contain property `Filter` of type array');
87
+ }
88
+ for (const filter of FilterCriteria.Filters){
89
+ if (!filter.Pattern){
90
+ throw new Error('An object in `FilterCriteria.Filter` was missing the required property `Pattern`');
91
+ }
92
+ try {
93
+ JSON.parse(filter.Pattern);
94
+ } catch (error) {
95
+ throw new Error('An object in `FilterCriteria.Filter` contains a `Pattern` property that is not a JSON parseable string');
96
+ }
97
+ }
66
98
  this.Resources[`${this.LogicalName}EventSource`].Properties.FilterCriteria = FilterCriteria;
67
99
  }
68
100
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapbox/cloudfriend",
3
- "version": "8.1.0-dev",
3
+ "version": "8.1.0",
4
4
  "description": "Helper functions for assembling CloudFormation templates in JavaScript",
5
5
  "main": "index.js",
6
6
  "engines": {
@@ -167,6 +167,13 @@
167
167
  "Properties": {
168
168
  "BatchSize": 10000,
169
169
  "MaximumBatchingWindowInSeconds": 300,
170
+ "FilterCriteria": {
171
+ "Filters": [
172
+ {
173
+ "Pattern": "{\"eventName\":[\"INSERT\",\"MODIFY\"]}"
174
+ }
175
+ ]
176
+ },
170
177
  "Enabled": false,
171
178
  "EventSourceArn": "arn:aws:kinesis:us-east-1:123456789012:stream/fake",
172
179
  "FunctionName": {
@@ -177,4 +184,4 @@
177
184
  }
178
185
  },
179
186
  "Outputs": {}
180
- }
187
+ }
@@ -475,6 +475,13 @@ test('[shortcuts] stream-lambda', (assert) => {
475
475
  S3Key: 'path/to/code.zip'
476
476
  },
477
477
  EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
478
+ FilterCriteria: {
479
+ Filters: [
480
+ {
481
+ Pattern: JSON.stringify({ eventName: ['INSERT', 'MODIFY'] })
482
+ }
483
+ ]
484
+ },
478
485
  BatchSize: 10000,
479
486
  MaximumBatchingWindowInSeconds: 300,
480
487
  Enabled: false,
@@ -492,6 +499,90 @@ test('[shortcuts] stream-lambda', (assert) => {
492
499
  assert.end();
493
500
  });
494
501
 
502
+ test('[shortcuts] StreamLambda FilterCriteria', (assert) => {
503
+ assert.throws(
504
+ () => new cf.shortcuts.StreamLambda({
505
+ LogicalName: 'MyLambda',
506
+ Code: {
507
+ S3Bucket: 'my-code-bucket',
508
+ S3Key: 'path/to/code.zip'
509
+ },
510
+ EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
511
+ FilterCriteria: ['test']
512
+ }),
513
+ '`FilterCriteria` must be a JSON-like object',
514
+ );
515
+ assert.throws(
516
+ () => new cf.shortcuts.StreamLambda({
517
+ LogicalName: 'MyLambda',
518
+ Code: {
519
+ S3Bucket: 'my-code-bucket',
520
+ S3Key: 'path/to/code.zip'
521
+ },
522
+ EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
523
+ FilterCriteria: {}
524
+ }),
525
+ '`FilterCriteria` must contain property `Filter` of type array',
526
+ );
527
+ assert.throws(
528
+ () => new cf.shortcuts.StreamLambda({
529
+ LogicalName: 'MyLambda',
530
+ Code: {
531
+ S3Bucket: 'my-code-bucket',
532
+ S3Key: 'path/to/code.zip'
533
+ },
534
+ EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
535
+ FilterCriteria: {
536
+ Filter: 613
537
+ }
538
+ }),
539
+ '`FilterCriteria` must contain property `Filter` of type array',
540
+ );
541
+ assert.throws(
542
+ () => new cf.shortcuts.StreamLambda({
543
+ LogicalName: 'MyLambda',
544
+ Code: {
545
+ S3Bucket: 'my-code-bucket',
546
+ S3Key: 'path/to/code.zip'
547
+ },
548
+ EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
549
+ FilterCriteria: {
550
+ Filters: [
551
+ {
552
+ NotPattern: JSON.stringify({ eventName: ['INSERT', 'MODIFY'] })
553
+ },
554
+ {
555
+ Pattern: JSON.stringify({ eventName: ['INSERT', 'MODIFY'] })
556
+ }
557
+ ]
558
+ }
559
+ }),
560
+ 'An object in `FilterCriteria.Filter` was missing the required property `Pattern`',
561
+ );
562
+ assert.throws(
563
+ () => new cf.shortcuts.StreamLambda({
564
+ LogicalName: 'MyLambda',
565
+ Code: {
566
+ S3Bucket: 'my-code-bucket',
567
+ S3Key: 'path/to/code.zip'
568
+ },
569
+ EventSourceArn: 'arn:aws:kinesis:us-east-1:123456789012:stream/fake',
570
+ FilterCriteria: {
571
+ Filters: [
572
+ {
573
+ Pattern: '{"eventName":["INSERT","MODIFY"]}'
574
+ },
575
+ {
576
+ Pattern: { eventName: ['INSERT', 'MODIFY'] }
577
+ }
578
+ ]
579
+ }
580
+ }),
581
+ 'An object in `FilterCriteria.Filter` contains a `Pattern` property that is not a JSON parseable string',
582
+ );
583
+ assert.end();
584
+ });
585
+
495
586
  test('[shortcuts] log-subscription-lambda', (assert) => {
496
587
  assert.throws(
497
588
  () => new cf.shortcuts.LogSubscriptionLambda(),
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="WEB_MODULE" version="4">
3
- <component name="NewModuleRootManager">
4
- <content url="file://$MODULE_DIR$">
5
- <excludeFolder url="file://$MODULE_DIR$/temp" />
6
- <excludeFolder url="file://$MODULE_DIR$/.tmp" />
7
- <excludeFolder url="file://$MODULE_DIR$/tmp" />
8
- </content>
9
- <orderEntry type="inheritedJdk" />
10
- <orderEntry type="sourceFolder" forTests="false" />
11
- </component>
12
- </module>
@@ -1,6 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <profile version="1.0">
3
- <option name="myName" value="Project Default" />
4
- <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
- </profile>
6
- </component>
package/.idea/modules.xml DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="ProjectModuleManager">
4
- <modules>
5
- <module fileurl="file://$PROJECT_DIR$/.idea/cloudfriend.iml" filepath="$PROJECT_DIR$/.idea/cloudfriend.iml" />
6
- </modules>
7
- </component>
8
- </project>
package/.idea/vcs.xml DELETED
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <project version="4">
3
- <component name="VcsDirectoryMappings">
4
- <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
- </component>
6
- </project>