@digitraffic/common 2024.6.26-2 → 2024.7.2-1
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.
- package/dist/__test__/dependencies.test.mjs +2 -2
- package/dist/__test__/infra/acl-builder.test.mjs +4 -7
- package/dist/__test__/infra/api/static-integration.test.mjs +8 -6
- package/dist/__test__/infra/scheduler.test.mjs +2 -2
- package/dist/__test__/infra/security-rule.test.mjs +2 -2
- package/dist/__test__/secrets/secret-holder.test.mjs +1 -1
- package/dist/__test__/secrets/secret.test.mjs +1 -1
- package/dist/__test__/stack/rest-apis.test.mjs +4 -4
- package/dist/__test__/utils/utils.test.mjs +3 -0
- package/dist/aws/infra/acl-builder.mjs +44 -44
- package/dist/aws/infra/api/static-integration.mjs +3 -5
- package/dist/aws/infra/security-rule.mjs +6 -6
- package/dist/aws/infra/stack/monitoredfunction.mjs +6 -6
- package/dist/aws/infra/stack/rest_apis.mjs +13 -7
- package/dist/aws/infra/stack/stack-checking-aspect.mjs +2 -2
- package/dist/aws/infra/stack/stack.mjs +2 -1
- package/dist/aws/runtime/apikey.mjs +5 -3
- package/dist/test/db-testutils.mjs +2 -2
- package/dist/utils/geometry.d.mts +6 -3
- package/dist/utils/geometry.mjs +11 -4
- package/dist/utils/slack.mjs +1 -1
- package/dist/utils/utils.d.mts +5 -0
- package/dist/utils/utils.mjs +7 -0
- package/package.json +1 -2
@@ -1,7 +1,7 @@
|
|
1
1
|
const madge = await import("madge");
|
2
2
|
const WHITELISTED_DEPENDENCIES = [
|
3
3
|
// aspect is using DigitrafficStack with instanceof, can't remove
|
4
|
-
`["aws/infra/stack/stack.mjs","aws/infra/stack/stack-checking-aspect.mjs"]
|
4
|
+
`["aws/infra/stack/stack.mjs","aws/infra/stack/stack-checking-aspect.mjs"]`,
|
5
5
|
];
|
6
6
|
function whitelist(circular) {
|
7
7
|
return !WHITELISTED_DEPENDENCIES.includes(JSON.stringify(circular));
|
@@ -11,7 +11,7 @@ function assertNoErrors(errors) {
|
|
11
11
|
}
|
12
12
|
test("circular dependencies", async () => {
|
13
13
|
const instance = await madge.default("dist", {
|
14
|
-
fileExtensions: ["mts", "mjs"]
|
14
|
+
fileExtensions: ["mts", "mjs"],
|
15
15
|
});
|
16
16
|
const circulars = instance.circular();
|
17
17
|
const errors = circulars.filter(whitelist);
|
@@ -27,7 +27,7 @@ describe("acl-builder tests", () => {
|
|
27
27
|
createBuilder().withThrottleDigitrafficUserIp(100),
|
28
28
|
createBuilder().withThrottleDigitrafficUserIpAndUriPath(100),
|
29
29
|
createBuilder().withThrottleAnonymousUserIp(100),
|
30
|
-
createBuilder().withThrottleAnonymousUserIpAndUriPath(100)
|
30
|
+
createBuilder().withThrottleAnonymousUserIpAndUriPath(100),
|
31
31
|
]) {
|
32
32
|
const acl = aclBuilder.build();
|
33
33
|
// Check that the rule exists and a custom response is defined
|
@@ -40,19 +40,16 @@ describe("acl-builder tests", () => {
|
|
40
40
|
}
|
41
41
|
});
|
42
42
|
test("Cannot define two rules with the same name", () => {
|
43
|
-
expect(() => createBuilder()
|
44
|
-
.withThrottleAnonymousUserIp(10)
|
45
|
-
.withThrottleAnonymousUserIp(200)
|
46
|
-
.build()).toThrow();
|
43
|
+
expect(() => createBuilder().withThrottleAnonymousUserIp(10).withThrottleAnonymousUserIp(200).build()).toThrow();
|
47
44
|
});
|
48
45
|
test("throtle rule without limit does nothing", () => {
|
49
46
|
for (const aclBuilder of [
|
50
47
|
createBuilder().withThrottleDigitrafficUserIp(undefined),
|
51
48
|
createBuilder().withThrottleDigitrafficUserIpAndUriPath(undefined),
|
52
49
|
createBuilder().withThrottleAnonymousUserIp(null),
|
53
|
-
createBuilder().withThrottleAnonymousUserIpAndUriPath(null)
|
50
|
+
createBuilder().withThrottleAnonymousUserIpAndUriPath(null),
|
54
51
|
]) {
|
55
|
-
expect(() => aclBuilder.build()).toThrowError(
|
52
|
+
expect(() => aclBuilder.build()).toThrowError("No rules");
|
56
53
|
}
|
57
54
|
});
|
58
55
|
});
|
@@ -5,21 +5,23 @@ describe("response tests", () => {
|
|
5
5
|
const integrationResponse = DigitrafficStaticIntegration.createIntegrationResponse("FakeResource", MediaType.APPLICATION_JSON, { "test-header": "test-value" });
|
6
6
|
expect(integrationResponse).toEqual({
|
7
7
|
responseParameters: {
|
8
|
-
"method.response.header.test-header": "'test-value'"
|
8
|
+
"method.response.header.test-header": "'test-value'",
|
9
9
|
},
|
10
10
|
responseTemplates: {
|
11
|
-
"application/json": "FakeResource"
|
11
|
+
"application/json": "FakeResource",
|
12
12
|
},
|
13
|
-
statusCode: "200"
|
13
|
+
statusCode: "200",
|
14
14
|
});
|
15
15
|
});
|
16
16
|
it("createMethodResponse works", () => {
|
17
|
-
const methodResponse = DigitrafficStaticIntegration.createMethodResponse({
|
17
|
+
const methodResponse = DigitrafficStaticIntegration.createMethodResponse({
|
18
|
+
"test-header": "test-value",
|
19
|
+
});
|
18
20
|
expect(methodResponse).toEqual({
|
19
21
|
responseParameters: {
|
20
|
-
"method.response.header.test-header": true
|
22
|
+
"method.response.header.test-header": true,
|
21
23
|
},
|
22
|
-
statusCode: "200"
|
24
|
+
statusCode: "200",
|
23
25
|
});
|
24
26
|
});
|
25
27
|
});
|
@@ -10,8 +10,8 @@ describe("scheduler tests", () => {
|
|
10
10
|
template.hasResource("AWS::Events::Rule", {
|
11
11
|
Properties: {
|
12
12
|
ScheduleExpression: expectedRate,
|
13
|
-
State: "ENABLED"
|
14
|
-
}
|
13
|
+
State: "ENABLED",
|
14
|
+
},
|
15
15
|
});
|
16
16
|
}
|
17
17
|
test("everyMinute", () => expectRate((stack) => Scheduler.everyMinute(stack, "test"), "rate(1 minute)"));
|
@@ -12,7 +12,7 @@ describe("Rest api test", () => {
|
|
12
12
|
shortName: "test",
|
13
13
|
stackProps: {},
|
14
14
|
trafficType: TrafficType.ROAD,
|
15
|
-
warningTopicArn: ""
|
15
|
+
warningTopicArn: "",
|
16
16
|
});
|
17
17
|
const publicApi = new DigitrafficRestApi(stack, "test", "testName");
|
18
18
|
const apiResource = publicApi.root.addResource("api");
|
@@ -30,12 +30,12 @@ describe("Rest api test", () => {
|
|
30
30
|
ResponseParameters: Match.objectEquals({
|
31
31
|
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,Digitraffic-User'",
|
32
32
|
"method.response.header.Access-Control-Allow-Origin": "'*'",
|
33
|
-
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,HEAD'"
|
33
|
+
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,HEAD'",
|
34
34
|
}),
|
35
|
-
})
|
35
|
+
}),
|
36
36
|
]),
|
37
37
|
},
|
38
|
-
}
|
38
|
+
},
|
39
39
|
});
|
40
40
|
});
|
41
41
|
});
|
@@ -39,5 +39,8 @@ describe("ArrayUtils", () => {
|
|
39
39
|
test("getLast - two objects", () => {
|
40
40
|
expect(ArrayUtils.getLast([1, 2])).toEqual(2);
|
41
41
|
});
|
42
|
+
test("isDefined", () => {
|
43
|
+
expect([1, 2, undefined, null, 3].filter(ArrayUtils.isDefined)).toEqual([1, 2, 3]);
|
44
|
+
});
|
42
45
|
});
|
43
46
|
//# sourceMappingURL=utils.test.mjs.map
|
@@ -64,17 +64,17 @@ export class AclBuilder {
|
|
64
64
|
visibilityConfig: {
|
65
65
|
sampledRequestsEnabled: true,
|
66
66
|
cloudWatchMetricsEnabled: true,
|
67
|
-
metricName: name
|
67
|
+
metricName: name,
|
68
68
|
},
|
69
69
|
action: {
|
70
70
|
block: {
|
71
71
|
customResponse: {
|
72
72
|
responseCode: 429,
|
73
|
-
customResponseBodyKey
|
74
|
-
}
|
75
|
-
}
|
73
|
+
customResponseBodyKey,
|
74
|
+
},
|
75
|
+
},
|
76
76
|
},
|
77
|
-
statement: createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath)
|
77
|
+
statement: createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath),
|
78
78
|
});
|
79
79
|
return this;
|
80
80
|
}
|
@@ -82,7 +82,7 @@ export class AclBuilder {
|
|
82
82
|
if (key in this._customResponseBodies) {
|
83
83
|
logger.warn({
|
84
84
|
method: "acl-builder.withCustomResponseBody",
|
85
|
-
message: `Overriding custom response body with key ${key}
|
85
|
+
message: `Overriding custom response body with key ${key}`,
|
86
86
|
});
|
87
87
|
}
|
88
88
|
this._customResponseBodies[key] = customResponseBody;
|
@@ -131,21 +131,21 @@ export class AclBuilder {
|
|
131
131
|
if (!this._isCustomResponseBodyKeySet(customResponseBodyKey)) {
|
132
132
|
this.withCustomResponseBody(customResponseBodyKey, {
|
133
133
|
content: `Request rate is limited to ${limit} requests in a 5 minute window.`,
|
134
|
-
contentType: "TEXT_PLAIN"
|
134
|
+
contentType: "TEXT_PLAIN",
|
135
135
|
});
|
136
136
|
}
|
137
137
|
}
|
138
138
|
_logMissingLimit(method) {
|
139
139
|
logger.warn({
|
140
140
|
method: `acl-builder.${method}`,
|
141
|
-
message: `'limit' was not defined. Not setting a throttle rule
|
141
|
+
message: `'limit' was not defined. Not setting a throttle rule`,
|
142
142
|
});
|
143
143
|
}
|
144
144
|
build() {
|
145
145
|
if (this._rules.length === 0) {
|
146
146
|
throw new Error("No rules defined for WebACL");
|
147
147
|
}
|
148
|
-
const uniqueRuleNames = new Set(this._rules.map(rule => rule.name));
|
148
|
+
const uniqueRuleNames = new Set(this._rules.map((rule) => rule.name));
|
149
149
|
if (uniqueRuleNames.size != this._rules.length) {
|
150
150
|
throw new Error("Tried to create an Access Control List with multiple rules having the same name");
|
151
151
|
}
|
@@ -155,7 +155,7 @@ export class AclBuilder {
|
|
155
155
|
visibilityConfig: {
|
156
156
|
cloudWatchMetricsEnabled: true,
|
157
157
|
metricName: "WAF-Blocked",
|
158
|
-
sampledRequestsEnabled: false
|
158
|
+
sampledRequestsEnabled: false,
|
159
159
|
},
|
160
160
|
rules: this._rules,
|
161
161
|
customResponseBodies: this._customResponseBodies,
|
@@ -169,28 +169,28 @@ const CUSTOM_KEYS_IP_AND_URI_PATH = [
|
|
169
169
|
textTransformations: [
|
170
170
|
{
|
171
171
|
priority: 1,
|
172
|
-
type: "LOWERCASE"
|
172
|
+
type: "LOWERCASE",
|
173
173
|
},
|
174
174
|
{
|
175
175
|
priority: 2,
|
176
|
-
type: "NORMALIZE_PATH"
|
176
|
+
type: "NORMALIZE_PATH",
|
177
177
|
},
|
178
178
|
{
|
179
179
|
priority: 3,
|
180
|
-
type: "MD5"
|
181
|
-
}
|
182
|
-
]
|
183
|
-
}
|
180
|
+
type: "MD5",
|
181
|
+
},
|
182
|
+
],
|
183
|
+
},
|
184
184
|
},
|
185
185
|
{
|
186
|
-
ip: {}
|
187
|
-
}
|
186
|
+
ip: {},
|
187
|
+
},
|
188
188
|
];
|
189
189
|
function notStatement(statement) {
|
190
190
|
return {
|
191
191
|
notStatement: {
|
192
|
-
statement
|
193
|
-
}
|
192
|
+
statement,
|
193
|
+
},
|
194
194
|
};
|
195
195
|
}
|
196
196
|
function createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath) {
|
@@ -200,12 +200,12 @@ function createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath)
|
|
200
200
|
comparisonOperator: isHeaderRequired ? "GT" : "GE",
|
201
201
|
fieldToMatch: {
|
202
202
|
singleHeader: {
|
203
|
-
Name: "digitraffic-user"
|
204
|
-
}
|
203
|
+
Name: "digitraffic-user",
|
204
|
+
},
|
205
205
|
},
|
206
206
|
textTransformations: [{ priority: 0, type: "NONE" }],
|
207
|
-
size: 0
|
208
|
-
}
|
207
|
+
size: 0,
|
208
|
+
},
|
209
209
|
};
|
210
210
|
// header present -> size > 0
|
211
211
|
// header not present -> NOT(size >= 0)
|
@@ -215,16 +215,16 @@ function createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath)
|
|
215
215
|
aggregateKeyType: "CUSTOM_KEYS",
|
216
216
|
customKeys: CUSTOM_KEYS_IP_AND_URI_PATH,
|
217
217
|
limit: limit,
|
218
|
-
scopeDownStatement: isHeaderRequired ? matchStatement : notStatement(matchStatement)
|
219
|
-
}
|
218
|
+
scopeDownStatement: isHeaderRequired ? matchStatement : notStatement(matchStatement),
|
219
|
+
},
|
220
220
|
};
|
221
221
|
}
|
222
222
|
return {
|
223
223
|
rateBasedStatement: {
|
224
224
|
aggregateKeyType: "IP",
|
225
225
|
limit: limit,
|
226
|
-
scopeDownStatement: isHeaderRequired ? matchStatement : notStatement(matchStatement)
|
227
|
-
}
|
226
|
+
scopeDownStatement: isHeaderRequired ? matchStatement : notStatement(matchStatement),
|
227
|
+
},
|
228
228
|
};
|
229
229
|
}
|
230
230
|
function createAWSCommonRuleSet() {
|
@@ -236,10 +236,10 @@ function createAWSCommonRuleSet() {
|
|
236
236
|
excludedRules: [
|
237
237
|
{ name: "NoUserAgent_HEADER" },
|
238
238
|
{ name: "SizeRestrictions_BODY" },
|
239
|
-
{ name: "GenericRFI_BODY" }
|
240
|
-
]
|
241
|
-
}
|
242
|
-
}
|
239
|
+
{ name: "GenericRFI_BODY" },
|
240
|
+
],
|
241
|
+
},
|
242
|
+
},
|
243
243
|
});
|
244
244
|
}
|
245
245
|
function createAWSReputationList() {
|
@@ -247,9 +247,9 @@ function createAWSReputationList() {
|
|
247
247
|
statement: {
|
248
248
|
managedRuleGroupStatement: {
|
249
249
|
vendorName: "AWS",
|
250
|
-
name: "AWSManagedRulesAmazonIpReputationList"
|
251
|
-
}
|
252
|
-
}
|
250
|
+
name: "AWSManagedRulesAmazonIpReputationList",
|
251
|
+
},
|
252
|
+
},
|
253
253
|
});
|
254
254
|
}
|
255
255
|
function createAWSKnownBadInput() {
|
@@ -257,9 +257,9 @@ function createAWSKnownBadInput() {
|
|
257
257
|
statement: {
|
258
258
|
managedRuleGroupStatement: {
|
259
259
|
vendorName: "AWS",
|
260
|
-
name: "AWSManagedRulesKnownBadInputsRuleSet"
|
261
|
-
}
|
262
|
-
}
|
260
|
+
name: "AWSManagedRulesKnownBadInputsRuleSet",
|
261
|
+
},
|
262
|
+
},
|
263
263
|
});
|
264
264
|
}
|
265
265
|
function createAWSAntiSQLInjection() {
|
@@ -267,9 +267,9 @@ function createAWSAntiSQLInjection() {
|
|
267
267
|
statement: {
|
268
268
|
managedRuleGroupStatement: {
|
269
269
|
vendorName: "AWS",
|
270
|
-
name: "AWSManagedRulesSQLiRuleSet"
|
271
|
-
}
|
272
|
-
}
|
270
|
+
name: "AWSManagedRulesSQLiRuleSet",
|
271
|
+
},
|
272
|
+
},
|
273
273
|
});
|
274
274
|
}
|
275
275
|
function createRuleProperty(name, priority, rule, overrideAction = true) {
|
@@ -280,11 +280,11 @@ function createRuleProperty(name, priority, rule, overrideAction = true) {
|
|
280
280
|
visibilityConfig: {
|
281
281
|
sampledRequestsEnabled: true,
|
282
282
|
cloudWatchMetricsEnabled: true,
|
283
|
-
metricName: name
|
284
|
-
}
|
283
|
+
metricName: name,
|
284
|
+
},
|
285
285
|
},
|
286
286
|
...rule,
|
287
|
-
...(overrideAction ? { overrideAction: { none: {} } } : {})
|
287
|
+
...(overrideAction ? { overrideAction: { none: {} } } : {}),
|
288
288
|
};
|
289
289
|
}
|
290
290
|
//# sourceMappingURL=acl-builder.mjs.map
|
@@ -26,9 +26,7 @@ export class DigitrafficStaticIntegration extends MockIntegration {
|
|
26
26
|
["GET", "HEAD"].forEach((httpMethod) => {
|
27
27
|
resource.addMethod(httpMethod, this, {
|
28
28
|
apiKeyRequired,
|
29
|
-
methodResponses: [
|
30
|
-
DigitrafficStaticIntegration.createMethodResponse(headers),
|
31
|
-
],
|
29
|
+
methodResponses: [DigitrafficStaticIntegration.createMethodResponse(headers)],
|
32
30
|
});
|
33
31
|
});
|
34
32
|
}
|
@@ -42,7 +40,7 @@ export class DigitrafficStaticIntegration extends MockIntegration {
|
|
42
40
|
responseTemplates: {
|
43
41
|
[mediaType]: response,
|
44
42
|
},
|
45
|
-
responseParameters: params
|
43
|
+
responseParameters: params,
|
46
44
|
};
|
47
45
|
}
|
48
46
|
static createMethodResponse(headers) {
|
@@ -50,7 +48,7 @@ export class DigitrafficStaticIntegration extends MockIntegration {
|
|
50
48
|
const entries = Object.fromEntries(allowedHeaders.map((key) => [key, true]));
|
51
49
|
return {
|
52
50
|
statusCode: "200",
|
53
|
-
responseParameters: prefixKeys("method.response.header.", entries)
|
51
|
+
responseParameters: prefixKeys("method.response.header.", entries),
|
54
52
|
};
|
55
53
|
}
|
56
54
|
}
|
@@ -17,14 +17,14 @@ export class DigitrafficSecurityRule extends Rule {
|
|
17
17
|
detailType: ["Security Hub Findings - Imported"],
|
18
18
|
detail: {
|
19
19
|
findings: {
|
20
|
-
|
21
|
-
|
20
|
+
Compliance: {
|
21
|
+
Status: ["FAILED"],
|
22
22
|
},
|
23
|
-
|
24
|
-
|
23
|
+
Workflow: {
|
24
|
+
Status: ["NEW"],
|
25
25
|
},
|
26
|
-
|
27
|
-
|
26
|
+
Severity: {
|
27
|
+
Label: ["HIGH", "CRITICAL"],
|
28
28
|
},
|
29
29
|
},
|
30
30
|
},
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ApplicationLogLevel, Function, LoggingFormat, SystemLogLevel } from "aws-cdk-lib/aws-lambda";
|
1
|
+
import { ApplicationLogLevel, Function, LoggingFormat, SystemLogLevel, } from "aws-cdk-lib/aws-lambda";
|
2
2
|
import { Stack } from "aws-cdk-lib";
|
3
3
|
import { SnsAction } from "aws-cdk-lib/aws-cloudwatch-actions";
|
4
4
|
import { ComparisonOperator, Metric } from "aws-cdk-lib/aws-cloudwatch";
|
@@ -35,8 +35,7 @@ export class MonitoredFunction extends Function {
|
|
35
35
|
* @param props Monitored function properties
|
36
36
|
*/
|
37
37
|
static create(stack, id, functionProps, props) {
|
38
|
-
if (props === MonitoredFunction.DISABLE_ALARMS &&
|
39
|
-
stack.configuration.production) {
|
38
|
+
if (props === MonitoredFunction.DISABLE_ALARMS && stack.configuration.production) {
|
40
39
|
throw new Error(
|
41
40
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
42
41
|
`Function ${functionProps.functionName} has DISABLE_ALARMS. Remove before installing to production or define your own properties!`);
|
@@ -78,9 +77,10 @@ export class MonitoredFunction extends Function {
|
|
78
77
|
super(scope, id, {
|
79
78
|
...{
|
80
79
|
loggingFormat: LoggingFormat.JSON,
|
81
|
-
|
82
|
-
|
83
|
-
},
|
80
|
+
applicationLogLevelV2: ApplicationLogLevel.DEBUG,
|
81
|
+
systemLogLevelV2: SystemLogLevel.INFO,
|
82
|
+
},
|
83
|
+
...functionProps,
|
84
84
|
});
|
85
85
|
if (functionProps.functionName === undefined) {
|
86
86
|
throw new Error("Function name not provided");
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { CfnDocumentationPart, Cors, EndpointType, GatewayResponse, MethodLoggingLevel, Model, Resource, ResponseType, RestApi, } from "aws-cdk-lib/aws-apigateway";
|
2
|
-
import { AnyPrincipal, Effect, PolicyDocument, PolicyStatement
|
2
|
+
import { AnyPrincipal, Effect, PolicyDocument, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
3
3
|
import { Construct } from "constructs";
|
4
4
|
import { getModelReference } from "../../../utils/api-model.mjs";
|
5
5
|
import { MediaType } from "../../types/mediatypes.mjs";
|
@@ -28,8 +28,7 @@ export class DigitrafficRestApi extends RestApi {
|
|
28
28
|
};
|
29
29
|
super(stack, apiId, apiConfig);
|
30
30
|
this.apiKeyIds = [];
|
31
|
-
this.enableDocumentation =
|
32
|
-
stack.configuration.stackFeatures?.enableDocumentation ?? true;
|
31
|
+
this.enableDocumentation = stack.configuration.stackFeatures?.enableDocumentation ?? true;
|
33
32
|
add404Support(this, stack);
|
34
33
|
}
|
35
34
|
hostname() {
|
@@ -85,7 +84,7 @@ export class DigitrafficRestApi extends RestApi {
|
|
85
84
|
addResourceWithCorsOptionsSubTree(resource, pathPart, config) {
|
86
85
|
const mergedConfig = {
|
87
86
|
...PUBLIC_REST_API_CORS_CONFIG,
|
88
|
-
...config
|
87
|
+
...config,
|
89
88
|
};
|
90
89
|
return resource.addResource(pathPart, mergedConfig);
|
91
90
|
}
|
@@ -191,8 +190,15 @@ export function createIpRestrictionPolicyDocument(allowFromIpAddresses) {
|
|
191
190
|
export const PUBLIC_REST_API_CORS_CONFIG = {
|
192
191
|
defaultCorsPreflightOptions: {
|
193
192
|
allowOrigins: Cors.ALL_ORIGINS,
|
194
|
-
allowHeaders: [
|
195
|
-
|
196
|
-
|
193
|
+
allowHeaders: [
|
194
|
+
"Content-Type",
|
195
|
+
"X-Amz-Date",
|
196
|
+
"Authorization",
|
197
|
+
"X-Api-Key",
|
198
|
+
"X-Amz-Security-Token",
|
199
|
+
"Digitraffic-User",
|
200
|
+
],
|
201
|
+
allowMethods: ["OPTIONS", "GET", "HEAD"],
|
202
|
+
},
|
197
203
|
};
|
198
204
|
//# sourceMappingURL=rest_apis.mjs.map
|
@@ -140,7 +140,7 @@ export class StackCheckingAspect {
|
|
140
140
|
const type = split[2];
|
141
141
|
const name = split[3];
|
142
142
|
if (name === undefined) {
|
143
|
-
throw Error(
|
143
|
+
throw Error("Name should not be undefined");
|
144
144
|
}
|
145
145
|
if (type === "querystring" && !StackCheckingAspect.isValidQueryString(name)) {
|
146
146
|
this.addAnnotation(node, name, "Querystring should be in snake_case");
|
@@ -159,7 +159,7 @@ export class StackCheckingAspect {
|
|
159
159
|
checkLogGroupRetention(node) {
|
160
160
|
if (node instanceof LogRetention) {
|
161
161
|
const child = node.node.defaultChild;
|
162
|
-
const retention = child?.[
|
162
|
+
const retention = child?.["_cfnProperties"]?.["RetentionInDays"];
|
163
163
|
if (!retention) {
|
164
164
|
this.addAnnotation(node, ResourceType.logGroupRetention, "Log group must define log group retention");
|
165
165
|
}
|
@@ -39,7 +39,8 @@ export class DigitrafficStack extends Stack {
|
|
39
39
|
this.lambdaDbSg = SecurityGroup.fromSecurityGroupId(this, "LambdaDbSG", configuration.lambdaDbSgId);
|
40
40
|
}
|
41
41
|
this.alarmTopic = Topic.fromTopicArn(this, "AlarmTopic", StringParameter.fromStringParameterName(this, "AlarmTopicParam", SSM_KEY_ALARM_TOPIC).stringValue);
|
42
|
-
this.warningTopic = Topic.fromTopicArn(this, "WarningTopic", StringParameter.fromStringParameterName(this, "WarningTopicParam", SSM_KEY_WARNING_TOPIC)
|
42
|
+
this.warningTopic = Topic.fromTopicArn(this, "WarningTopic", StringParameter.fromStringParameterName(this, "WarningTopicParam", SSM_KEY_WARNING_TOPIC)
|
43
|
+
.stringValue);
|
43
44
|
this.addAspects();
|
44
45
|
}
|
45
46
|
addAspects() {
|
@@ -3,10 +3,12 @@
|
|
3
3
|
import { APIGateway } from "aws-sdk";
|
4
4
|
export async function getApiKeyFromAPIGateway(keyId) {
|
5
5
|
const ag = new APIGateway();
|
6
|
-
return ag
|
6
|
+
return ag
|
7
|
+
.getApiKey({
|
7
8
|
apiKey: keyId,
|
8
|
-
includeValue: true
|
9
|
-
})
|
9
|
+
includeValue: true,
|
10
|
+
})
|
11
|
+
.promise();
|
10
12
|
/*
|
11
13
|
const client = new APIGatewayClient();
|
12
14
|
const command = new GetApiKeyCommand({
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import { DatabaseEnvironmentKeys, initDbConnection
|
1
|
+
import { DatabaseEnvironmentKeys, initDbConnection } from "../database/database.mjs";
|
2
2
|
export async function assertCount(db, sql, count) {
|
3
3
|
await db.one(sql).then((x) => expect(x.count).toEqual(count));
|
4
4
|
}
|
5
5
|
export function dbTestBase(fn, truncateFn, dbUser, dbPass, dbUri) {
|
6
|
-
const theDbUri = process.env[
|
6
|
+
const theDbUri = process.env["DB_URI"] ?? dbUri;
|
7
7
|
console.log(`Test database URI: ${theDbUri}`);
|
8
8
|
return () => {
|
9
9
|
const db = initDbConnection(dbUser, dbPass, "test", theDbUri, {
|
@@ -17,9 +17,12 @@ export declare function createFeatureCollection(features: Feature[], lastUpdated
|
|
17
17
|
export declare function isValidGeoJson<T>(json: T): boolean;
|
18
18
|
export declare function isFeatureCollection<T>(json: T): boolean;
|
19
19
|
/**
|
20
|
-
*
|
21
|
-
*
|
22
|
-
*
|
20
|
+
* Returns the distance between two WGS84 GeoJSON positions in kilometers. Doesn't take in account altitude.
|
21
|
+
* Based on the following Stack Overflow question:
|
22
|
+
* http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
|
23
|
+
* which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
|
24
|
+
* @param pos1 first position
|
25
|
+
* @param pos2 second position
|
23
26
|
*/
|
24
27
|
export declare function distanceBetweenPositionsInKm(pos1: Position, pos2: Position): number;
|
25
28
|
export declare function areDistinctPositions(previous: Position, next: Position): boolean;
|
package/dist/utils/geometry.mjs
CHANGED
@@ -65,10 +65,14 @@ export function isFeatureCollection(json) {
|
|
65
65
|
const DEGREES_TO_RADIANS = 0.017453292519943295; // = Math.PI / 180
|
66
66
|
const EARTH_RADIUS_KM = 6371;
|
67
67
|
/**
|
68
|
-
* Returns the distance between
|
68
|
+
* Returns the distance between two WGS84 points in kilometers. Doesn't take in account altitude.
|
69
69
|
* Based on the following Stack Overflow question:
|
70
70
|
* http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
|
71
71
|
* which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
|
72
|
+
* @param fromXLon first point longitude
|
73
|
+
* @param fromYLat first point latitude
|
74
|
+
* @param toXLon second point longitude
|
75
|
+
* @param toYLat second point latitude
|
72
76
|
*/
|
73
77
|
function distanceBetweenWGS84PointsInKm(fromXLon, fromYLat, toXLon, toYLat) {
|
74
78
|
const diffLat = toRadians(toYLat - fromYLat);
|
@@ -82,9 +86,12 @@ function distanceBetweenWGS84PointsInKm(fromXLon, fromYLat, toXLon, toYLat) {
|
|
82
86
|
return EARTH_RADIUS_KM * c;
|
83
87
|
}
|
84
88
|
/**
|
85
|
-
*
|
86
|
-
*
|
87
|
-
*
|
89
|
+
* Returns the distance between two WGS84 GeoJSON positions in kilometers. Doesn't take in account altitude.
|
90
|
+
* Based on the following Stack Overflow question:
|
91
|
+
* http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
|
92
|
+
* which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
|
93
|
+
* @param pos1 first position
|
94
|
+
* @param pos2 second position
|
88
95
|
*/
|
89
96
|
export function distanceBetweenPositionsInKm(pos1, pos2) {
|
90
97
|
if (pos1.length < 2 || pos1.length > 3 || pos2.length < 2 || pos2.length > 3) {
|
package/dist/utils/slack.mjs
CHANGED
package/dist/utils/utils.d.mts
CHANGED
@@ -89,3 +89,8 @@ export declare function hasOwnPropertySafe(object: object, propertyName: string)
|
|
89
89
|
* @param maybeError
|
90
90
|
*/
|
91
91
|
export declare function getErrorMessage(maybeError: unknown): string;
|
92
|
+
/**
|
93
|
+
*
|
94
|
+
* @param value
|
95
|
+
*/
|
96
|
+
export declare function isDefined<T>(value: T | undefined | null): value is T;
|
package/dist/utils/utils.mjs
CHANGED
@@ -153,4 +153,11 @@ export function getErrorMessage(maybeError) {
|
|
153
153
|
}
|
154
154
|
return String(maybeError);
|
155
155
|
}
|
156
|
+
/**
|
157
|
+
*
|
158
|
+
* @param value
|
159
|
+
*/
|
160
|
+
export function isDefined(value) {
|
161
|
+
return value !== undefined && value !== null;
|
162
|
+
}
|
156
163
|
//# sourceMappingURL=utils.mjs.map
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@digitraffic/common",
|
3
|
-
"version": "2024.
|
3
|
+
"version": "2024.7.2-1",
|
4
4
|
"description": "",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -138,7 +138,6 @@
|
|
138
138
|
"ky": "^1.3.0",
|
139
139
|
"lodash": "^4.17.21",
|
140
140
|
"node-ttl": "^0.2.0",
|
141
|
-
"pg-native": "^3.1.0",
|
142
141
|
"pg-promise": "^11.8.0",
|
143
142
|
"@jest/globals": "^29.7.0",
|
144
143
|
"@rushstack/eslint-config": "^3.7.0",
|