@digitraffic/common 2026.3.17-1 → 2026.3.26-1-beta

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.
Files changed (238) hide show
  1. package/README.md +18 -1
  2. package/dist/__test__/asserter.d.ts +13 -0
  3. package/dist/__test__/asserter.js +39 -0
  4. package/dist/__test__/db-testutils.d.ts +3 -0
  5. package/dist/__test__/db-testutils.js +38 -0
  6. package/dist/__test__/dependencies.test.d.ts +1 -0
  7. package/dist/__test__/dependencies.test.js +21 -0
  8. package/dist/__test__/imports.test.d.ts +1 -0
  9. package/dist/__test__/imports.test.js +318 -0
  10. package/dist/__test__/infra/acl-builder.test.d.ts +1 -0
  11. package/dist/__test__/infra/acl-builder.test.js +72 -0
  12. package/dist/__test__/infra/api/handler-factory.test.d.ts +1 -0
  13. package/dist/__test__/infra/api/handler-factory.test.js +42 -0
  14. package/dist/__test__/infra/api/integration.test.d.ts +1 -0
  15. package/dist/__test__/infra/api/integration.test.js +162 -0
  16. package/dist/__test__/infra/api/response.test.d.ts +1 -0
  17. package/dist/__test__/infra/api/response.test.js +77 -0
  18. package/dist/__test__/infra/api/static-integration.test.d.ts +1 -0
  19. package/dist/__test__/infra/api/static-integration.test.js +35 -0
  20. package/dist/__test__/infra/documentation.test.d.ts +1 -0
  21. package/dist/__test__/infra/documentation.test.js +38 -0
  22. package/dist/__test__/infra/scheduler.test.d.ts +1 -0
  23. package/dist/__test__/infra/scheduler.test.js +23 -0
  24. package/dist/__test__/infra/security-rule.test.d.ts +1 -0
  25. package/dist/__test__/infra/security-rule.test.js +21 -0
  26. package/dist/__test__/infra/stack/rest-apis.test.d.ts +1 -0
  27. package/dist/__test__/infra/stack/rest-apis.test.js +47 -0
  28. package/dist/__test__/marine/id_utils.test.d.ts +1 -0
  29. package/dist/__test__/marine/id_utils.test.js +45 -0
  30. package/dist/__test__/mock-ky.d.ts +2 -0
  31. package/dist/__test__/mock-ky.js +15 -0
  32. package/dist/__test__/promise/promise.test.d.ts +1 -0
  33. package/dist/__test__/promise/promise.test.js +126 -0
  34. package/dist/__test__/runtime/dt-logger.test.d.ts +1 -0
  35. package/dist/__test__/runtime/dt-logger.test.js +193 -0
  36. package/dist/__test__/secrets/secret-holder.test.d.ts +1 -0
  37. package/dist/__test__/secrets/secret-holder.test.js +96 -0
  38. package/dist/__test__/secrets/secret.test.d.ts +1 -0
  39. package/dist/__test__/secrets/secret.test.js +57 -0
  40. package/dist/__test__/stack/dt-function.test.d.ts +1 -0
  41. package/dist/__test__/stack/dt-function.test.js +340 -0
  42. package/dist/__test__/stack/rest-apis.test.d.ts +1 -0
  43. package/dist/__test__/stack/rest-apis.test.js +45 -0
  44. package/dist/__test__/test/mock-ky.test.d.ts +1 -0
  45. package/dist/__test__/test/mock-ky.test.js +46 -0
  46. package/dist/__test__/testutils.d.ts +12 -0
  47. package/dist/__test__/testutils.js +32 -0
  48. package/dist/__test__/types/lambda-proxy-types.test.d.ts +8 -0
  49. package/dist/__test__/types/lambda-proxy-types.test.js +155 -0
  50. package/dist/__test__/types/lambda-response-builder.test.d.ts +1 -0
  51. package/dist/__test__/types/lambda-response-builder.test.js +81 -0
  52. package/dist/__test__/types/lambda-response.test.d.ts +9 -0
  53. package/dist/__test__/types/lambda-response.test.js +73 -0
  54. package/dist/__test__/utils/base64.test.d.ts +1 -0
  55. package/dist/__test__/utils/base64.test.js +38 -0
  56. package/dist/__test__/utils/date-utils.test.d.ts +1 -0
  57. package/dist/__test__/utils/date-utils.test.js +32 -0
  58. package/dist/__test__/utils/geometry.test.d.ts +1 -0
  59. package/dist/__test__/utils/geometry.test.js +25 -0
  60. package/dist/__test__/utils/lambda-proxy-event.test.d.ts +1 -0
  61. package/dist/__test__/utils/lambda-proxy-event.test.js +45 -0
  62. package/dist/__test__/utils/logging.test.d.ts +1 -0
  63. package/dist/__test__/utils/logging.test.js +75 -0
  64. package/dist/__test__/utils/stop-watch.test.d.ts +1 -0
  65. package/dist/__test__/utils/stop-watch.test.js +118 -0
  66. package/dist/__test__/utils/utils.test.d.ts +1 -0
  67. package/dist/__test__/utils/utils.test.js +48 -0
  68. package/dist/aws/infra/acl-builder.d.ts +53 -0
  69. package/dist/aws/infra/acl-builder.js +407 -0
  70. package/dist/aws/infra/api/handler-factory.d.ts +22 -0
  71. package/dist/aws/infra/api/handler-factory.js +68 -0
  72. package/dist/aws/infra/api/integration.d.ts +49 -0
  73. package/dist/aws/infra/api/integration.js +162 -0
  74. package/dist/aws/infra/api/response.d.ts +62 -0
  75. package/dist/aws/infra/api/response.js +132 -0
  76. package/dist/aws/infra/api/responses.d.ts +60 -0
  77. package/dist/aws/infra/api/responses.js +90 -0
  78. package/dist/aws/infra/api/static-integration.d.ts +16 -0
  79. package/dist/aws/infra/api/static-integration.js +76 -0
  80. package/dist/aws/infra/bucket-policy.d.ts +38 -0
  81. package/dist/aws/infra/bucket-policy.js +30 -0
  82. package/dist/aws/infra/canaries/canary-alarm.d.ts +6 -0
  83. package/dist/aws/infra/canaries/canary-alarm.js +20 -0
  84. package/dist/aws/infra/canaries/canary-keys.d.ts +3 -0
  85. package/dist/aws/infra/canaries/canary-keys.js +4 -0
  86. package/dist/aws/infra/canaries/canary-parameters.d.ts +19 -0
  87. package/dist/aws/infra/canaries/canary-parameters.js +2 -0
  88. package/dist/aws/infra/canaries/canary-role.d.ts +14 -0
  89. package/dist/aws/infra/canaries/canary-role.js +51 -0
  90. package/dist/aws/infra/canaries/canary.d.ts +8 -0
  91. package/dist/aws/infra/canaries/canary.js +26 -0
  92. package/dist/aws/infra/canaries/database-canary.d.ts +17 -0
  93. package/dist/aws/infra/canaries/database-canary.js +65 -0
  94. package/dist/aws/infra/canaries/database-checker.d.ts +33 -0
  95. package/dist/aws/infra/canaries/database-checker.js +119 -0
  96. package/dist/aws/infra/canaries/url-canary.d.ts +16 -0
  97. package/dist/aws/infra/canaries/url-canary.js +55 -0
  98. package/dist/aws/infra/canaries/url-checker.d.ts +45 -0
  99. package/dist/aws/infra/canaries/url-checker.js +256 -0
  100. package/dist/aws/infra/documentation.d.ts +56 -0
  101. package/dist/aws/infra/documentation.js +90 -0
  102. package/dist/aws/infra/import-util.d.ts +17 -0
  103. package/dist/aws/infra/import-util.js +41 -0
  104. package/dist/aws/infra/scheduler.d.ts +12 -0
  105. package/dist/aws/infra/scheduler.js +27 -0
  106. package/dist/aws/infra/security-rule.d.ts +12 -0
  107. package/dist/aws/infra/security-rule.js +35 -0
  108. package/dist/aws/infra/sqs-integration.d.ts +4 -0
  109. package/dist/aws/infra/sqs-integration.js +85 -0
  110. package/dist/aws/infra/sqs-queue.d.ts +19 -0
  111. package/dist/aws/infra/sqs-queue.js +145 -0
  112. package/dist/aws/infra/stack/dt-function-alarms.d.ts +29 -0
  113. package/dist/aws/infra/stack/dt-function-alarms.js +54 -0
  114. package/dist/aws/infra/stack/dt-function.d.ts +124 -0
  115. package/dist/aws/infra/stack/dt-function.js +315 -0
  116. package/dist/aws/infra/stack/lambda-configs.d.ts +44 -0
  117. package/dist/aws/infra/stack/lambda-configs.js +71 -0
  118. package/dist/aws/infra/stack/lambda-log-group.d.ts +15 -0
  119. package/dist/aws/infra/stack/lambda-log-group.js +24 -0
  120. package/dist/aws/infra/stack/monitoredfunction.d.ts +85 -0
  121. package/dist/aws/infra/stack/monitoredfunction.js +147 -0
  122. package/dist/aws/infra/stack/parameters.d.ts +40 -0
  123. package/dist/aws/infra/stack/parameters.js +50 -0
  124. package/dist/aws/infra/stack/rest-api.d.ts +74 -0
  125. package/dist/aws/infra/stack/rest-api.js +235 -0
  126. package/dist/aws/infra/stack/stack-checking-aspect.d.ts +20 -0
  127. package/dist/aws/infra/stack/stack-checking-aspect.js +183 -0
  128. package/dist/aws/infra/stack/stack.d.ts +56 -0
  129. package/dist/aws/infra/stack/stack.js +71 -0
  130. package/dist/aws/infra/stack/subscription.d.ts +17 -0
  131. package/dist/aws/infra/stack/subscription.js +37 -0
  132. package/dist/aws/infra/stacks/db-dns-stack.d.ts +13 -0
  133. package/dist/aws/infra/stacks/db-dns-stack.js +60 -0
  134. package/dist/aws/infra/stacks/db-proxy-stack.d.ts +24 -0
  135. package/dist/aws/infra/stacks/db-proxy-stack.js +74 -0
  136. package/dist/aws/infra/stacks/db-stack.d.ts +65 -0
  137. package/dist/aws/infra/stacks/db-stack.js +189 -0
  138. package/dist/aws/infra/stacks/intra-stack-configuration.d.ts +5 -0
  139. package/dist/aws/infra/stacks/intra-stack-configuration.js +2 -0
  140. package/dist/aws/infra/stacks/network-stack.d.ts +14 -0
  141. package/dist/aws/infra/stacks/network-stack.js +45 -0
  142. package/dist/aws/infra/usage-plans.d.ts +16 -0
  143. package/dist/aws/infra/usage-plans.js +38 -0
  144. package/dist/aws/runtime/apikey.d.ts +2 -0
  145. package/dist/aws/runtime/apikey.js +13 -0
  146. package/dist/aws/runtime/digitraffic-integration-response.d.ts +8 -0
  147. package/dist/aws/runtime/digitraffic-integration-response.js +25 -0
  148. package/dist/aws/runtime/dt-logger-default.d.ts +9 -0
  149. package/dist/aws/runtime/dt-logger-default.js +6 -0
  150. package/dist/aws/runtime/dt-logger.d.ts +117 -0
  151. package/dist/aws/runtime/dt-logger.js +159 -0
  152. package/dist/aws/runtime/environment.d.ts +5 -0
  153. package/dist/aws/runtime/environment.js +7 -0
  154. package/dist/aws/runtime/s3.d.ts +3 -0
  155. package/dist/aws/runtime/s3.js +21 -0
  156. package/dist/aws/runtime/secrets/dbsecret.d.ts +16 -0
  157. package/dist/aws/runtime/secrets/dbsecret.js +26 -0
  158. package/dist/aws/runtime/secrets/proxy-holder.d.ts +9 -0
  159. package/dist/aws/runtime/secrets/proxy-holder.js +25 -0
  160. package/dist/aws/runtime/secrets/rds-holder.d.ts +9 -0
  161. package/dist/aws/runtime/secrets/rds-holder.js +25 -0
  162. package/dist/aws/runtime/secrets/secret-holder.d.ts +30 -0
  163. package/dist/aws/runtime/secrets/secret-holder.js +81 -0
  164. package/dist/aws/runtime/secrets/secret.d.ts +8 -0
  165. package/dist/aws/runtime/secrets/secret.js +61 -0
  166. package/dist/aws/types/errors.d.ts +8 -0
  167. package/dist/aws/types/errors.js +13 -0
  168. package/dist/aws/types/lambda-proxy-types.d.ts +59 -0
  169. package/dist/aws/types/lambda-proxy-types.js +210 -0
  170. package/dist/aws/types/lambda-response.d.ts +89 -0
  171. package/dist/aws/types/lambda-response.js +204 -0
  172. package/dist/aws/types/mediatypes.d.ts +11 -0
  173. package/dist/aws/types/mediatypes.js +14 -0
  174. package/dist/aws/types/model-with-reference.d.ts +7 -0
  175. package/dist/aws/types/model-with-reference.js +2 -0
  176. package/dist/aws/types/tags.d.ts +2 -0
  177. package/dist/aws/types/tags.js +4 -0
  178. package/dist/database/database.d.ts +27 -0
  179. package/dist/database/database.js +95 -0
  180. package/dist/database/last-updated.d.ts +15 -0
  181. package/dist/database/last-updated.js +46 -0
  182. package/dist/database/models.d.ts +6 -0
  183. package/dist/database/models.js +2 -0
  184. package/dist/index.d.ts +2 -0
  185. package/dist/index.js +2 -0
  186. package/dist/marine/id_utils.d.ts +3 -0
  187. package/dist/marine/id_utils.js +36 -0
  188. package/dist/marine/rtz.d.ts +48 -0
  189. package/dist/marine/rtz.js +2 -0
  190. package/dist/types/async-timeout-error.d.ts +3 -0
  191. package/dist/types/async-timeout-error.js +6 -0
  192. package/dist/types/either.d.ts +9 -0
  193. package/dist/types/either.js +2 -0
  194. package/dist/types/geojson.d.ts +47 -0
  195. package/dist/types/geojson.js +51 -0
  196. package/dist/types/http-error.d.ts +4 -0
  197. package/dist/types/http-error.js +8 -0
  198. package/dist/types/input-error.d.ts +2 -0
  199. package/dist/types/input-error.js +3 -0
  200. package/dist/types/language.d.ts +5 -0
  201. package/dist/types/language.js +7 -0
  202. package/dist/types/nullable.d.ts +24 -0
  203. package/dist/types/nullable.js +2 -0
  204. package/dist/types/openapi-schema.d.ts +932 -0
  205. package/dist/types/openapi-schema.js +151 -0
  206. package/dist/types/traffictype.d.ts +11 -0
  207. package/dist/types/traffictype.js +13 -0
  208. package/dist/types/urn.d.ts +1 -0
  209. package/dist/types/urn.js +2 -0
  210. package/dist/types/util-types.d.ts +11 -0
  211. package/dist/types/util-types.js +2 -0
  212. package/dist/types/validator.d.ts +4 -0
  213. package/dist/types/validator.js +9 -0
  214. package/dist/utils/api-model.d.ts +51 -0
  215. package/dist/utils/api-model.js +118 -0
  216. package/dist/utils/base64.d.ts +34 -0
  217. package/dist/utils/base64.js +53 -0
  218. package/dist/utils/date-utils.d.ts +27 -0
  219. package/dist/utils/date-utils.js +45 -0
  220. package/dist/utils/geojson-types.d.ts +14 -0
  221. package/dist/utils/geojson-types.js +15 -0
  222. package/dist/utils/geometry.d.ts +44 -0
  223. package/dist/utils/geometry.js +154 -0
  224. package/dist/utils/lambda-proxy-event.d.ts +9 -0
  225. package/dist/utils/lambda-proxy-event.js +31 -0
  226. package/dist/utils/logging.d.ts +40 -0
  227. package/dist/utils/logging.js +88 -0
  228. package/dist/utils/retry.d.ts +33 -0
  229. package/dist/utils/retry.js +135 -0
  230. package/dist/utils/slack.d.ts +5 -0
  231. package/dist/utils/slack.js +24 -0
  232. package/dist/utils/stop-watch.d.ts +46 -0
  233. package/dist/utils/stop-watch.js +114 -0
  234. package/dist/utils/utils.d.ts +95 -0
  235. package/dist/utils/utils.js +178 -0
  236. package/dist/utils/zod-utils.d.ts +27 -0
  237. package/dist/utils/zod-utils.js +57 -0
  238. package/package.json +30 -28
@@ -0,0 +1,256 @@
1
+ import synthetics from "Synthetics";
2
+ import zlib from "node:zlib";
3
+ import { Asserter } from "../../../__test__/asserter.js";
4
+ import { isValidGeoJson } from "../../../utils/geometry.js";
5
+ import { logException } from "../../../utils/logging.js";
6
+ import { getEnvVariable } from "../../../utils/utils.js";
7
+ import { getApiKeyFromAPIGateway } from "../../runtime/apikey.js";
8
+ import { logger } from "../../runtime/dt-logger-default.js";
9
+ import { MediaType } from "../../types/mediatypes.js";
10
+ import { ENV_API_KEY, ENV_HOSTNAME } from "./canary-keys.js";
11
+ export const API_KEY_HEADER = "x-api-key";
12
+ const baseHeaders = {
13
+ "Digitraffic-User": "internal-digitraffic-canary",
14
+ "Accept-Encoding": "gzip",
15
+ Accept: "*/*",
16
+ };
17
+ // Step name can only contain letters, numbers, hyphens, underscores, periods, and spaces
18
+ function sanitizeStepName(url) {
19
+ return url.replace(/auth=.*/, "").replace(/[^a-zA-Z0-9\-_. ]/g, " ");
20
+ }
21
+ export class UrlChecker {
22
+ requestOptions;
23
+ constructor(hostname, apiKey) {
24
+ const headers = { ...baseHeaders };
25
+ if (apiKey) {
26
+ headers[API_KEY_HEADER] = apiKey;
27
+ }
28
+ this.requestOptions = {
29
+ hostname,
30
+ method: "GET",
31
+ protocol: "https:",
32
+ headers,
33
+ };
34
+ synthetics.getConfiguration().disableRequestMetrics();
35
+ synthetics
36
+ .getConfiguration()
37
+ .withIncludeRequestBody(false)
38
+ .withIncludeRequestHeaders(false)
39
+ .withIncludeResponseBody(false)
40
+ .withIncludeResponseHeaders(false)
41
+ .withFailedCanaryMetric(true);
42
+ }
43
+ static async create(hostname, apiKeyId) {
44
+ const apiKey = await getApiKeyFromAPIGateway(apiKeyId);
45
+ return new UrlChecker(hostname, apiKey.value);
46
+ }
47
+ static createV2() {
48
+ return UrlChecker.create(getEnvVariable(ENV_HOSTNAME), getEnvVariable(ENV_API_KEY));
49
+ }
50
+ async expectStatus(statusCode, url, callback) {
51
+ const requestOptions = {
52
+ ...this.requestOptions,
53
+ ...{
54
+ path: url,
55
+ },
56
+ };
57
+ await synthetics.executeHttpStep(`Verify ${statusCode} for ${sanitizeStepName(url)}`, requestOptions, callback);
58
+ }
59
+ expect200(url, ...callbacks) {
60
+ const callback = async (json, body, res) => {
61
+ await Promise.allSettled(callbacks.map((c) => c(json, body, res)));
62
+ };
63
+ return this.expectStatus(200, url, callback);
64
+ }
65
+ expect404(url) {
66
+ const requestOptions = {
67
+ ...this.requestOptions,
68
+ ...{
69
+ path: url,
70
+ },
71
+ };
72
+ return synthetics.executeHttpStep(`Verify 404 for ${sanitizeStepName(url)}`, requestOptions, validateStatusCodeAndContentType(404, MediaType.TEXT_PLAIN));
73
+ }
74
+ expect400(url) {
75
+ const requestOptions = {
76
+ ...this.requestOptions,
77
+ ...{
78
+ path: url,
79
+ },
80
+ };
81
+ return synthetics.executeHttpStep(`Verify 400 for ${sanitizeStepName(url)}`, requestOptions, validateStatusCodeAndContentType(400, MediaType.TEXT_PLAIN));
82
+ }
83
+ expect403WithoutApiKey(url, mediaType) {
84
+ if (!this.requestOptions.headers ||
85
+ !(API_KEY_HEADER in this.requestOptions.headers) ||
86
+ !this.requestOptions.headers[API_KEY_HEADER]) {
87
+ logger.error({
88
+ method: "UrlChecker.expect403WithoutApiKey",
89
+ message: "No Api-key defined",
90
+ });
91
+ }
92
+ const requestOptions = {
93
+ ...this.requestOptions,
94
+ ...{
95
+ path: url,
96
+ headers: baseHeaders,
97
+ },
98
+ };
99
+ return synthetics.executeHttpStep(`Verify 403 for ${sanitizeStepName(url)}`, requestOptions, validateStatusCodeAndContentType(403, mediaType ?? MediaType.APPLICATION_JSON));
100
+ }
101
+ done() {
102
+ return "Canary successful";
103
+ }
104
+ }
105
+ async function getResponseBody(response) {
106
+ const body = await getBodyFromResponse(response);
107
+ if (response.headers["content-encoding"] === "gzip") {
108
+ try {
109
+ return zlib.gunzipSync(body).toString();
110
+ }
111
+ catch (e) {
112
+ logException(logger, e);
113
+ }
114
+ }
115
+ return body.toString();
116
+ }
117
+ function getBodyFromResponse(response) {
118
+ return new Promise((resolve) => {
119
+ const buffers = [];
120
+ response.on("data", (data) => {
121
+ buffers.push(data);
122
+ });
123
+ response.on("end", () => {
124
+ resolve(Buffer.concat(buffers).toString());
125
+ });
126
+ });
127
+ }
128
+ /**
129
+ * Returns function, that validates that the status code and content-type from response are the given values
130
+ * @param statusCode
131
+ * @param contentType
132
+ */
133
+ function validateStatusCodeAndContentType(statusCode, contentType) {
134
+ return (res) => {
135
+ return new Promise((resolve) => {
136
+ if (res.statusCode !== statusCode) {
137
+ throw new Error(`${res.statusCode ?? undefined} ${res.statusMessage ?? undefined}`);
138
+ }
139
+ if (res.headers["content-type"] !== contentType) {
140
+ throw new Error(`Wrong content-type ${res.headers["content-type"] ?? undefined}`);
141
+ }
142
+ resolve();
143
+ });
144
+ };
145
+ }
146
+ // DEPRECATED
147
+ export class ResponseChecker {
148
+ contentType;
149
+ checkCors = true;
150
+ constructor(contentType) {
151
+ this.contentType = contentType;
152
+ }
153
+ static forJson() {
154
+ return new ResponseChecker(MediaType.APPLICATION_JSON);
155
+ }
156
+ static forCSV() {
157
+ return new ResponseChecker(MediaType.TEXT_CSV);
158
+ }
159
+ static forGeojson() {
160
+ return new ResponseChecker(MediaType.APPLICATION_GEOJSON);
161
+ }
162
+ static forJpeg() {
163
+ return new ResponseChecker(MediaType.IMAGE_JPEG);
164
+ }
165
+ check() {
166
+ return this.responseChecker(() => {
167
+ // no need to do anything
168
+ });
169
+ }
170
+ checkJson(fn) {
171
+ return this.responseChecker((body, res) => {
172
+ fn(JSON.parse(body), body, res);
173
+ });
174
+ }
175
+ responseChecker(fn) {
176
+ return async (res) => {
177
+ if (!res.statusCode) {
178
+ throw new Error("statusCode missing");
179
+ }
180
+ if (res.statusCode < 200 || res.statusCode > 299) {
181
+ throw new Error(`${res.statusCode} ${res.statusMessage ?? undefined}`);
182
+ }
183
+ if (this.checkCors && !res.headers["access-control-allow-origin"]) {
184
+ throw new Error("CORS missing");
185
+ }
186
+ if (res.headers["content-type"] !== this.contentType) {
187
+ throw new Error(`Wrong content-type ${res.headers["content-type"] ?? undefined}`);
188
+ }
189
+ const body = await getResponseBody(res);
190
+ fn(body, res);
191
+ };
192
+ }
193
+ }
194
+ export const ContentChecker = {
195
+ checkJson(fn) {
196
+ return async (res) => {
197
+ const body = await getResponseBody(res);
198
+ fn(JSON.parse(body), body, res);
199
+ };
200
+ },
201
+ checkResponse(fn) {
202
+ return async (res) => {
203
+ const body = await getResponseBody(res);
204
+ fn(body, res);
205
+ };
206
+ },
207
+ };
208
+ export const ContentTypeChecker = {
209
+ checkContentType(contentType) {
210
+ return (res) => {
211
+ if (!res.statusCode) {
212
+ throw new Error("statusCode missing");
213
+ }
214
+ if (res.statusCode < 200 || res.statusCode > 299) {
215
+ throw new Error(`${res.statusCode} ${res.statusMessage ?? undefined}`);
216
+ }
217
+ if (!res.headers["access-control-allow-origin"]) {
218
+ throw new Error("CORS missing");
219
+ }
220
+ if (res.headers["content-type"] !== contentType) {
221
+ throw new Error(`Wrong content-type ${res.headers["content-type"] ?? undefined}`);
222
+ }
223
+ return Promise.resolve();
224
+ };
225
+ },
226
+ };
227
+ export const GeoJsonChecker = {
228
+ validFeatureCollection(fn) {
229
+ return ResponseChecker.forGeojson().checkJson((json) => {
230
+ Asserter.assertEquals(json.type, "FeatureCollection");
231
+ Asserter.assertTrue(isValidGeoJson(json));
232
+ if (fn) {
233
+ fn(json);
234
+ }
235
+ });
236
+ },
237
+ };
238
+ export const HeaderChecker = {
239
+ checkHeaderExists(headerName) {
240
+ return (res) => {
241
+ if (!res.headers[headerName]) {
242
+ throw new Error(`Missing header: ${headerName}`);
243
+ }
244
+ return Promise.resolve();
245
+ };
246
+ },
247
+ checkHeaderMissing(headerName) {
248
+ return (res) => {
249
+ if (res.headers[headerName]) {
250
+ throw new Error(`Header should not exist: ${headerName}`);
251
+ }
252
+ return Promise.resolve();
253
+ };
254
+ },
255
+ };
256
+ //# sourceMappingURL=url-checker.js.map
@@ -0,0 +1,56 @@
1
+ import type { Resource } from "aws-cdk-lib/aws-apigateway";
2
+ import type { Construct } from "constructs";
3
+ /**
4
+ * Add description to a query parameter
5
+ * @param name query parameter name
6
+ * @param description query parameter description
7
+ * @param resource REST API resource
8
+ * @param stack CloudFormation stack
9
+ *
10
+ * @deprecated Use DigitrafficRestApi.documentResource
11
+ */
12
+ export declare function addQueryParameterDescription(name: string, description: string, resource: Resource, stack: Construct): void;
13
+ /**
14
+ * Add a documentation part to a method
15
+ * @param methodDescription
16
+ * @param documentationProperties
17
+ * @param resource REST API resource
18
+ * @param stack CloudFormation stack
19
+ */
20
+ export declare function addDocumentation(methodDescription: string, documentationProperties: object, resource: Resource, stack: Construct): void;
21
+ /**
22
+ * Adds OpenAPI tags to an API method
23
+ * @param methodDescription Description of API method
24
+ * @param tags OpenAPI tags
25
+ * @param resource REST API resource
26
+ * @param stack CloudFormation stack
27
+ */
28
+ export declare function addTags(methodDescription: string, tags: string[], resource: Resource, stack: Construct): void;
29
+ /**
30
+ * Adds OpenAPI tags and a method summary to an API method
31
+ *
32
+ * @deprecated Use DigitrafficRestApi.documentResource
33
+ *
34
+ * @param methodDescription Description of API method
35
+ * @param tags OpenAPI tags
36
+ * @param summary OpenAPI summary
37
+ * @param resource REST API resource
38
+ * @param stack CloudFormation stack
39
+ */
40
+ export declare function addTagsAndSummary(methodDescription: string, tags: string[], summary: string, resource: Resource, stack: Construct): void;
41
+ export interface DocumentationProperties {
42
+ description?: string;
43
+ tags?: string[];
44
+ summary?: string;
45
+ deprecated?: boolean;
46
+ }
47
+ export declare class DocumentationPart {
48
+ readonly parameterName: string;
49
+ readonly type: string;
50
+ readonly documentationProperties: DocumentationProperties;
51
+ private constructor();
52
+ deprecated(note: string): this;
53
+ static queryParameter(parameterName: string, description: string): DocumentationPart;
54
+ static pathParameter(parameterName: string, description: string): DocumentationPart;
55
+ static method(tags: string[], name: string, summary: string): DocumentationPart;
56
+ }
@@ -0,0 +1,90 @@
1
+ import { CfnDocumentationPart } from "aws-cdk-lib/aws-apigateway";
2
+ // Documentation parts are objects that describe an API Gateway API or parts of an API
3
+ // https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-documenting-api.html
4
+ /**
5
+ * Add description to a query parameter
6
+ * @param name query parameter name
7
+ * @param description query parameter description
8
+ * @param resource REST API resource
9
+ * @param stack CloudFormation stack
10
+ *
11
+ * @deprecated Use DigitrafficRestApi.documentResource
12
+ */
13
+ export function addQueryParameterDescription(name, description, resource, stack) {
14
+ new CfnDocumentationPart(stack, `${name}Documentation`, {
15
+ restApiId: resource.api.restApiId,
16
+ location: {
17
+ type: "QUERY_PARAMETER",
18
+ name,
19
+ path: resource.path,
20
+ },
21
+ properties: JSON.stringify({ description }),
22
+ });
23
+ }
24
+ /**
25
+ * Add a documentation part to a method
26
+ * @param methodDescription
27
+ * @param documentationProperties
28
+ * @param resource REST API resource
29
+ * @param stack CloudFormation stack
30
+ */
31
+ export function addDocumentation(methodDescription, documentationProperties, resource, stack) {
32
+ new CfnDocumentationPart(stack, `${methodDescription}Documentation`, {
33
+ restApiId: resource.api.restApiId,
34
+ location: {
35
+ type: "METHOD",
36
+ path: resource.path,
37
+ },
38
+ properties: JSON.stringify(documentationProperties),
39
+ });
40
+ }
41
+ /**
42
+ * Adds OpenAPI tags to an API method
43
+ * @param methodDescription Description of API method
44
+ * @param tags OpenAPI tags
45
+ * @param resource REST API resource
46
+ * @param stack CloudFormation stack
47
+ */
48
+ export function addTags(methodDescription, tags, resource, stack) {
49
+ addDocumentation(methodDescription, { tags }, resource, stack);
50
+ }
51
+ /**
52
+ * Adds OpenAPI tags and a method summary to an API method
53
+ *
54
+ * @deprecated Use DigitrafficRestApi.documentResource
55
+ *
56
+ * @param methodDescription Description of API method
57
+ * @param tags OpenAPI tags
58
+ * @param summary OpenAPI summary
59
+ * @param resource REST API resource
60
+ * @param stack CloudFormation stack
61
+ */
62
+ export function addTagsAndSummary(methodDescription, tags, summary, resource, stack) {
63
+ addDocumentation(methodDescription, { tags, summary }, resource, stack);
64
+ }
65
+ export class DocumentationPart {
66
+ parameterName;
67
+ type;
68
+ documentationProperties;
69
+ constructor(parameterName, documentationProperties, type) {
70
+ this.parameterName = parameterName;
71
+ this.documentationProperties = documentationProperties;
72
+ this.type = type;
73
+ }
74
+ deprecated(note) {
75
+ // deprecated is not supported ATM: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html
76
+ this.documentationProperties.deprecated = true;
77
+ this.documentationProperties.summary += `. ${note}`;
78
+ return this;
79
+ }
80
+ static queryParameter(parameterName, description) {
81
+ return new DocumentationPart(parameterName, { description }, "QUERY_PARAMETER");
82
+ }
83
+ static pathParameter(parameterName, description) {
84
+ return new DocumentationPart(parameterName, { description }, "PATH_PARAMETER");
85
+ }
86
+ static method(tags, name, summary) {
87
+ return new DocumentationPart(name, { tags, summary }, "METHOD");
88
+ }
89
+ }
90
+ //# sourceMappingURL=documentation.js.map
@@ -0,0 +1,17 @@
1
+ import type { Stack } from "aws-cdk-lib";
2
+ import type { IVpc } from "aws-cdk-lib/aws-ec2";
3
+ import type { Construct } from "constructs";
4
+ /**
5
+ * Import VPC from other stack outputs
6
+ */
7
+ export declare function importVpc(scope: Construct, environmentName: string): IVpc;
8
+ /**
9
+ * Import value from other stack output. Stack outputs are named with
10
+ * digitraffic-${environmentName}-${name} pattern and this function takes care of it
11
+ */
12
+ export declare function importValue(environmentName: string, name: string): string;
13
+ /**
14
+ * Export value as stack output. Use same naming pattern as importValue.
15
+ */
16
+ export declare function exportValue(stack: Stack, environmentName: string, name: string, value: string): void;
17
+ export declare function outputName(environmentName: string, name: string): string;
@@ -0,0 +1,41 @@
1
+ import { CfnOutput, Fn } from "aws-cdk-lib";
2
+ import { Vpc } from "aws-cdk-lib/aws-ec2";
3
+ /**
4
+ * Import VPC from other stack outputs
5
+ */
6
+ export function importVpc(scope, environmentName) {
7
+ const vpcId = importValue(environmentName, "VPCID");
8
+ const privateSubnetIds = [
9
+ importValue(environmentName, "digitrafficprivateASubnet"),
10
+ importValue(environmentName, "digitrafficprivateBSubnet"),
11
+ ];
12
+ const availabilityZones = ["euw1-az1", "euw1-az2"];
13
+ // VPC reference construction requires vpcId and availability zones
14
+ // private subnets are used in Lambda configuration
15
+ return Vpc.fromVpcAttributes(scope, "vpc", {
16
+ vpcId,
17
+ privateSubnetIds,
18
+ availabilityZones,
19
+ });
20
+ }
21
+ /**
22
+ * Import value from other stack output. Stack outputs are named with
23
+ * digitraffic-${environmentName}-${name} pattern and this function takes care of it
24
+ */
25
+ export function importValue(environmentName, name) {
26
+ return Fn.importValue(outputName(environmentName, name));
27
+ }
28
+ /**
29
+ * Export value as stack output. Use same naming pattern as importValue.
30
+ */
31
+ export function exportValue(stack, environmentName, name, value) {
32
+ const exportName = outputName(environmentName, name);
33
+ new CfnOutput(stack, exportName, {
34
+ exportName,
35
+ value,
36
+ });
37
+ }
38
+ export function outputName(environmentName, name) {
39
+ return `digitraffic-${environmentName}-${name}`;
40
+ }
41
+ //# sourceMappingURL=import-util.js.map
@@ -0,0 +1,12 @@
1
+ import { Duration } from "aws-cdk-lib";
2
+ import { Rule, Schedule } from "aws-cdk-lib/aws-events";
3
+ import type { Function as AWSFunction } from "aws-cdk-lib/aws-lambda";
4
+ import type { Construct } from "constructs";
5
+ export declare class Scheduler extends Rule {
6
+ constructor(stack: Construct, ruleName: string, schedule: Schedule, lambda?: AWSFunction);
7
+ static everyMinute(stack: Construct, ruleName: string, lambda?: AWSFunction): Scheduler;
8
+ static everyMinutes(stack: Construct, ruleName: string, minutes: number, lambda?: AWSFunction): Scheduler;
9
+ static everyHour(stack: Construct, ruleName: string, lambda?: AWSFunction): Scheduler;
10
+ static everyDay(stack: Construct, ruleName: string, lambda?: AWSFunction): Scheduler;
11
+ static every(stack: Construct, ruleName: string, duration: Duration, lambda?: AWSFunction): Scheduler;
12
+ }
@@ -0,0 +1,27 @@
1
+ import { Duration } from "aws-cdk-lib";
2
+ import { Rule, Schedule } from "aws-cdk-lib/aws-events";
3
+ import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
4
+ export class Scheduler extends Rule {
5
+ constructor(stack, ruleName, schedule, lambda) {
6
+ super(stack, ruleName, { ruleName, schedule });
7
+ if (lambda) {
8
+ this.addTarget(new LambdaFunction(lambda));
9
+ }
10
+ }
11
+ static everyMinute(stack, ruleName, lambda) {
12
+ return Scheduler.every(stack, ruleName, Duration.minutes(1), lambda);
13
+ }
14
+ static everyMinutes(stack, ruleName, minutes, lambda) {
15
+ return Scheduler.every(stack, ruleName, Duration.minutes(minutes), lambda);
16
+ }
17
+ static everyHour(stack, ruleName, lambda) {
18
+ return Scheduler.every(stack, ruleName, Duration.hours(1), lambda);
19
+ }
20
+ static everyDay(stack, ruleName, lambda) {
21
+ return Scheduler.every(stack, ruleName, Duration.days(1), lambda);
22
+ }
23
+ static every(stack, ruleName, duration, lambda) {
24
+ return new Scheduler(stack, ruleName, Schedule.rate(duration), lambda);
25
+ }
26
+ }
27
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1,12 @@
1
+ import { Rule } from "aws-cdk-lib/aws-events";
2
+ import type { ITopic } from "aws-cdk-lib/aws-sns";
3
+ import type { Construct } from "constructs";
4
+ /**
5
+ * Automatic rule for Security Hub. Send notification to given topic if the following conditions apply:
6
+ * * There is a finding with a status of NEW
7
+ * * It has severity of HIGH or CRITICAL
8
+ * * It is in a FAILED state
9
+ */
10
+ export declare class DigitrafficSecurityRule extends Rule {
11
+ constructor(scope: Construct, topic: ITopic);
12
+ }
@@ -0,0 +1,35 @@
1
+ import { Rule } from "aws-cdk-lib/aws-events";
2
+ import { SnsTopic } from "aws-cdk-lib/aws-events-targets";
3
+ /**
4
+ * Automatic rule for Security Hub. Send notification to given topic if the following conditions apply:
5
+ * * There is a finding with a status of NEW
6
+ * * It has severity of HIGH or CRITICAL
7
+ * * It is in a FAILED state
8
+ */
9
+ export class DigitrafficSecurityRule extends Rule {
10
+ constructor(scope, topic) {
11
+ const ruleName = "SecurityHubRule";
12
+ super(scope, ruleName, {
13
+ ruleName,
14
+ eventPattern: {
15
+ source: ["aws.securityhub"],
16
+ detailType: ["Security Hub Findings - Imported"],
17
+ detail: {
18
+ findings: {
19
+ Compliance: {
20
+ Status: ["FAILED"],
21
+ },
22
+ Workflow: {
23
+ Status: ["NEW"],
24
+ },
25
+ Severity: {
26
+ Label: ["HIGH", "CRITICAL"],
27
+ },
28
+ },
29
+ },
30
+ },
31
+ });
32
+ this.addTarget(new SnsTopic(topic));
33
+ }
34
+ }
35
+ //# sourceMappingURL=security-rule.js.map
@@ -0,0 +1,4 @@
1
+ import type { IModel, RequestValidator, Resource } from "aws-cdk-lib/aws-apigateway";
2
+ import type { Queue } from "aws-cdk-lib/aws-sqs";
3
+ import type { Construct } from "constructs";
4
+ export declare function attachQueueToApiGatewayResource(stack: Construct, queue: Queue, resource: Resource, requestValidator: RequestValidator, resourceName: string, apiKeyRequired: boolean, requestModels?: Record<string, IModel>): void;
@@ -0,0 +1,85 @@
1
+ import { Aws } from "aws-cdk-lib";
2
+ import { AwsIntegration, PassthroughBehavior, } from "aws-cdk-lib/aws-apigateway";
3
+ import { PolicyStatement, Role, ServicePrincipal } from "aws-cdk-lib/aws-iam";
4
+ export function attachQueueToApiGatewayResource(stack, queue, resource, requestValidator, resourceName, apiKeyRequired, requestModels) {
5
+ // role for API Gateway
6
+ const apiGwRole = new Role(stack, `${resourceName}APIGatewayToSQSRole`, {
7
+ assumedBy: new ServicePrincipal("apigateway.amazonaws.com"),
8
+ });
9
+ // grants API Gateway the right to send SQS messages
10
+ apiGwRole.addToPolicy(new PolicyStatement({
11
+ resources: [queue.queueArn],
12
+ actions: ["sqs:SendMessage"],
13
+ }));
14
+ // grants API Gateway the right write CloudWatch Logs
15
+ apiGwRole.addToPolicy(new PolicyStatement({
16
+ resources: ["*"],
17
+ actions: [
18
+ "logs:CreateLogGroup",
19
+ "logs:CreateLogStream",
20
+ "logs:DescribeLogGroups",
21
+ "logs:DescribeLogStreams",
22
+ "logs:PutLogEvents",
23
+ "logs:GetLogEvents",
24
+ "logs:FilterLogEvents",
25
+ ],
26
+ }));
27
+ // create an integration between API Gateway and an SQS queue
28
+ const fifoMessageGroupId = queue.fifo
29
+ ? "&MessageGroupId=AlwaysSameFifoGroup"
30
+ : "";
31
+ const sqsIntegration = new AwsIntegration({
32
+ service: "sqs",
33
+ integrationHttpMethod: "POST",
34
+ options: {
35
+ passthroughBehavior: PassthroughBehavior.NEVER,
36
+ credentialsRole: apiGwRole,
37
+ requestParameters: {
38
+ // SQS requires the Content-Type of the HTTP request to be application/x-www-form-urlencoded
39
+ "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'",
40
+ },
41
+ requestTemplates: {
42
+ // map the JSON request to a form parameter, FIFO needs also MessageGroupId
43
+ // https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
44
+ "application/json": `Action=SendMessage${fifoMessageGroupId}&MessageBody=$util.urlEncode($input.body)`,
45
+ },
46
+ // these are required by SQS
47
+ integrationResponses: [
48
+ {
49
+ statusCode: "200",
50
+ responseTemplates: {
51
+ "text/html": "Success",
52
+ },
53
+ },
54
+ {
55
+ statusCode: "500",
56
+ responseTemplates: {
57
+ "text/html": "Error",
58
+ },
59
+ selectionPattern: "500",
60
+ },
61
+ ],
62
+ },
63
+ path: `${Aws.ACCOUNT_ID}/${queue.queueName}`,
64
+ });
65
+ resource.addMethod("POST", sqsIntegration, {
66
+ requestValidator,
67
+ apiKeyRequired,
68
+ requestModels: requestModels ?? {},
69
+ methodResponses: [
70
+ {
71
+ statusCode: "200",
72
+ responseParameters: {
73
+ "method.response.header.Content-Type": true,
74
+ },
75
+ },
76
+ {
77
+ statusCode: "500",
78
+ responseParameters: {
79
+ "method.response.header.Content-Type": true,
80
+ },
81
+ },
82
+ ],
83
+ });
84
+ }
85
+ //# sourceMappingURL=sqs-integration.js.map
@@ -0,0 +1,19 @@
1
+ import type { QueueProps } from "aws-cdk-lib/aws-sqs";
2
+ import { Queue } from "aws-cdk-lib/aws-sqs";
3
+ import type { DigitrafficStack } from "./stack/stack.js";
4
+ /**
5
+ * Construct for creating SQS-queues.
6
+ *
7
+ * If you don't config your own deadLetterQueue, this will create a dlq for you, also a lambda function, a s3 bucket
8
+ * and an alarm for the queue. Anything that goes to the dlq will be written into the bucket and the alarm is activated.
9
+ */
10
+ export declare class DigitrafficSqsQueue extends Queue {
11
+ static create(stack: DigitrafficStack, name: string, props: QueueProps): DigitrafficSqsQueue;
12
+ /**
13
+ * Create a fifo with given name. No DLQ created!
14
+ */
15
+ static createFifo(stack: DigitrafficStack, name: string, props: QueueProps): DigitrafficSqsQueue;
16
+ }
17
+ export declare const DigitrafficDLQueue: {
18
+ create(stack: DigitrafficStack, name: string): DigitrafficSqsQueue;
19
+ };