@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.
- package/README.md +18 -1
- package/dist/__test__/asserter.d.ts +13 -0
- package/dist/__test__/asserter.js +39 -0
- package/dist/__test__/db-testutils.d.ts +3 -0
- package/dist/__test__/db-testutils.js +38 -0
- package/dist/__test__/dependencies.test.d.ts +1 -0
- package/dist/__test__/dependencies.test.js +21 -0
- package/dist/__test__/imports.test.d.ts +1 -0
- package/dist/__test__/imports.test.js +318 -0
- package/dist/__test__/infra/acl-builder.test.d.ts +1 -0
- package/dist/__test__/infra/acl-builder.test.js +72 -0
- package/dist/__test__/infra/api/handler-factory.test.d.ts +1 -0
- package/dist/__test__/infra/api/handler-factory.test.js +42 -0
- package/dist/__test__/infra/api/integration.test.d.ts +1 -0
- package/dist/__test__/infra/api/integration.test.js +162 -0
- package/dist/__test__/infra/api/response.test.d.ts +1 -0
- package/dist/__test__/infra/api/response.test.js +77 -0
- package/dist/__test__/infra/api/static-integration.test.d.ts +1 -0
- package/dist/__test__/infra/api/static-integration.test.js +35 -0
- package/dist/__test__/infra/documentation.test.d.ts +1 -0
- package/dist/__test__/infra/documentation.test.js +38 -0
- package/dist/__test__/infra/scheduler.test.d.ts +1 -0
- package/dist/__test__/infra/scheduler.test.js +23 -0
- package/dist/__test__/infra/security-rule.test.d.ts +1 -0
- package/dist/__test__/infra/security-rule.test.js +21 -0
- package/dist/__test__/infra/stack/rest-apis.test.d.ts +1 -0
- package/dist/__test__/infra/stack/rest-apis.test.js +47 -0
- package/dist/__test__/marine/id_utils.test.d.ts +1 -0
- package/dist/__test__/marine/id_utils.test.js +45 -0
- package/dist/__test__/mock-ky.d.ts +2 -0
- package/dist/__test__/mock-ky.js +15 -0
- package/dist/__test__/promise/promise.test.d.ts +1 -0
- package/dist/__test__/promise/promise.test.js +126 -0
- package/dist/__test__/runtime/dt-logger.test.d.ts +1 -0
- package/dist/__test__/runtime/dt-logger.test.js +193 -0
- package/dist/__test__/secrets/secret-holder.test.d.ts +1 -0
- package/dist/__test__/secrets/secret-holder.test.js +96 -0
- package/dist/__test__/secrets/secret.test.d.ts +1 -0
- package/dist/__test__/secrets/secret.test.js +57 -0
- package/dist/__test__/stack/dt-function.test.d.ts +1 -0
- package/dist/__test__/stack/dt-function.test.js +340 -0
- package/dist/__test__/stack/rest-apis.test.d.ts +1 -0
- package/dist/__test__/stack/rest-apis.test.js +45 -0
- package/dist/__test__/test/mock-ky.test.d.ts +1 -0
- package/dist/__test__/test/mock-ky.test.js +46 -0
- package/dist/__test__/testutils.d.ts +12 -0
- package/dist/__test__/testutils.js +32 -0
- package/dist/__test__/types/lambda-proxy-types.test.d.ts +8 -0
- package/dist/__test__/types/lambda-proxy-types.test.js +155 -0
- package/dist/__test__/types/lambda-response-builder.test.d.ts +1 -0
- package/dist/__test__/types/lambda-response-builder.test.js +81 -0
- package/dist/__test__/types/lambda-response.test.d.ts +9 -0
- package/dist/__test__/types/lambda-response.test.js +73 -0
- package/dist/__test__/utils/base64.test.d.ts +1 -0
- package/dist/__test__/utils/base64.test.js +38 -0
- package/dist/__test__/utils/date-utils.test.d.ts +1 -0
- package/dist/__test__/utils/date-utils.test.js +32 -0
- package/dist/__test__/utils/geometry.test.d.ts +1 -0
- package/dist/__test__/utils/geometry.test.js +25 -0
- package/dist/__test__/utils/lambda-proxy-event.test.d.ts +1 -0
- package/dist/__test__/utils/lambda-proxy-event.test.js +45 -0
- package/dist/__test__/utils/logging.test.d.ts +1 -0
- package/dist/__test__/utils/logging.test.js +75 -0
- package/dist/__test__/utils/stop-watch.test.d.ts +1 -0
- package/dist/__test__/utils/stop-watch.test.js +118 -0
- package/dist/__test__/utils/utils.test.d.ts +1 -0
- package/dist/__test__/utils/utils.test.js +48 -0
- package/dist/aws/infra/acl-builder.d.ts +53 -0
- package/dist/aws/infra/acl-builder.js +407 -0
- package/dist/aws/infra/api/handler-factory.d.ts +22 -0
- package/dist/aws/infra/api/handler-factory.js +68 -0
- package/dist/aws/infra/api/integration.d.ts +49 -0
- package/dist/aws/infra/api/integration.js +162 -0
- package/dist/aws/infra/api/response.d.ts +62 -0
- package/dist/aws/infra/api/response.js +132 -0
- package/dist/aws/infra/api/responses.d.ts +60 -0
- package/dist/aws/infra/api/responses.js +90 -0
- package/dist/aws/infra/api/static-integration.d.ts +16 -0
- package/dist/aws/infra/api/static-integration.js +76 -0
- package/dist/aws/infra/bucket-policy.d.ts +38 -0
- package/dist/aws/infra/bucket-policy.js +30 -0
- package/dist/aws/infra/canaries/canary-alarm.d.ts +6 -0
- package/dist/aws/infra/canaries/canary-alarm.js +20 -0
- package/dist/aws/infra/canaries/canary-keys.d.ts +3 -0
- package/dist/aws/infra/canaries/canary-keys.js +4 -0
- package/dist/aws/infra/canaries/canary-parameters.d.ts +19 -0
- package/dist/aws/infra/canaries/canary-parameters.js +2 -0
- package/dist/aws/infra/canaries/canary-role.d.ts +14 -0
- package/dist/aws/infra/canaries/canary-role.js +51 -0
- package/dist/aws/infra/canaries/canary.d.ts +8 -0
- package/dist/aws/infra/canaries/canary.js +26 -0
- package/dist/aws/infra/canaries/database-canary.d.ts +17 -0
- package/dist/aws/infra/canaries/database-canary.js +65 -0
- package/dist/aws/infra/canaries/database-checker.d.ts +33 -0
- package/dist/aws/infra/canaries/database-checker.js +119 -0
- package/dist/aws/infra/canaries/url-canary.d.ts +16 -0
- package/dist/aws/infra/canaries/url-canary.js +55 -0
- package/dist/aws/infra/canaries/url-checker.d.ts +45 -0
- package/dist/aws/infra/canaries/url-checker.js +256 -0
- package/dist/aws/infra/documentation.d.ts +56 -0
- package/dist/aws/infra/documentation.js +90 -0
- package/dist/aws/infra/import-util.d.ts +17 -0
- package/dist/aws/infra/import-util.js +41 -0
- package/dist/aws/infra/scheduler.d.ts +12 -0
- package/dist/aws/infra/scheduler.js +27 -0
- package/dist/aws/infra/security-rule.d.ts +12 -0
- package/dist/aws/infra/security-rule.js +35 -0
- package/dist/aws/infra/sqs-integration.d.ts +4 -0
- package/dist/aws/infra/sqs-integration.js +85 -0
- package/dist/aws/infra/sqs-queue.d.ts +19 -0
- package/dist/aws/infra/sqs-queue.js +145 -0
- package/dist/aws/infra/stack/dt-function-alarms.d.ts +29 -0
- package/dist/aws/infra/stack/dt-function-alarms.js +54 -0
- package/dist/aws/infra/stack/dt-function.d.ts +124 -0
- package/dist/aws/infra/stack/dt-function.js +315 -0
- package/dist/aws/infra/stack/lambda-configs.d.ts +44 -0
- package/dist/aws/infra/stack/lambda-configs.js +71 -0
- package/dist/aws/infra/stack/lambda-log-group.d.ts +15 -0
- package/dist/aws/infra/stack/lambda-log-group.js +24 -0
- package/dist/aws/infra/stack/monitoredfunction.d.ts +85 -0
- package/dist/aws/infra/stack/monitoredfunction.js +147 -0
- package/dist/aws/infra/stack/parameters.d.ts +40 -0
- package/dist/aws/infra/stack/parameters.js +50 -0
- package/dist/aws/infra/stack/rest-api.d.ts +74 -0
- package/dist/aws/infra/stack/rest-api.js +235 -0
- package/dist/aws/infra/stack/stack-checking-aspect.d.ts +20 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js +183 -0
- package/dist/aws/infra/stack/stack.d.ts +56 -0
- package/dist/aws/infra/stack/stack.js +71 -0
- package/dist/aws/infra/stack/subscription.d.ts +17 -0
- package/dist/aws/infra/stack/subscription.js +37 -0
- package/dist/aws/infra/stacks/db-dns-stack.d.ts +13 -0
- package/dist/aws/infra/stacks/db-dns-stack.js +60 -0
- package/dist/aws/infra/stacks/db-proxy-stack.d.ts +24 -0
- package/dist/aws/infra/stacks/db-proxy-stack.js +74 -0
- package/dist/aws/infra/stacks/db-stack.d.ts +65 -0
- package/dist/aws/infra/stacks/db-stack.js +189 -0
- package/dist/aws/infra/stacks/intra-stack-configuration.d.ts +5 -0
- package/dist/aws/infra/stacks/intra-stack-configuration.js +2 -0
- package/dist/aws/infra/stacks/network-stack.d.ts +14 -0
- package/dist/aws/infra/stacks/network-stack.js +45 -0
- package/dist/aws/infra/usage-plans.d.ts +16 -0
- package/dist/aws/infra/usage-plans.js +38 -0
- package/dist/aws/runtime/apikey.d.ts +2 -0
- package/dist/aws/runtime/apikey.js +13 -0
- package/dist/aws/runtime/digitraffic-integration-response.d.ts +8 -0
- package/dist/aws/runtime/digitraffic-integration-response.js +25 -0
- package/dist/aws/runtime/dt-logger-default.d.ts +9 -0
- package/dist/aws/runtime/dt-logger-default.js +6 -0
- package/dist/aws/runtime/dt-logger.d.ts +117 -0
- package/dist/aws/runtime/dt-logger.js +159 -0
- package/dist/aws/runtime/environment.d.ts +5 -0
- package/dist/aws/runtime/environment.js +7 -0
- package/dist/aws/runtime/s3.d.ts +3 -0
- package/dist/aws/runtime/s3.js +21 -0
- package/dist/aws/runtime/secrets/dbsecret.d.ts +16 -0
- package/dist/aws/runtime/secrets/dbsecret.js +26 -0
- package/dist/aws/runtime/secrets/proxy-holder.d.ts +9 -0
- package/dist/aws/runtime/secrets/proxy-holder.js +25 -0
- package/dist/aws/runtime/secrets/rds-holder.d.ts +9 -0
- package/dist/aws/runtime/secrets/rds-holder.js +25 -0
- package/dist/aws/runtime/secrets/secret-holder.d.ts +30 -0
- package/dist/aws/runtime/secrets/secret-holder.js +81 -0
- package/dist/aws/runtime/secrets/secret.d.ts +8 -0
- package/dist/aws/runtime/secrets/secret.js +61 -0
- package/dist/aws/types/errors.d.ts +8 -0
- package/dist/aws/types/errors.js +13 -0
- package/dist/aws/types/lambda-proxy-types.d.ts +59 -0
- package/dist/aws/types/lambda-proxy-types.js +210 -0
- package/dist/aws/types/lambda-response.d.ts +89 -0
- package/dist/aws/types/lambda-response.js +204 -0
- package/dist/aws/types/mediatypes.d.ts +11 -0
- package/dist/aws/types/mediatypes.js +14 -0
- package/dist/aws/types/model-with-reference.d.ts +7 -0
- package/dist/aws/types/model-with-reference.js +2 -0
- package/dist/aws/types/tags.d.ts +2 -0
- package/dist/aws/types/tags.js +4 -0
- package/dist/database/database.d.ts +27 -0
- package/dist/database/database.js +95 -0
- package/dist/database/last-updated.d.ts +15 -0
- package/dist/database/last-updated.js +46 -0
- package/dist/database/models.d.ts +6 -0
- package/dist/database/models.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/marine/id_utils.d.ts +3 -0
- package/dist/marine/id_utils.js +36 -0
- package/dist/marine/rtz.d.ts +48 -0
- package/dist/marine/rtz.js +2 -0
- package/dist/types/async-timeout-error.d.ts +3 -0
- package/dist/types/async-timeout-error.js +6 -0
- package/dist/types/either.d.ts +9 -0
- package/dist/types/either.js +2 -0
- package/dist/types/geojson.d.ts +47 -0
- package/dist/types/geojson.js +51 -0
- package/dist/types/http-error.d.ts +4 -0
- package/dist/types/http-error.js +8 -0
- package/dist/types/input-error.d.ts +2 -0
- package/dist/types/input-error.js +3 -0
- package/dist/types/language.d.ts +5 -0
- package/dist/types/language.js +7 -0
- package/dist/types/nullable.d.ts +24 -0
- package/dist/types/nullable.js +2 -0
- package/dist/types/openapi-schema.d.ts +932 -0
- package/dist/types/openapi-schema.js +151 -0
- package/dist/types/traffictype.d.ts +11 -0
- package/dist/types/traffictype.js +13 -0
- package/dist/types/urn.d.ts +1 -0
- package/dist/types/urn.js +2 -0
- package/dist/types/util-types.d.ts +11 -0
- package/dist/types/util-types.js +2 -0
- package/dist/types/validator.d.ts +4 -0
- package/dist/types/validator.js +9 -0
- package/dist/utils/api-model.d.ts +51 -0
- package/dist/utils/api-model.js +118 -0
- package/dist/utils/base64.d.ts +34 -0
- package/dist/utils/base64.js +53 -0
- package/dist/utils/date-utils.d.ts +27 -0
- package/dist/utils/date-utils.js +45 -0
- package/dist/utils/geojson-types.d.ts +14 -0
- package/dist/utils/geojson-types.js +15 -0
- package/dist/utils/geometry.d.ts +44 -0
- package/dist/utils/geometry.js +154 -0
- package/dist/utils/lambda-proxy-event.d.ts +9 -0
- package/dist/utils/lambda-proxy-event.js +31 -0
- package/dist/utils/logging.d.ts +40 -0
- package/dist/utils/logging.js +88 -0
- package/dist/utils/retry.d.ts +33 -0
- package/dist/utils/retry.js +135 -0
- package/dist/utils/slack.d.ts +5 -0
- package/dist/utils/slack.js +24 -0
- package/dist/utils/stop-watch.d.ts +46 -0
- package/dist/utils/stop-watch.js +114 -0
- package/dist/utils/utils.d.ts +95 -0
- package/dist/utils/utils.js +178 -0
- package/dist/utils/zod-utils.d.ts +27 -0
- package/dist/utils/zod-utils.js +57 -0
- package/package.json +30 -28
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as geoJsonValidator from "geojson-validation";
|
|
2
|
+
import { logger } from "../aws/runtime/dt-logger-default.js";
|
|
3
|
+
export const SRID_WGS84 = 4326;
|
|
4
|
+
/**
|
|
5
|
+
* Creates WKT geometry from GeoJSON geometry
|
|
6
|
+
* @param geometry GeoJson geometry to convert to WKT
|
|
7
|
+
*/
|
|
8
|
+
export function createGeometry(geometry) {
|
|
9
|
+
if (geometry.type === "LineString") {
|
|
10
|
+
const coordinates = linestring(geometry.coordinates);
|
|
11
|
+
return `LINESTRING(${coordinates})`;
|
|
12
|
+
}
|
|
13
|
+
else if (geometry.type === "Point") {
|
|
14
|
+
const coordinates = coordinatePair(geometry.coordinates);
|
|
15
|
+
return `POINT(${coordinates})`;
|
|
16
|
+
}
|
|
17
|
+
else if (geometry.type === "Polygon") {
|
|
18
|
+
const coordinates = polygon(geometry.coordinates);
|
|
19
|
+
return `POLYGON(${coordinates})`;
|
|
20
|
+
}
|
|
21
|
+
else if (geometry.type === "MultiPolygon") {
|
|
22
|
+
const coordinates = multiPolygon(geometry.coordinates);
|
|
23
|
+
return `MULTIPOLYGON(${coordinates})`;
|
|
24
|
+
}
|
|
25
|
+
logger.error({
|
|
26
|
+
method: "Geometry.createGeometry",
|
|
27
|
+
message: `Unsupported locationType ${geometry.type}`,
|
|
28
|
+
});
|
|
29
|
+
return "POLYGON EMPTY";
|
|
30
|
+
}
|
|
31
|
+
function linestring(coordinates) {
|
|
32
|
+
return coordinates.map((c) => coordinatePair(c)).join(",");
|
|
33
|
+
}
|
|
34
|
+
function polygon(coordinates) {
|
|
35
|
+
const list = coordinates.map((c) => linestring(c)).join(",");
|
|
36
|
+
return `(${list})`;
|
|
37
|
+
}
|
|
38
|
+
function multiPolygon(coordinates) {
|
|
39
|
+
const list = coordinates.map((c) => polygon(c)).join(",");
|
|
40
|
+
return `(${list})`;
|
|
41
|
+
}
|
|
42
|
+
function coordinatePair(coordinate) {
|
|
43
|
+
return `${coordinate[0]} ${coordinate[1]}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a GeoJSON FeatureCollection from a list of GeoJSON features with a 'last updated' property.
|
|
47
|
+
* Geometry is nullable. According to the GeoJSON specification, if coordinates are unavailable,
|
|
48
|
+
* the value of geometry should be null.
|
|
49
|
+
* @param features List of Features
|
|
50
|
+
* @param lastUpdated Last updated date
|
|
51
|
+
*/
|
|
52
|
+
export function createFeatureCollection(features, lastUpdated) {
|
|
53
|
+
return {
|
|
54
|
+
type: "FeatureCollection",
|
|
55
|
+
lastUpdated: lastUpdated,
|
|
56
|
+
features: features,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function isValidGeoJson(json) {
|
|
60
|
+
// Tests complain about this method returning type string[] which is obviously wrong. Therefore, this casting.
|
|
61
|
+
return geoJsonValidator.valid(json);
|
|
62
|
+
}
|
|
63
|
+
export function isFeatureCollection(json) {
|
|
64
|
+
// Tests complain about this method returning type string[] which is obviously wrong. Therefore, this casting.
|
|
65
|
+
return geoJsonValidator.isFeatureCollection(json);
|
|
66
|
+
}
|
|
67
|
+
const DEGREES_TO_RADIANS = 0.017453292519943295; // = Math.PI / 180
|
|
68
|
+
const EARTH_RADIUS_KM = 6371;
|
|
69
|
+
/**
|
|
70
|
+
* Returns the distance between two WGS84 points in kilometers. Doesn't take in account altitude.
|
|
71
|
+
* Based on the following Stack Overflow question:
|
|
72
|
+
* http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
|
|
73
|
+
* which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
|
|
74
|
+
* @param fromXLon first point longitude
|
|
75
|
+
* @param fromYLat first point latitude
|
|
76
|
+
* @param toXLon second point longitude
|
|
77
|
+
* @param toYLat second point latitude
|
|
78
|
+
*/
|
|
79
|
+
function distanceBetweenWGS84PointsInKm(fromXLon, fromYLat, toXLon, toYLat) {
|
|
80
|
+
const diffLat = toRadians(toYLat - fromYLat);
|
|
81
|
+
const diffLon = toRadians(toXLon - fromXLon);
|
|
82
|
+
const a = Math.sin(diffLat / 2) * Math.sin(diffLat / 2) +
|
|
83
|
+
Math.cos(toRadians(fromYLat)) *
|
|
84
|
+
Math.cos(toRadians(toYLat)) *
|
|
85
|
+
Math.sin(diffLon / 2) *
|
|
86
|
+
Math.sin(diffLon / 2);
|
|
87
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
88
|
+
return EARTH_RADIUS_KM * c;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns the distance between two WGS84 GeoJSON positions in kilometers. Doesn't take in account altitude.
|
|
92
|
+
* Based on the following Stack Overflow question:
|
|
93
|
+
* http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
|
|
94
|
+
* which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
|
|
95
|
+
* @param pos1 first position
|
|
96
|
+
* @param pos2 second position
|
|
97
|
+
*/
|
|
98
|
+
export function distanceBetweenPositionsInKm(pos1, pos2) {
|
|
99
|
+
const [pos10, pos11] = pos1;
|
|
100
|
+
const [pos20, pos21] = pos2;
|
|
101
|
+
if (pos1.length > 3 ||
|
|
102
|
+
pos2.length > 3 ||
|
|
103
|
+
!pos10 ||
|
|
104
|
+
!pos11 ||
|
|
105
|
+
!pos20 ||
|
|
106
|
+
!pos21) {
|
|
107
|
+
throw Error(`Illegal Positions ${pos1.toString()} and ${pos2.toString()}. Both must have length between 2 or 3.`);
|
|
108
|
+
}
|
|
109
|
+
return distanceBetweenWGS84PointsInKm(pos10, pos11, pos20, pos21);
|
|
110
|
+
}
|
|
111
|
+
export function areDistinctPositions(previous, next) {
|
|
112
|
+
return previous[0] !== next[0] || previous[1] !== next[1];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Calculates distance between two GeoJSON points (WGS84)
|
|
116
|
+
* @param pos1
|
|
117
|
+
* @param pos2
|
|
118
|
+
*/
|
|
119
|
+
export function distanceBetweenPositionsInM(pos1, pos2) {
|
|
120
|
+
return distanceBetweenPositionsInKm(pos1, pos2) * 1000; // km -> m
|
|
121
|
+
}
|
|
122
|
+
export function createGmlLineString(geometry, srsName = "EPSG:4326") {
|
|
123
|
+
const posList = createPosList(geometry);
|
|
124
|
+
return {
|
|
125
|
+
srsName,
|
|
126
|
+
posList,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function createPosList(geometry) {
|
|
130
|
+
if (geometry.type === "Point") {
|
|
131
|
+
return positionToList(geometry.coordinates);
|
|
132
|
+
}
|
|
133
|
+
else if (geometry.type === "LineString") {
|
|
134
|
+
return lineStringToList(geometry.coordinates);
|
|
135
|
+
}
|
|
136
|
+
else if (geometry.type === "Polygon") {
|
|
137
|
+
return polygonToList(geometry.coordinates);
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`unknown geometry type ${JSON.stringify(geometry)}`);
|
|
140
|
+
}
|
|
141
|
+
function polygonToList(positions, precision = 8) {
|
|
142
|
+
return positions.map((p) => lineStringToList(p, precision)).join(" ");
|
|
143
|
+
}
|
|
144
|
+
function lineStringToList(positions, precision = 8) {
|
|
145
|
+
return positions.map((p) => positionToList(p, precision)).join(" ");
|
|
146
|
+
}
|
|
147
|
+
export function positionToList(position, precision = 8) {
|
|
148
|
+
return position.map((n) => n.toPrecision(precision)).join(" ");
|
|
149
|
+
}
|
|
150
|
+
// Converts numeric degrees to radians
|
|
151
|
+
function toRadians(angdeg) {
|
|
152
|
+
return angdeg * DEGREES_TO_RADIANS;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { APIGatewayProxyEvent } from "aws-lambda";
|
|
2
|
+
/**
|
|
3
|
+
* Parses query parameters from an APIGatewayProxyEvent, allowing certain fields to always be treated as arrays (multiValueQueryStringParameters).
|
|
4
|
+
* As APIGatewayProxyEvent can have both single and multi-value query parameters, this function merges them appropriately mixed in both variables.
|
|
5
|
+
* e.g. multiValueQueryStringParameters contains always values from queryStringParameters.
|
|
6
|
+
* @param event APIGatewayProxyEvent from lambda proxy integration handler
|
|
7
|
+
* @param multiValueQueryParameters fields that are multi-value query parameters
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseQueryParams<T extends Record<string, unknown>>(event: APIGatewayProxyEvent, multiValueQueryParameters?: readonly string[]): T;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses query parameters from an APIGatewayProxyEvent, allowing certain fields to always be treated as arrays (multiValueQueryStringParameters).
|
|
3
|
+
* As APIGatewayProxyEvent can have both single and multi-value query parameters, this function merges them appropriately mixed in both variables.
|
|
4
|
+
* e.g. multiValueQueryStringParameters contains always values from queryStringParameters.
|
|
5
|
+
* @param event APIGatewayProxyEvent from lambda proxy integration handler
|
|
6
|
+
* @param multiValueQueryParameters fields that are multi-value query parameters
|
|
7
|
+
*/
|
|
8
|
+
export function parseQueryParams(event, multiValueQueryParameters = []) {
|
|
9
|
+
const multi = event.multiValueQueryStringParameters ?? {};
|
|
10
|
+
const single = event.queryStringParameters ?? {};
|
|
11
|
+
const keys = new Set([...Object.keys(single), ...Object.keys(multi)]);
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const key of keys) {
|
|
14
|
+
const multiVal = multi[key];
|
|
15
|
+
const singleVal = single[key];
|
|
16
|
+
let values;
|
|
17
|
+
if (Array.isArray(multiVal)) {
|
|
18
|
+
values = multiVal;
|
|
19
|
+
}
|
|
20
|
+
else if (typeof singleVal === "string") {
|
|
21
|
+
values = [singleVal];
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const forceArray = multiValueQueryParameters.includes(key);
|
|
27
|
+
result[key] = forceArray ? values : values.length > 1 ? values : values[0];
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=lambda-proxy-event.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DtLogger } from "../aws/runtime/dt-logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* Curried version of logException.
|
|
4
|
+
*
|
|
5
|
+
* @example <caption>Using default configuration</caption>
|
|
6
|
+
* Promise.reject(x).catch(createExceptionLogger())
|
|
7
|
+
*
|
|
8
|
+
* @example <caption>Providing external logger and requiring stack</caption>
|
|
9
|
+
* import {logger} from "@digitraffic/common/dist/aws/runtime/dt-logger-default"
|
|
10
|
+
* Promise.reject(x).catch(createExceptionLogger(logger, true))
|
|
11
|
+
*
|
|
12
|
+
* @param [logger=undefined] - DtLogger to use. If not given, will create a new instance of DtLogger
|
|
13
|
+
* @param [includeStack=false] - Define if the stack trace should be logged.
|
|
14
|
+
* @returns Logger that logs the error without rethrowing.
|
|
15
|
+
* @see {@link logException}
|
|
16
|
+
*/
|
|
17
|
+
export declare function createExceptionLogger(logger?: DtLogger | undefined, includeStack?: boolean): (error: unknown) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Log given exception with level ERROR to given logger.
|
|
20
|
+
*
|
|
21
|
+
* @param logger - DtLogger to use
|
|
22
|
+
* @param error - Error or string to log
|
|
23
|
+
* @param [includeStack=true] - Include stack in the message, default false
|
|
24
|
+
* @returns Logs the error without rethrowing
|
|
25
|
+
* @see {@link DtLogger.log}
|
|
26
|
+
* @see {@link createExceptionLogger} for a curried setup
|
|
27
|
+
*/
|
|
28
|
+
export declare function logException(logger: DtLogger, error: unknown, includeStack?: boolean): void;
|
|
29
|
+
/**
|
|
30
|
+
* Truncate string at the end if it exceeds max length.
|
|
31
|
+
* @param str
|
|
32
|
+
* @param max
|
|
33
|
+
*/
|
|
34
|
+
export declare function truncateEnd(str: string, max?: number): string;
|
|
35
|
+
/**
|
|
36
|
+
* Truncate string in the middle if it exceeds max length.
|
|
37
|
+
* @param str
|
|
38
|
+
* @param max
|
|
39
|
+
*/
|
|
40
|
+
export declare function truncateMiddle(str: string, max?: number): string;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { DtLogger } from "../aws/runtime/dt-logger.js";
|
|
2
|
+
import { getEnvVariableOrElse } from "./utils.js";
|
|
3
|
+
const functionName = getEnvVariableOrElse("AWS_LAMBDA_FUNCTION_NAME", "test");
|
|
4
|
+
/**
|
|
5
|
+
* Curried version of logException.
|
|
6
|
+
*
|
|
7
|
+
* @example <caption>Using default configuration</caption>
|
|
8
|
+
* Promise.reject(x).catch(createExceptionLogger())
|
|
9
|
+
*
|
|
10
|
+
* @example <caption>Providing external logger and requiring stack</caption>
|
|
11
|
+
* import {logger} from "@digitraffic/common/dist/aws/runtime/dt-logger-default"
|
|
12
|
+
* Promise.reject(x).catch(createExceptionLogger(logger, true))
|
|
13
|
+
*
|
|
14
|
+
* @param [logger=undefined] - DtLogger to use. If not given, will create a new instance of DtLogger
|
|
15
|
+
* @param [includeStack=false] - Define if the stack trace should be logged.
|
|
16
|
+
* @returns Logger that logs the error without rethrowing.
|
|
17
|
+
* @see {@link logException}
|
|
18
|
+
*/
|
|
19
|
+
export function createExceptionLogger(logger = undefined, includeStack = false) {
|
|
20
|
+
let thatLogger;
|
|
21
|
+
if (logger) {
|
|
22
|
+
thatLogger = logger;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
thatLogger = new DtLogger();
|
|
26
|
+
}
|
|
27
|
+
return (error) => {
|
|
28
|
+
logException(thatLogger, error, includeStack);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Log given exception with level ERROR to given logger.
|
|
33
|
+
*
|
|
34
|
+
* @param logger - DtLogger to use
|
|
35
|
+
* @param error - Error or string to log
|
|
36
|
+
* @param [includeStack=true] - Include stack in the message, default false
|
|
37
|
+
* @returns Logs the error without rethrowing
|
|
38
|
+
* @see {@link DtLogger.log}
|
|
39
|
+
* @see {@link createExceptionLogger} for a curried setup
|
|
40
|
+
*/
|
|
41
|
+
export function logException(logger, error, includeStack = false) {
|
|
42
|
+
const message = error instanceof Error
|
|
43
|
+
? error.message
|
|
44
|
+
: typeof error === "string"
|
|
45
|
+
? error
|
|
46
|
+
: JSON.stringify(error);
|
|
47
|
+
const stack = error instanceof Error && includeStack ? error.stack : undefined;
|
|
48
|
+
logger.error({
|
|
49
|
+
type: "Error",
|
|
50
|
+
method: `${functionName}.logException`,
|
|
51
|
+
message: `error=${message}`,
|
|
52
|
+
stack,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Truncate string at the end if it exceeds max length.
|
|
57
|
+
* @param str
|
|
58
|
+
* @param max
|
|
59
|
+
*/
|
|
60
|
+
export function truncateEnd(str, max = 1000) {
|
|
61
|
+
if (!str) {
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
const truncate = str.length - max;
|
|
65
|
+
const markerLen = `[TRUNCATED ${truncate} CHARS]`.length;
|
|
66
|
+
if (str.length <= max || truncate <= markerLen) {
|
|
67
|
+
return str;
|
|
68
|
+
}
|
|
69
|
+
return `${str.slice(0, max).trim()} [TRUNCATED ${str.length - max} CHARS]`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Truncate string in the middle if it exceeds max length.
|
|
73
|
+
* @param str
|
|
74
|
+
* @param max
|
|
75
|
+
*/
|
|
76
|
+
export function truncateMiddle(str, max = 1000) {
|
|
77
|
+
if (!str) {
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
const truncate = str.length - max;
|
|
81
|
+
const markerLen = `[TRUNCATED ${truncate} CHARS]`.length;
|
|
82
|
+
if (str.length <= max || truncate <= markerLen) {
|
|
83
|
+
return str;
|
|
84
|
+
}
|
|
85
|
+
const half = Math.floor(max / 2);
|
|
86
|
+
return `${str.slice(0, half).trim()} [TRUNCATED ${str.length - max} CHARS] ${str.slice(str.length - half).trim()}`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare enum RetryLogError {
|
|
2
|
+
LOG_ALL_AS_ERRORS = 0,
|
|
3
|
+
LOG_LAST_RETRY_AS_ERROR_OTHERS_AS_WARNS = 1,
|
|
4
|
+
NO_LOGGING = 2
|
|
5
|
+
}
|
|
6
|
+
export type TimeoutFn = (retryCount: number) => number;
|
|
7
|
+
export type RetryPredicate = (error: unknown) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Utility timeout functions for "retry" function.
|
|
10
|
+
*/
|
|
11
|
+
export declare const timeoutFunctions: {
|
|
12
|
+
noTimeout: (_: number) => number;
|
|
13
|
+
exponentialTimeout: (retryCount: number) => number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Utility retry predicates for "retry" function.
|
|
17
|
+
*/
|
|
18
|
+
export declare const retryPredicates: {
|
|
19
|
+
retryBasedOnStatusCode: (error: unknown) => boolean;
|
|
20
|
+
alwaysRetry: (_: unknown) => boolean;
|
|
21
|
+
};
|
|
22
|
+
export declare let retryCount: number;
|
|
23
|
+
/**
|
|
24
|
+
* Utility function for retrying async functions.
|
|
25
|
+
* @param asyncFn Function
|
|
26
|
+
* @param retries Amount of retries, default is 3. If set to <= 0, no retries will be done. Using non-finite numbers will throw an error. The maximum allowed retry count is 100.
|
|
27
|
+
* @param logError Logging options
|
|
28
|
+
* @param timeoutBetweenRetries A function that returns the timeout between retries in milliseconds. Default is a function returning 0. The function is called with the current retry count.
|
|
29
|
+
* @param retryPredicate A function that returns true if the error should be retried. Default is a function that always returns true. The function is called with the error object.
|
|
30
|
+
* @return Promise return value
|
|
31
|
+
*/
|
|
32
|
+
export declare function retry<T>(asyncFn: () => Promise<T>, retries?: number, logError?: RetryLogError, timeoutBetweenRetries?: TimeoutFn, retryPredicate?: RetryPredicate): Promise<T>;
|
|
33
|
+
export declare function retryRequest<T>(request: (...args: unknown[]) => Promise<T>, ...args: unknown[]): Promise<T>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { logger } from "../aws/runtime/dt-logger-default.js";
|
|
2
|
+
import { AsyncTimeoutError } from "../types/async-timeout-error.js";
|
|
3
|
+
import { HttpError } from "../types/http-error.js";
|
|
4
|
+
export var RetryLogError;
|
|
5
|
+
(function (RetryLogError) {
|
|
6
|
+
RetryLogError[RetryLogError["LOG_ALL_AS_ERRORS"] = 0] = "LOG_ALL_AS_ERRORS";
|
|
7
|
+
RetryLogError[RetryLogError["LOG_LAST_RETRY_AS_ERROR_OTHERS_AS_WARNS"] = 1] = "LOG_LAST_RETRY_AS_ERROR_OTHERS_AS_WARNS";
|
|
8
|
+
RetryLogError[RetryLogError["NO_LOGGING"] = 2] = "NO_LOGGING";
|
|
9
|
+
})(RetryLogError || (RetryLogError = {}));
|
|
10
|
+
/**
|
|
11
|
+
* Utility timeout functions for "retry" function.
|
|
12
|
+
*/
|
|
13
|
+
export const timeoutFunctions = (() => ({
|
|
14
|
+
noTimeout: (_) => {
|
|
15
|
+
return 0;
|
|
16
|
+
},
|
|
17
|
+
exponentialTimeout: (retryCount) => {
|
|
18
|
+
return 2 ** retryCount * 1000;
|
|
19
|
+
},
|
|
20
|
+
}))();
|
|
21
|
+
/**
|
|
22
|
+
* Utility retry predicates for "retry" function.
|
|
23
|
+
*/
|
|
24
|
+
export const retryPredicates = (() => {
|
|
25
|
+
const retryStatusCodes = new Set([
|
|
26
|
+
// service might return 403 for no apparent reason
|
|
27
|
+
403,
|
|
28
|
+
// Opensearch responds 429, if you make too many requests too fast
|
|
29
|
+
429,
|
|
30
|
+
]);
|
|
31
|
+
return {
|
|
32
|
+
retryBasedOnStatusCode: (error) => {
|
|
33
|
+
if (error instanceof HttpError) {
|
|
34
|
+
return retryStatusCodes.has(error.statusCode);
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
},
|
|
38
|
+
alwaysRetry: (_) => {
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
function readPossibleErrorMessage(error) {
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
return error.message;
|
|
46
|
+
}
|
|
47
|
+
return "Something else than an Error object was thrown";
|
|
48
|
+
}
|
|
49
|
+
// Tämä muuttuja on testejä varten määritelty täällä.
|
|
50
|
+
export let retryCount = 0;
|
|
51
|
+
async function retryRecursive(asyncFn, retries, retryCountInj, logError, timeoutBetweenRetries, retryPredicate) {
|
|
52
|
+
const asyncFnTimeout = 30 * 60 * 1000; // 30 minutes
|
|
53
|
+
if (!Number.isFinite(retries)) {
|
|
54
|
+
throw new Error("Only finite numbers are supported");
|
|
55
|
+
}
|
|
56
|
+
if (retries > 100) {
|
|
57
|
+
throw new Error("Exceeded the maximum retry count of 100");
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
// NOTE, a Promise cannot be cancelled. So if the asyncFn calls multiple async/await paris and the first one takes 31 minutes to complete,
|
|
61
|
+
// then the rest of async/await pairs will be called even though AsyncTimeoutError is already thrown.
|
|
62
|
+
const result = await Promise.race([
|
|
63
|
+
asyncFn(),
|
|
64
|
+
new Promise((_resolve, reject) => setTimeout(() => reject(new AsyncTimeoutError()), asyncFnTimeout)),
|
|
65
|
+
]);
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const remainingRetries = retries - 1;
|
|
70
|
+
if (logError === RetryLogError.LOG_ALL_AS_ERRORS) {
|
|
71
|
+
logger.error({
|
|
72
|
+
message: readPossibleErrorMessage(error),
|
|
73
|
+
method: "retry.retryRecursive",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else if (logError === RetryLogError.LOG_LAST_RETRY_AS_ERROR_OTHERS_AS_WARNS) {
|
|
77
|
+
if (remainingRetries < 0) {
|
|
78
|
+
logger.error({
|
|
79
|
+
message: readPossibleErrorMessage(error),
|
|
80
|
+
method: "retry.retryRecursive",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
logger.warn({
|
|
85
|
+
message: readPossibleErrorMessage(error),
|
|
86
|
+
method: "retry.retryRecursive",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (remainingRetries < 0) {
|
|
91
|
+
logger.warn({
|
|
92
|
+
message: "No retries left",
|
|
93
|
+
method: "retry.retryRecursive",
|
|
94
|
+
});
|
|
95
|
+
throw new Error("No retries left");
|
|
96
|
+
}
|
|
97
|
+
logger.warn({
|
|
98
|
+
message: `Retrying with remaining retries ${remainingRetries}`,
|
|
99
|
+
method: "retry.retryRecursive",
|
|
100
|
+
});
|
|
101
|
+
if (retryPredicate(error)) {
|
|
102
|
+
retryCountInj++;
|
|
103
|
+
retryCount = retryCountInj;
|
|
104
|
+
const milliseconds = timeoutBetweenRetries(retryCountInj);
|
|
105
|
+
if (milliseconds > 0) {
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
107
|
+
}
|
|
108
|
+
return retryRecursive(asyncFn, remainingRetries, retryCountInj, logError, timeoutBetweenRetries, retryPredicate);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
throw new Error("Retry predicate failed");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Utility function for retrying async functions.
|
|
117
|
+
* @param asyncFn Function
|
|
118
|
+
* @param retries Amount of retries, default is 3. If set to <= 0, no retries will be done. Using non-finite numbers will throw an error. The maximum allowed retry count is 100.
|
|
119
|
+
* @param logError Logging options
|
|
120
|
+
* @param timeoutBetweenRetries A function that returns the timeout between retries in milliseconds. Default is a function returning 0. The function is called with the current retry count.
|
|
121
|
+
* @param retryPredicate A function that returns true if the error should be retried. Default is a function that always returns true. The function is called with the error object.
|
|
122
|
+
* @return Promise return value
|
|
123
|
+
*/
|
|
124
|
+
export async function retry(asyncFn, retries = 3, logError = RetryLogError.LOG_LAST_RETRY_AS_ERROR_OTHERS_AS_WARNS, timeoutBetweenRetries = timeoutFunctions.noTimeout, retryPredicate = retryPredicates.alwaysRetry) {
|
|
125
|
+
retryCount = 0;
|
|
126
|
+
return retryRecursive(asyncFn, retries, 0, logError, timeoutBetweenRetries, retryPredicate);
|
|
127
|
+
}
|
|
128
|
+
function wrapArgsToFn(fn, ...args) {
|
|
129
|
+
return async () => await fn(...args);
|
|
130
|
+
}
|
|
131
|
+
export async function retryRequest(request, ...args) {
|
|
132
|
+
const asyncFn = wrapArgsToFn(request, ...args);
|
|
133
|
+
return retry(asyncFn, 5, RetryLogError.LOG_LAST_RETRY_AS_ERROR_OTHERS_AS_WARNS, timeoutFunctions.exponentialTimeout, retryPredicates.retryBasedOnStatusCode);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import ky from "ky";
|
|
2
|
+
import { logger } from "../aws/runtime/dt-logger-default.js";
|
|
3
|
+
import { logException } from "./logging.js";
|
|
4
|
+
export class SlackApi {
|
|
5
|
+
url;
|
|
6
|
+
constructor(url) {
|
|
7
|
+
this.url = url;
|
|
8
|
+
}
|
|
9
|
+
async notify(text) {
|
|
10
|
+
try {
|
|
11
|
+
logger.info({
|
|
12
|
+
method: "SlackApi.notify",
|
|
13
|
+
message: "Sending slack notification",
|
|
14
|
+
});
|
|
15
|
+
await ky.post(this.url, {
|
|
16
|
+
json: { text: text },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
logException(logger, error);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=slack.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { DtLogger, LoggerMethodType } from "../aws/runtime/dt-logger.js";
|
|
2
|
+
export interface TaskPeriod {
|
|
3
|
+
startTime: number;
|
|
4
|
+
endTime?: number;
|
|
5
|
+
duration?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface TaskRecord {
|
|
8
|
+
taskName: string;
|
|
9
|
+
periods: TaskPeriod[];
|
|
10
|
+
totalDuration: number;
|
|
11
|
+
isRunning: boolean;
|
|
12
|
+
}
|
|
13
|
+
export type ReadonlyTaskRecord = Readonly<{
|
|
14
|
+
taskName: string;
|
|
15
|
+
periods: ReadonlyArray<Readonly<TaskPeriod>>;
|
|
16
|
+
totalDuration: number;
|
|
17
|
+
isRunning: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
export declare class StopWatch {
|
|
20
|
+
private tasks;
|
|
21
|
+
private static readonly DEFAULT_TASK_NAME;
|
|
22
|
+
static createStarted(taskName?: string): StopWatch;
|
|
23
|
+
getDuration(taskName?: string): number;
|
|
24
|
+
start(taskName?: string): this;
|
|
25
|
+
stop(taskName?: string): this;
|
|
26
|
+
/**
|
|
27
|
+
* If task is running, records does not include duration of current period.
|
|
28
|
+
* @param taskName
|
|
29
|
+
*/
|
|
30
|
+
getTask(taskName: string): ReadonlyTaskRecord | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* If task is running, records does not include duration of current period.
|
|
33
|
+
*/
|
|
34
|
+
getTasks(): ReadonlyTaskRecord[];
|
|
35
|
+
/**
|
|
36
|
+
* Removes one or all tasks.
|
|
37
|
+
* @param taskName if given resets only that task otherwise clears all.
|
|
38
|
+
*/
|
|
39
|
+
reset(taskName?: string): this;
|
|
40
|
+
/**
|
|
41
|
+
* Logs all tasks and their durations. If there is also default task, logs that too with <code>task: method</code>.
|
|
42
|
+
* @param method
|
|
43
|
+
* @param level
|
|
44
|
+
*/
|
|
45
|
+
logTasks(method: LoggerMethodType, level?: keyof Pick<DtLogger, "debug" | "info" | "warn" | "error">): void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { logger } from "../aws/runtime/dt-logger-default.js";
|
|
2
|
+
export class StopWatch {
|
|
3
|
+
tasks = new Map();
|
|
4
|
+
static DEFAULT_TASK_NAME = "DEFAULT_INTERNAL_TASK";
|
|
5
|
+
static createStarted(taskName = StopWatch.DEFAULT_TASK_NAME) {
|
|
6
|
+
const sw = new StopWatch();
|
|
7
|
+
sw.start(taskName);
|
|
8
|
+
return sw;
|
|
9
|
+
}
|
|
10
|
+
getDuration(taskName = StopWatch.DEFAULT_TASK_NAME) {
|
|
11
|
+
const task = this.getTask(taskName);
|
|
12
|
+
if (!task) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
let duration = task.totalDuration;
|
|
16
|
+
if (task.isRunning) {
|
|
17
|
+
// If the task is running, last period is ongoing
|
|
18
|
+
const currentPeriod = task.periods[task.periods.length - 1];
|
|
19
|
+
if (currentPeriod) {
|
|
20
|
+
duration += Date.now() - currentPeriod.startTime;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return duration;
|
|
24
|
+
}
|
|
25
|
+
start(taskName = StopWatch.DEFAULT_TASK_NAME) {
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
let task = this.tasks.get(taskName);
|
|
28
|
+
if (!task) {
|
|
29
|
+
// create a new one
|
|
30
|
+
task = {
|
|
31
|
+
taskName,
|
|
32
|
+
periods: [],
|
|
33
|
+
totalDuration: 0,
|
|
34
|
+
isRunning: false,
|
|
35
|
+
};
|
|
36
|
+
this.tasks.set(taskName, task);
|
|
37
|
+
}
|
|
38
|
+
// if already running, stop it and start new
|
|
39
|
+
if (task.isRunning) {
|
|
40
|
+
this.stop(taskName);
|
|
41
|
+
}
|
|
42
|
+
// start a new period
|
|
43
|
+
task.periods.push({ startTime: now });
|
|
44
|
+
task.isRunning = true;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
stop(taskName = StopWatch.DEFAULT_TASK_NAME) {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
const task = this.tasks.get(taskName);
|
|
50
|
+
if (!task) {
|
|
51
|
+
throw new Error(`Task "${taskName}" not found`);
|
|
52
|
+
}
|
|
53
|
+
if (!task.isRunning) {
|
|
54
|
+
return this; // nothing to stop
|
|
55
|
+
}
|
|
56
|
+
const currentPeriod = task.periods[task.periods.length - 1];
|
|
57
|
+
if (!currentPeriod || currentPeriod.endTime) {
|
|
58
|
+
throw new Error(`Task "${taskName}" is not currently running`);
|
|
59
|
+
}
|
|
60
|
+
currentPeriod.endTime = now;
|
|
61
|
+
currentPeriod.duration = now - currentPeriod.startTime;
|
|
62
|
+
task.totalDuration += currentPeriod.duration;
|
|
63
|
+
task.isRunning = false;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* If task is running, records does not include duration of current period.
|
|
68
|
+
* @param taskName
|
|
69
|
+
*/
|
|
70
|
+
getTask(taskName) {
|
|
71
|
+
return this.tasks.get(taskName);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* If task is running, records does not include duration of current period.
|
|
75
|
+
*/
|
|
76
|
+
getTasks() {
|
|
77
|
+
return Array.from(this.tasks.values()).filter((task) => task.taskName !== StopWatch.DEFAULT_TASK_NAME);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Removes one or all tasks.
|
|
81
|
+
* @param taskName if given resets only that task otherwise clears all.
|
|
82
|
+
*/
|
|
83
|
+
reset(taskName) {
|
|
84
|
+
if (taskName) {
|
|
85
|
+
this.tasks.delete(taskName);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
this.tasks.clear();
|
|
89
|
+
}
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Logs all tasks and their durations. If there is also default task, logs that too with <code>task: method</code>.
|
|
94
|
+
* @param method
|
|
95
|
+
* @param level
|
|
96
|
+
*/
|
|
97
|
+
logTasks(method, level = "info") {
|
|
98
|
+
for (const task of this.getTasks()) {
|
|
99
|
+
logger[level]({
|
|
100
|
+
method,
|
|
101
|
+
customTask: task.taskName,
|
|
102
|
+
tookMs: this.getDuration(task.taskName),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (this.getTask(StopWatch.DEFAULT_TASK_NAME)) {
|
|
106
|
+
logger[level]({
|
|
107
|
+
method,
|
|
108
|
+
customTask: method,
|
|
109
|
+
tookMs: this.getDuration(StopWatch.DEFAULT_TASK_NAME),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=stop-watch.js.map
|