@digitraffic/common 2026.2.4-4 → 2026.2.5-2
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__/imports.test.js +6 -2
- package/dist/__test__/infra/api/integration.test.js +1 -1
- package/dist/__test__/infra/api/response.test.js +21 -7
- package/dist/__test__/stack/dt-function.test.js +6 -30
- package/dist/__test__/types/lambda-response.test.d.ts +7 -8
- package/dist/__test__/types/lambda-response.test.js +65 -15
- package/dist/__test__/utils/base64.test.js +1 -11
- package/dist/__test__/utils/logging.test.js +1 -13
- package/dist/aws/infra/api/response.d.ts +1 -1
- package/dist/aws/infra/api/response.js +22 -18
- package/dist/aws/infra/canaries/canary.js +1 -1
- package/dist/aws/infra/canaries/url-checker.js +4 -11
- package/dist/aws/infra/sqs-queue.js +1 -1
- package/dist/aws/infra/stack/dt-function.d.ts +2 -5
- package/dist/aws/infra/stack/dt-function.js +4 -17
- package/dist/aws/infra/stack/lambda-configs.d.ts +0 -6
- package/dist/aws/infra/stack/lambda-configs.js +2 -8
- package/dist/aws/infra/stack/rest-api.js +1 -1
- package/dist/aws/infra/stack/stack-checking-aspect.d.ts +0 -1
- package/dist/aws/infra/stack/stack-checking-aspect.js +3 -7
- package/dist/aws/types/lambda-response.d.ts +19 -22
- package/dist/aws/types/lambda-response.js +73 -65
- package/dist/aws/types/proxytypes.d.ts +26 -0
- package/dist/aws/types/proxytypes.js +2 -0
- package/dist/database/cached.d.ts +19 -0
- package/dist/database/cached.js +40 -0
- package/dist/utils/base64.d.ts +3 -5
- package/dist/utils/base64.js +4 -12
- package/dist/utils/logging.d.ts +0 -12
- package/dist/utils/logging.js +0 -33
- package/package.json +34 -33
- package/dist/__test__/types/lambda-proxy-types.test.d.ts +0 -8
- package/dist/__test__/types/lambda-proxy-types.test.js +0 -154
- package/dist/__test__/types/lambda-response-builder.test.d.ts +0 -1
- package/dist/__test__/types/lambda-response-builder.test.js +0 -80
- package/dist/__test__/utils/lambda-proxy-event.test.d.ts +0 -1
- package/dist/__test__/utils/lambda-proxy-event.test.js +0 -44
- package/dist/aws/types/lambda-proxy-types.d.ts +0 -59
- package/dist/aws/types/lambda-proxy-types.js +0 -210
- package/dist/utils/lambda-proxy-event.d.ts +0 -9
- package/dist/utils/lambda-proxy-event.js +0 -31
- package/dist/utils/zod-utils.d.ts +0 -14
- package/dist/utils/zod-utils.js +0 -29
|
@@ -7,6 +7,10 @@ test("database import ok?", () => {
|
|
|
7
7
|
const database = import("../database/database.js");
|
|
8
8
|
return expect(database).resolves.toBeDefined();
|
|
9
9
|
});
|
|
10
|
+
test("cached import ok?", () => {
|
|
11
|
+
const cached = import("../database/cached.js");
|
|
12
|
+
return expect(cached).resolves.toBeDefined();
|
|
13
|
+
});
|
|
10
14
|
test("models import ok?", () => {
|
|
11
15
|
const models = import("../database/models.js");
|
|
12
16
|
return expect(models).resolves.toBeDefined();
|
|
@@ -239,8 +243,8 @@ test("canaryKeys import ok?", () => {
|
|
|
239
243
|
const canaryKeys = import("../aws/infra/canaries/canary-keys.js");
|
|
240
244
|
return expect(canaryKeys).resolves.toBeDefined();
|
|
241
245
|
});
|
|
242
|
-
test("
|
|
243
|
-
const proxytypes = import("../aws/types/
|
|
246
|
+
test("proxytypes import ok?", () => {
|
|
247
|
+
const proxytypes = import("../aws/types/proxytypes.js");
|
|
244
248
|
return expect(proxytypes).resolves.toBeDefined();
|
|
245
249
|
});
|
|
246
250
|
test("tags import ok?", () => {
|
|
@@ -58,7 +58,7 @@ describe("integration tests", () => {
|
|
|
58
58
|
const app = new App();
|
|
59
59
|
const stack = new Stack(app);
|
|
60
60
|
const f = new LambdaFunction(stack, "id", {
|
|
61
|
-
runtime: Runtime.
|
|
61
|
+
runtime: Runtime.NODEJS_22_X,
|
|
62
62
|
code: Code.fromInline("placeholder"),
|
|
63
63
|
handler: "handler",
|
|
64
64
|
});
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import etag from "etag";
|
|
2
2
|
import velocity from "velocityjs";
|
|
3
3
|
import { RESPONSE_DEFAULT_LAMBDA } from "../../../aws/infra/api/response.js";
|
|
4
|
+
import { compressBuffer, decodeBase64ToString, } from "../../../aws/types/lambda-response.js";
|
|
5
|
+
import { TEST_BIG_JSON } from "../../types/lambda-response.test.js";
|
|
4
6
|
const TEST_BODY = "Hello world!";
|
|
5
7
|
describe("response tests", () => {
|
|
6
8
|
function generateEtagValueFromString(body) {
|
|
@@ -9,20 +11,24 @@ describe("response tests", () => {
|
|
|
9
11
|
function generateEtagValueFromBase64String(bodyBase64) {
|
|
10
12
|
return etag(bodyBase64);
|
|
11
13
|
}
|
|
12
|
-
function generateResponse(status, fileName, timestamp) {
|
|
14
|
+
function generateResponse(status, fileName, timestamp, compressBody = false, body = TEST_BODY) {
|
|
13
15
|
const compile = new velocity.Compile(velocity.parse(RESPONSE_DEFAULT_LAMBDA));
|
|
16
|
+
const rawBuffer = Buffer.from(body, "utf8");
|
|
14
17
|
const output = compile.render({
|
|
15
18
|
input: {
|
|
16
19
|
path: () => ({
|
|
17
|
-
body:
|
|
20
|
+
body: (compressBody
|
|
21
|
+
? compressBuffer(rawBuffer)
|
|
22
|
+
: rawBuffer).toString("base64"),
|
|
18
23
|
status,
|
|
19
24
|
fileName,
|
|
20
25
|
timestamp: timestamp?.toUTCString(),
|
|
21
|
-
etag: generateEtagValueFromString(
|
|
26
|
+
etag: generateEtagValueFromString(body),
|
|
27
|
+
compressed: compressBody,
|
|
22
28
|
}),
|
|
23
29
|
},
|
|
24
30
|
util: {
|
|
25
|
-
base64Decode: (data) =>
|
|
31
|
+
base64Decode: (data) => decodeBase64ToString(data, compressBody),
|
|
26
32
|
},
|
|
27
33
|
context: {
|
|
28
34
|
responseOverride: {
|
|
@@ -33,6 +39,7 @@ describe("response tests", () => {
|
|
|
33
39
|
ETag: undefined,
|
|
34
40
|
"Last-Modified": undefined,
|
|
35
41
|
"Content-Disposition": undefined,
|
|
42
|
+
"Content-Encoding": undefined,
|
|
36
43
|
},
|
|
37
44
|
},
|
|
38
45
|
},
|
|
@@ -40,8 +47,8 @@ describe("response tests", () => {
|
|
|
40
47
|
// @ts-expect-error: context is not in the type definition
|
|
41
48
|
return [output, compile.context.context];
|
|
42
49
|
}
|
|
43
|
-
function assertOutputAndContext(output, context, status, contentType, fileName, timestamp) {
|
|
44
|
-
expect(output).toEqual(
|
|
50
|
+
function assertOutputAndContext(output, context, status, contentType, fileName, timestamp, body = TEST_BODY, compressBody = false) {
|
|
51
|
+
expect(output).toEqual(body);
|
|
45
52
|
expect(context).toMatchObject({
|
|
46
53
|
responseOverride: {
|
|
47
54
|
status,
|
|
@@ -50,7 +57,8 @@ describe("response tests", () => {
|
|
|
50
57
|
"Access-Control-Allow-Origin": "*",
|
|
51
58
|
"Content-Disposition": fileName,
|
|
52
59
|
"Last-Modified": timestamp?.toUTCString(),
|
|
53
|
-
ETag: generateEtagValueFromString(
|
|
60
|
+
ETag: generateEtagValueFromString(body),
|
|
61
|
+
"Content-Encoding": compressBody ? "gzip" : undefined,
|
|
54
62
|
},
|
|
55
63
|
},
|
|
56
64
|
});
|
|
@@ -72,5 +80,11 @@ describe("response tests", () => {
|
|
|
72
80
|
const [output, context] = generateResponse(204);
|
|
73
81
|
assertOutputAndContext(output, context, 204, "text/plain");
|
|
74
82
|
});
|
|
83
|
+
test("test 200 - compressed", () => {
|
|
84
|
+
const now = new Date();
|
|
85
|
+
const body = JSON.stringify(TEST_BIG_JSON);
|
|
86
|
+
const [output, context] = generateResponse(200, "test.json", now, true, body);
|
|
87
|
+
assertOutputAndContext(output, context, undefined, undefined, 'attachment; filename="test.json"', now, body, true);
|
|
88
|
+
});
|
|
75
89
|
});
|
|
76
90
|
//# sourceMappingURL=response.test.js.map
|
|
@@ -8,10 +8,8 @@ import { EnvKeys } from "../../aws/runtime/environment.js";
|
|
|
8
8
|
import { TrafficType } from "../../types/traffictype.js";
|
|
9
9
|
const TEST_ENV_VAR = "TEST_ENV_VAR";
|
|
10
10
|
const TEST_ENV_VALUE = "testValue";
|
|
11
|
-
// AWS::Lambda::Function Template Reference
|
|
12
|
-
// https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html
|
|
13
11
|
describe("FunctionBuilder test", () => {
|
|
14
|
-
function createTemplate(tester, plain = false
|
|
12
|
+
function createTemplate(tester, plain = false) {
|
|
15
13
|
const app = new App();
|
|
16
14
|
const stack = new DigitrafficStack(app, "test-stack", {
|
|
17
15
|
alarmTopicArn: "",
|
|
@@ -26,10 +24,10 @@ describe("FunctionBuilder test", () => {
|
|
|
26
24
|
[TEST_ENV_VAR]: TEST_ENV_VALUE,
|
|
27
25
|
};
|
|
28
26
|
const builder = plain
|
|
29
|
-
? FunctionBuilder.plain(stack,
|
|
27
|
+
? FunctionBuilder.plain(stack, "test")
|
|
30
28
|
.withEnvironment(environment)
|
|
31
29
|
.withCode(Code.fromInline("{}"))
|
|
32
|
-
: FunctionBuilder.create(stack,
|
|
30
|
+
: FunctionBuilder.create(stack, "test")
|
|
33
31
|
.withoutDatabaseAccess()
|
|
34
32
|
.withEnvironment(environment)
|
|
35
33
|
.withCode(Code.fromInline("{}"));
|
|
@@ -64,7 +62,7 @@ describe("FunctionBuilder test", () => {
|
|
|
64
62
|
[TEST_ENV_VAR]: TEST_ENV_VALUE,
|
|
65
63
|
},
|
|
66
64
|
},
|
|
67
|
-
Runtime: Runtime.
|
|
65
|
+
Runtime: Runtime.NODEJS_22_X.name,
|
|
68
66
|
MemorySize: 128,
|
|
69
67
|
Timeout: 60,
|
|
70
68
|
Handler: "test.handler",
|
|
@@ -83,18 +81,10 @@ describe("FunctionBuilder test", () => {
|
|
|
83
81
|
});
|
|
84
82
|
test("Lambda runtime is set", () => {
|
|
85
83
|
const template = createTemplate((builder) => {
|
|
86
|
-
builder.withRuntime(Runtime.
|
|
84
|
+
builder.withRuntime(Runtime.NODEJS_20_X);
|
|
87
85
|
});
|
|
88
86
|
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
89
|
-
Runtime: Runtime.
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
test("Lambda description is set", () => {
|
|
93
|
-
const template = createTemplate((builder) => {
|
|
94
|
-
builder.withDescription("Does something useful");
|
|
95
|
-
});
|
|
96
|
-
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
97
|
-
Description: "Does something useful",
|
|
87
|
+
Runtime: Runtime.NODEJS_20_X.name,
|
|
98
88
|
});
|
|
99
89
|
});
|
|
100
90
|
test("Lambda memory size is set", () => {
|
|
@@ -137,20 +127,6 @@ describe("FunctionBuilder test", () => {
|
|
|
137
127
|
Handler: "custom.main",
|
|
138
128
|
});
|
|
139
129
|
});
|
|
140
|
-
test("Lambda handler module is resolved from path last element", () => {
|
|
141
|
-
const template = createTemplate((_builder) => { }, false, "api/charging-network/v1/operators");
|
|
142
|
-
// const lambdas = template.findResources("AWS::Lambda::Function");
|
|
143
|
-
// console.debug(JSON.stringify(lambdas, null, 2));
|
|
144
|
-
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
145
|
-
Handler: "operators.handler",
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
test("Lambda handler module is same as lambda name", () => {
|
|
149
|
-
const template = createTemplate((_builder) => { }, false, "operators");
|
|
150
|
-
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
151
|
-
Handler: "operators.handler",
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
130
|
test("withRolePolicies adds custom policy to lambda role", () => {
|
|
155
131
|
const template = createTemplate((builder) => {
|
|
156
132
|
builder.withRolePolicies(new PolicyStatement({
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
count: number;
|
|
1
|
+
export declare const TEST_BIG_JSON: {
|
|
2
|
+
items: {
|
|
3
|
+
id: number;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
value: number;
|
|
7
|
+
}[];
|
|
9
8
|
};
|
|
@@ -1,24 +1,32 @@
|
|
|
1
|
-
import { LambdaResponse, LambdaResponseBuilder, } from "../../aws/types/lambda-response.js";
|
|
2
|
-
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
count: TEST_COUNT,
|
|
1
|
+
import { decodeBase64ToString, LambdaResponse, LambdaResponseBuilder, } from "../../aws/types/lambda-response.js";
|
|
2
|
+
// About 18 MB will be compressed to 2 MB
|
|
3
|
+
export const TEST_BIG_JSON = {
|
|
4
|
+
items: Array.from({ length: 10 }, (_, i) => ({
|
|
5
|
+
id: i,
|
|
6
|
+
name: `Item ${i}`,
|
|
7
|
+
description: "This is a test description that repeats to allow compression",
|
|
8
|
+
value: Math.random(),
|
|
9
|
+
})),
|
|
11
10
|
};
|
|
12
11
|
describe("lambda-response", () => {
|
|
12
|
+
const TEST_MESSAGE = "HELLO";
|
|
13
|
+
const TEST_COUNT = 12;
|
|
14
|
+
const TEST_FILENAME = "file.txt";
|
|
15
|
+
const TEST_TIMESTAMP = new Date();
|
|
16
|
+
const TEST_TIMESTAMP_STR = TEST_TIMESTAMP.toISOString();
|
|
17
|
+
const TEST_JSON = {
|
|
18
|
+
message: TEST_MESSAGE,
|
|
19
|
+
count: TEST_COUNT,
|
|
20
|
+
};
|
|
13
21
|
function assertJson(response, expectedJson, expectedStatus, expectedFilename, expectedTimestamp) {
|
|
14
|
-
const body = JSON.parse(
|
|
22
|
+
const body = JSON.parse(decodeBase64ToString(response.body, response.compressed));
|
|
15
23
|
expect(body).toEqual(expectedJson);
|
|
16
24
|
expect(response.status).toEqual(expectedStatus);
|
|
17
25
|
expect(response.fileName).toEqual(expectedFilename);
|
|
18
26
|
expect(response.timestamp).toEqual(expectedTimestamp?.toUTCString());
|
|
19
27
|
}
|
|
20
28
|
function assertBinary(response, expectedString, expectedStatus, expectedFilename, expectedTimestamp) {
|
|
21
|
-
const body =
|
|
29
|
+
const body = decodeBase64ToString(response.body, response.compressed);
|
|
22
30
|
expect(body).toEqual(expectedString);
|
|
23
31
|
expect(response.status).toEqual(expectedStatus);
|
|
24
32
|
expect(response.fileName).toEqual(expectedFilename);
|
|
@@ -46,15 +54,15 @@ describe("lambda-response", () => {
|
|
|
46
54
|
});
|
|
47
55
|
test("notFound", () => {
|
|
48
56
|
const response = LambdaResponse.notFound();
|
|
49
|
-
assertBinary(response, "Not
|
|
57
|
+
assertBinary(response, "Not found", 404);
|
|
50
58
|
});
|
|
51
59
|
test("internalError", () => {
|
|
52
60
|
const response = LambdaResponse.internalError();
|
|
53
|
-
assertBinary(response, "Internal
|
|
61
|
+
assertBinary(response, "Internal error", 500);
|
|
54
62
|
});
|
|
55
63
|
test("notImplemented", () => {
|
|
56
64
|
const response = LambdaResponse.notImplemented();
|
|
57
|
-
assertBinary(response, "Not
|
|
65
|
+
assertBinary(response, "Not implemented", 501);
|
|
58
66
|
});
|
|
59
67
|
// Builder
|
|
60
68
|
test("Builder - okJson - without fileName", () => {
|
|
@@ -68,5 +76,47 @@ describe("lambda-response", () => {
|
|
|
68
76
|
.build();
|
|
69
77
|
assertJson(response, TEST_JSON, 200, TEST_FILENAME);
|
|
70
78
|
});
|
|
79
|
+
test("Builder - okJson - with fileName and timestamp", () => {
|
|
80
|
+
const response = LambdaResponseBuilder.create()
|
|
81
|
+
.withBody(TEST_JSON)
|
|
82
|
+
.withFileName(TEST_FILENAME)
|
|
83
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
84
|
+
.build();
|
|
85
|
+
const response2 = LambdaResponseBuilder.create()
|
|
86
|
+
.withBody(TEST_JSON)
|
|
87
|
+
.withFileName(TEST_FILENAME)
|
|
88
|
+
.withTimestamp(TEST_TIMESTAMP_STR)
|
|
89
|
+
.build();
|
|
90
|
+
assertJson(response, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
91
|
+
assertJson(response2, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
92
|
+
});
|
|
93
|
+
test("Builder - okBinary - with fileName and timestamp", () => {
|
|
94
|
+
const response = LambdaResponseBuilder.create()
|
|
95
|
+
.withBody(TEST_MESSAGE)
|
|
96
|
+
.withFileName(TEST_FILENAME)
|
|
97
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
98
|
+
.build();
|
|
99
|
+
assertBinary(response, TEST_MESSAGE, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
100
|
+
});
|
|
101
|
+
test("Builder - compression uneffective for small json", () => {
|
|
102
|
+
const response = LambdaResponseBuilder.create()
|
|
103
|
+
.withBody(TEST_JSON)
|
|
104
|
+
.withFileName(TEST_FILENAME)
|
|
105
|
+
.withCompression()
|
|
106
|
+
.withDebug()
|
|
107
|
+
.build();
|
|
108
|
+
expect(response.compressed).toBe(false);
|
|
109
|
+
assertJson(response, TEST_JSON, 200, TEST_FILENAME);
|
|
110
|
+
});
|
|
111
|
+
test("Builder - compression effective for large json", () => {
|
|
112
|
+
const response = LambdaResponseBuilder.create()
|
|
113
|
+
.withBody(TEST_BIG_JSON)
|
|
114
|
+
.withFileName(TEST_FILENAME)
|
|
115
|
+
.withCompression()
|
|
116
|
+
.withDebug()
|
|
117
|
+
.build();
|
|
118
|
+
expect(response.compressed).toBe(true);
|
|
119
|
+
assertJson(response, TEST_BIG_JSON, 200, TEST_FILENAME);
|
|
120
|
+
});
|
|
71
121
|
});
|
|
72
122
|
//# sourceMappingURL=lambda-response.test.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { decodeBase64ToAscii, decodeBase64ToUtf8, encodeAsciiToBase64, encodeUtf8ToBase64, } from "../../utils/base64.js";
|
|
2
2
|
describe("Base64UtilTest", () => {
|
|
3
3
|
const EXPECTED_ASCII = "0a9f4967-faaa-445a-ba11-078f7f9556b4";
|
|
4
4
|
const EXPECTED_ASCII_BASE64 = "MGE5ZjQ5NjctZmFhYS00NDVhLWJhMTEtMDc4ZjdmOTU1NmI0";
|
|
@@ -23,15 +23,5 @@ describe("Base64UtilTest", () => {
|
|
|
23
23
|
expect(encodedUtf8).toEqual(EXPECTED_UTF8_BASE64);
|
|
24
24
|
expect(decodedUtf8).toEqual(EXPECTED_UTF8);
|
|
25
25
|
});
|
|
26
|
-
test("decode utf8 compressed", () => {
|
|
27
|
-
const originalBody = { message: EXPECTED_UTF8 };
|
|
28
|
-
const body = JSON.stringify(originalBody);
|
|
29
|
-
const rawBuffer = Buffer.from(body, "utf8");
|
|
30
|
-
const compressed = compressBuffer(rawBuffer);
|
|
31
|
-
const compressedBase64 = compressed.toString("base64");
|
|
32
|
-
const uncompressedBody = decodeBase64ToUtf8(compressedBase64, true);
|
|
33
|
-
const restoredBody = JSON.parse(uncompressedBody);
|
|
34
|
-
expect(originalBody).toEqual(restoredBody);
|
|
35
|
-
});
|
|
36
26
|
});
|
|
37
27
|
//# sourceMappingURL=base64.test.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Writable } from "node:stream";
|
|
2
2
|
import { DtLogger } from "../../aws/runtime/dt-logger.js";
|
|
3
|
-
import { logException
|
|
3
|
+
import { logException } from "../../utils/logging.js";
|
|
4
4
|
const TEST_METHODNAME = "test.logException";
|
|
5
5
|
describe("logging-test", () => {
|
|
6
6
|
function assertLogError(error, expected, includeStack = false) {
|
|
@@ -58,17 +58,5 @@ describe("logging-test", () => {
|
|
|
58
58
|
stack: true,
|
|
59
59
|
}, true);
|
|
60
60
|
});
|
|
61
|
-
test("truncateEnd - not truncated as would be longer", () => {
|
|
62
|
-
expect(truncateEnd("This is a test string", 10)).toBe("This is a test string");
|
|
63
|
-
});
|
|
64
|
-
test("truncateEnd", () => {
|
|
65
|
-
expect(truncateEnd("This is a test string that is long enough", 10)).toBe("This is a [TRUNCATED 31 CHARS]");
|
|
66
|
-
});
|
|
67
|
-
test("truncateMiddle - not truncated as would be longer", () => {
|
|
68
|
-
expect(truncateMiddle("This is a test string", 10)).toBe("This is a test string");
|
|
69
|
-
});
|
|
70
|
-
test("truncateMiddle", () => {
|
|
71
|
-
expect(truncateMiddle("This is a test string that is long enough", 20)).toBe("This is a [TRUNCATED 21 CHARS] ong enough");
|
|
72
|
-
});
|
|
73
61
|
});
|
|
74
62
|
//# sourceMappingURL=logging.test.js.map
|
|
@@ -11,7 +11,7 @@ import { MediaType } from "../../types/mediatypes.js";
|
|
|
11
11
|
* If fileName is set, then Content-Disposition-header will be set to use it
|
|
12
12
|
* If timestamp is set, then ETag & Last-Modified headers will be set
|
|
13
13
|
*/
|
|
14
|
-
export declare const RESPONSE_DEFAULT_LAMBDA = "#set($inputRoot = $input.path('$'))
|
|
14
|
+
export declare const RESPONSE_DEFAULT_LAMBDA = "#set($inputRoot = $input.path('$'))\n#if ($inputRoot.status != 200)\n#set ($context.responseOverride.status = $inputRoot.status)\n#set ($context.responseOverride.header.Content-Type = 'text/plain')\n#end\n#set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')\n#if (\"$!inputRoot.timestamp\" != \"\")\n#set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)\n#end\n#if (\"$!inputRoot.etag\" != \"\")\n#set ($context.responseOverride.header.ETag = $inputRoot.etag)\n#end\n#if (\"$!inputRoot.fileName\" != \"\")\n#set ($disposition = 'attachment; filename=\"FN\"')\n#set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))\n#end\n#* Conditionally add Content-Encoding if compressed is true *#\n#if($!inputRoot.compressed == true)\n#set($context.responseOverride.header.Content-Encoding = \"gzip\")\n#end\n$util.base64Decode($inputRoot.body)";
|
|
15
15
|
/**
|
|
16
16
|
* Use this for deprecated integrations.
|
|
17
17
|
* Will add HTTP headers Deprecation and Sunset to response.
|
|
@@ -12,22 +12,26 @@ import { MediaType } from "../../types/mediatypes.js";
|
|
|
12
12
|
* If fileName is set, then Content-Disposition-header will be set to use it
|
|
13
13
|
* If timestamp is set, then ETag & Last-Modified headers will be set
|
|
14
14
|
*/
|
|
15
|
-
export const RESPONSE_DEFAULT_LAMBDA = `#set($inputRoot = $input.path('$'))
|
|
16
|
-
#if ($inputRoot.status != 200)
|
|
17
|
-
#set ($context.responseOverride.status = $inputRoot.status)
|
|
18
|
-
#set ($context.responseOverride.header.Content-Type = 'text/plain')
|
|
19
|
-
#end
|
|
20
|
-
#set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')
|
|
21
|
-
#if ("$!inputRoot.timestamp" != "")
|
|
22
|
-
#set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)
|
|
23
|
-
#end
|
|
24
|
-
#if ("$!inputRoot.etag" != "")
|
|
25
|
-
#set ($context.responseOverride.header.ETag = $inputRoot.etag)
|
|
26
|
-
#end
|
|
27
|
-
#if ("$!inputRoot.fileName" != "")
|
|
28
|
-
#set ($disposition = 'attachment; filename="FN"')
|
|
29
|
-
#set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))
|
|
30
|
-
#end
|
|
15
|
+
export const RESPONSE_DEFAULT_LAMBDA = `#set($inputRoot = $input.path('$'))
|
|
16
|
+
#if ($inputRoot.status != 200)
|
|
17
|
+
#set ($context.responseOverride.status = $inputRoot.status)
|
|
18
|
+
#set ($context.responseOverride.header.Content-Type = 'text/plain')
|
|
19
|
+
#end
|
|
20
|
+
#set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')
|
|
21
|
+
#if ("$!inputRoot.timestamp" != "")
|
|
22
|
+
#set ($context.responseOverride.header.Last-Modified = $inputRoot.timestamp)
|
|
23
|
+
#end
|
|
24
|
+
#if ("$!inputRoot.etag" != "")
|
|
25
|
+
#set ($context.responseOverride.header.ETag = $inputRoot.etag)
|
|
26
|
+
#end
|
|
27
|
+
#if ("$!inputRoot.fileName" != "")
|
|
28
|
+
#set ($disposition = 'attachment; filename="FN"')
|
|
29
|
+
#set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))
|
|
30
|
+
#end
|
|
31
|
+
#* Conditionally add Content-Encoding if compressed is true *#
|
|
32
|
+
#if($!inputRoot.compressed == true)
|
|
33
|
+
#set($context.responseOverride.header.Content-Encoding = "gzip")
|
|
34
|
+
#end
|
|
31
35
|
$util.base64Decode($inputRoot.body)`;
|
|
32
36
|
/**
|
|
33
37
|
* Use this for deprecated integrations.
|
|
@@ -67,13 +71,13 @@ export const MessageModel = {
|
|
|
67
71
|
modelName: "MessageResponseModel",
|
|
68
72
|
schema: messageSchema,
|
|
69
73
|
};
|
|
70
|
-
const NotFoundMessage = "Not
|
|
74
|
+
const NotFoundMessage = "Not found";
|
|
71
75
|
export const NotFoundResponse = JSON.stringify({ message: NotFoundMessage });
|
|
72
76
|
const InternalServerErrorMessage = "Error";
|
|
73
77
|
const InternalServerErrorResponse = JSON.stringify({
|
|
74
78
|
message: InternalServerErrorMessage,
|
|
75
79
|
});
|
|
76
|
-
const BadRequestMessage = "Bad
|
|
80
|
+
const BadRequestMessage = "Bad request";
|
|
77
81
|
const BadRequestResponse = JSON.stringify({ message: BadRequestMessage });
|
|
78
82
|
/**
|
|
79
83
|
* @deprecated
|
|
@@ -4,7 +4,7 @@ import { CanaryAlarm } from "./canary-alarm.js";
|
|
|
4
4
|
export class DigitrafficCanary extends Canary {
|
|
5
5
|
constructor(scope, canaryName, role, params, environmentVariables) {
|
|
6
6
|
super(scope, canaryName, {
|
|
7
|
-
runtime: params.runtime ?? Runtime.
|
|
7
|
+
runtime: params.runtime ?? Runtime.SYNTHETICS_NODEJS_PUPPETEER_9_0,
|
|
8
8
|
role,
|
|
9
9
|
test: Test.custom({
|
|
10
10
|
code: new AssetCode("dist", {
|
|
@@ -14,12 +14,6 @@ const baseHeaders = {
|
|
|
14
14
|
"Accept-Encoding": "gzip",
|
|
15
15
|
Accept: "*/*",
|
|
16
16
|
};
|
|
17
|
-
function sanitizeStepName(url) {
|
|
18
|
-
return url
|
|
19
|
-
.replace(/\//g, " ")
|
|
20
|
-
.replace(/[?&=]/g, " ")
|
|
21
|
-
.replace(/auth=.*/, "");
|
|
22
|
-
}
|
|
23
17
|
export class UrlChecker {
|
|
24
18
|
requestOptions;
|
|
25
19
|
constructor(hostname, apiKey) {
|
|
@@ -56,8 +50,7 @@ export class UrlChecker {
|
|
|
56
50
|
path: url,
|
|
57
51
|
},
|
|
58
52
|
};
|
|
59
|
-
|
|
60
|
-
await synthetics.executeHttpStep(`Verify ${statusCode} for ${sanitizeStepName(url)}`, requestOptions, callback);
|
|
53
|
+
await synthetics.executeHttpStep(`Verify ${statusCode} for ${url.replace(/auth=.*/, "")}`, requestOptions, callback);
|
|
61
54
|
}
|
|
62
55
|
expect200(url, ...callbacks) {
|
|
63
56
|
const callback = async (json, body, res) => {
|
|
@@ -72,7 +65,7 @@ export class UrlChecker {
|
|
|
72
65
|
path: url,
|
|
73
66
|
},
|
|
74
67
|
};
|
|
75
|
-
return synthetics.executeHttpStep(`Verify 404 for ${
|
|
68
|
+
return synthetics.executeHttpStep(`Verify 404 for ${url}`, requestOptions, validateStatusCodeAndContentType(404, MediaType.TEXT_PLAIN));
|
|
76
69
|
}
|
|
77
70
|
expect400(url) {
|
|
78
71
|
const requestOptions = {
|
|
@@ -81,7 +74,7 @@ export class UrlChecker {
|
|
|
81
74
|
path: url,
|
|
82
75
|
},
|
|
83
76
|
};
|
|
84
|
-
return synthetics.executeHttpStep(`Verify 400 for ${
|
|
77
|
+
return synthetics.executeHttpStep(`Verify 400 for ${url}`, requestOptions, validateStatusCodeAndContentType(400, MediaType.TEXT_PLAIN));
|
|
85
78
|
}
|
|
86
79
|
expect403WithoutApiKey(url, mediaType) {
|
|
87
80
|
if (!this.requestOptions.headers ||
|
|
@@ -99,7 +92,7 @@ export class UrlChecker {
|
|
|
99
92
|
headers: baseHeaders,
|
|
100
93
|
},
|
|
101
94
|
};
|
|
102
|
-
return synthetics.executeHttpStep(`Verify 403 for ${
|
|
95
|
+
return synthetics.executeHttpStep(`Verify 403 for ${url}`, requestOptions, validateStatusCodeAndContentType(403, mediaType ?? MediaType.APPLICATION_JSON));
|
|
103
96
|
}
|
|
104
97
|
done() {
|
|
105
98
|
return "Canary successful";
|
|
@@ -73,7 +73,7 @@ export const DigitrafficDLQueue = {
|
|
|
73
73
|
functionName: dlqFunctionName,
|
|
74
74
|
});
|
|
75
75
|
const lambda = MonitoredFunction.create(stack, dlqFunctionName, {
|
|
76
|
-
runtime: Runtime.
|
|
76
|
+
runtime: Runtime.NODEJS_22_X,
|
|
77
77
|
logGroup: dlqLogGroup,
|
|
78
78
|
functionName: dlqFunctionName,
|
|
79
79
|
code: getDlqCode(dlqBucket.bucketName),
|
|
@@ -9,7 +9,6 @@ import type { DigitrafficStack } from "./stack.js";
|
|
|
9
9
|
export declare class FunctionBuilder {
|
|
10
10
|
private readonly _stack;
|
|
11
11
|
private readonly _name;
|
|
12
|
-
private description?;
|
|
13
12
|
private runtime;
|
|
14
13
|
private architecture;
|
|
15
14
|
private role?;
|
|
@@ -46,13 +45,11 @@ export declare class FunctionBuilder {
|
|
|
46
45
|
withAssetCode(path?: string): this;
|
|
47
46
|
withCode(code: Code): this;
|
|
48
47
|
/**
|
|
49
|
-
* Use given handler(${name}.handler) to run the lambda. Default value is
|
|
48
|
+
* Use given handler(${name}.handler) to run the lambda. Default value is lambdaname.
|
|
50
49
|
* @param name
|
|
51
|
-
* @param handlerFunctionName
|
|
52
50
|
* @returns
|
|
53
51
|
*/
|
|
54
52
|
withHandler(name: string, handlerFunctionName?: string): this;
|
|
55
|
-
withDescription(description: string): this;
|
|
56
53
|
/**
|
|
57
54
|
* Do not grant database access. Default is with database access.
|
|
58
55
|
*/
|
|
@@ -70,7 +67,7 @@ export declare class FunctionBuilder {
|
|
|
70
67
|
*/
|
|
71
68
|
withMemorySize(memorySize: number): this;
|
|
72
69
|
/**
|
|
73
|
-
* Set runtime for the lambda. Default is Runtime.
|
|
70
|
+
* Set runtime for the lambda. Default is Runtime.NODEJS_22_X.
|
|
74
71
|
*/
|
|
75
72
|
withRuntime(runtime: Runtime): this;
|
|
76
73
|
/**
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { basename } from "node:path";
|
|
2
1
|
import { Duration } from "aws-cdk-lib";
|
|
3
2
|
import { SnsAction } from "aws-cdk-lib/aws-cloudwatch-actions";
|
|
4
3
|
import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
@@ -11,8 +10,7 @@ import { createLambdaLogGroup } from "./lambda-log-group.js";
|
|
|
11
10
|
export class FunctionBuilder {
|
|
12
11
|
_stack;
|
|
13
12
|
_name;
|
|
14
|
-
|
|
15
|
-
runtime = Runtime.NODEJS_24_X;
|
|
13
|
+
runtime = Runtime.NODEJS_22_X;
|
|
16
14
|
architecture = Architecture.ARM_64;
|
|
17
15
|
role;
|
|
18
16
|
timeout = Duration.seconds(60);
|
|
@@ -39,13 +37,8 @@ export class FunctionBuilder {
|
|
|
39
37
|
this.functionName = `${stack.configuration.shortName}-${startCase(camelCase(lambdaName)).replace(/\s/g, "")}`;
|
|
40
38
|
this.environment = {};
|
|
41
39
|
this.vpc = stack.vpc;
|
|
42
|
-
|
|
40
|
+
this.withHandler(lambdaName);
|
|
43
41
|
this.withAssetCode(lambdaName);
|
|
44
|
-
// Remove path from lambda to get module name.
|
|
45
|
-
// e.g. for lambdaName "api/charging-network/v1/operators",
|
|
46
|
-
// moduleName becomes "operators" and handler becomes "operators.handler"
|
|
47
|
-
const moduleName = basename(lambdaName);
|
|
48
|
-
this.withHandler(moduleName);
|
|
49
42
|
}
|
|
50
43
|
/**
|
|
51
44
|
* Creates a new builder with defaults, using the lambdaName as a source for the lambda implementation (dist/lambdaName/lambdaName.js).
|
|
@@ -85,19 +78,14 @@ export class FunctionBuilder {
|
|
|
85
78
|
return this;
|
|
86
79
|
}
|
|
87
80
|
/**
|
|
88
|
-
* Use given handler(${name}.handler) to run the lambda. Default value is
|
|
81
|
+
* Use given handler(${name}.handler) to run the lambda. Default value is lambdaname.
|
|
89
82
|
* @param name
|
|
90
|
-
* @param handlerFunctionName
|
|
91
83
|
* @returns
|
|
92
84
|
*/
|
|
93
85
|
withHandler(name, handlerFunctionName = "handler") {
|
|
94
86
|
this.handler = `${name}.${handlerFunctionName}`;
|
|
95
87
|
return this;
|
|
96
88
|
}
|
|
97
|
-
withDescription(description) {
|
|
98
|
-
this.description = description;
|
|
99
|
-
return this;
|
|
100
|
-
}
|
|
101
89
|
/**
|
|
102
90
|
* Do not grant database access. Default is with database access.
|
|
103
91
|
*/
|
|
@@ -127,7 +115,7 @@ export class FunctionBuilder {
|
|
|
127
115
|
return this;
|
|
128
116
|
}
|
|
129
117
|
/**
|
|
130
|
-
* Set runtime for the lambda. Default is Runtime.
|
|
118
|
+
* Set runtime for the lambda. Default is Runtime.NODEJS_22_X.
|
|
131
119
|
*/
|
|
132
120
|
withRuntime(runtime) {
|
|
133
121
|
this.runtime = runtime;
|
|
@@ -229,7 +217,6 @@ export class FunctionBuilder {
|
|
|
229
217
|
functionName: this.functionName,
|
|
230
218
|
securityGroups,
|
|
231
219
|
environment: this.getEnvironment(),
|
|
232
|
-
description: this.description,
|
|
233
220
|
});
|
|
234
221
|
if (this._features.secretAccess) {
|
|
235
222
|
this._stack.grantSecret(createdFunction);
|
|
@@ -10,13 +10,7 @@ export type DBLambdaEnvironment = LambdaEnvironment & {
|
|
|
10
10
|
SECRET_ID?: string;
|
|
11
11
|
DB_APPLICATION: string;
|
|
12
12
|
};
|
|
13
|
-
/**
|
|
14
|
-
* @deprecated use dt-function.ts: FunctionBuilder
|
|
15
|
-
*/
|
|
16
13
|
export declare function databaseFunctionProps(stack: DigitrafficStack, environment: LambdaEnvironment, lambdaName: string, simpleLambdaName: string, logGroup: ILogGroup, config?: Partial<FunctionParameters>): FunctionProps;
|
|
17
|
-
/**
|
|
18
|
-
* @deprecated use dt-function.ts: FunctionBuilder
|
|
19
|
-
*/
|
|
20
14
|
export declare function lambdaFunctionProps(_: DigitrafficStack, environment: LambdaEnvironment, lambdaName: string, simpleLambdaName: string, logGroup: ILogGroup, config?: Partial<FunctionParameters>): FunctionProps;
|
|
21
15
|
export declare function defaultLambdaConfiguration(config: FunctionParameters): FunctionProps;
|
|
22
16
|
export interface FunctionParameters {
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { Duration } from "aws-cdk-lib";
|
|
2
2
|
import { Architecture, AssetCode, Runtime } from "aws-cdk-lib/aws-lambda";
|
|
3
|
-
/**
|
|
4
|
-
* @deprecated use dt-function.ts: FunctionBuilder
|
|
5
|
-
*/
|
|
6
3
|
export function databaseFunctionProps(stack, environment, lambdaName, simpleLambdaName, logGroup, config) {
|
|
7
4
|
const vpcSubnets = stack.vpc
|
|
8
5
|
? {
|
|
@@ -18,12 +15,9 @@ export function databaseFunctionProps(stack, environment, lambdaName, simpleLamb
|
|
|
18
15
|
},
|
|
19
16
|
};
|
|
20
17
|
}
|
|
21
|
-
/**
|
|
22
|
-
* @deprecated use dt-function.ts: FunctionBuilder
|
|
23
|
-
*/
|
|
24
18
|
export function lambdaFunctionProps(_, environment, lambdaName, simpleLambdaName, logGroup, config) {
|
|
25
19
|
return {
|
|
26
|
-
runtime: config?.runtime ?? Runtime.
|
|
20
|
+
runtime: config?.runtime ?? Runtime.NODEJS_22_X,
|
|
27
21
|
architecture: config?.architecture ?? Architecture.ARM_64,
|
|
28
22
|
memorySize: config?.memorySize ?? 128,
|
|
29
23
|
functionName: lambdaName,
|
|
@@ -44,7 +38,7 @@ function getAssetCode(simpleLambdaName, isSingleLambda) {
|
|
|
44
38
|
}
|
|
45
39
|
export function defaultLambdaConfiguration(config) {
|
|
46
40
|
const props = {
|
|
47
|
-
runtime: Runtime.
|
|
41
|
+
runtime: Runtime.NODEJS_22_X,
|
|
48
42
|
memorySize: config.memorySize ?? 128,
|
|
49
43
|
functionName: config.functionName,
|
|
50
44
|
handler: config.handler,
|