@digitraffic/common 2026.5.27-1 → 2026.6.29-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,152 @@
1
+ import { afterEach, describe, expect, test, vi } from "vitest";
2
+ import { logger } from "../../aws/runtime/dt-logger-default.js";
3
+ import { logLeadTime, logLeadTimes } from "../../utils/lead-time-logging.js";
4
+ describe("lead-time-logging", () => {
5
+ afterEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+ test("logLeadTime logs expected payload", () => {
9
+ const infoSpy = vi
10
+ .spyOn(logger, "info")
11
+ .mockImplementation(() => undefined);
12
+ const errorSpy = vi
13
+ .spyOn(logger, "error")
14
+ .mockImplementation(() => undefined);
15
+ logLeadTime("lead-time", "test-target", 123);
16
+ expect(infoSpy).toHaveBeenCalledTimes(1);
17
+ expect(infoSpy).toHaveBeenCalledWith({
18
+ method: "LeadTimeLogging.logLeadTime",
19
+ customLeadTime: true,
20
+ customName: "lead-time",
21
+ customTarget: "test-target",
22
+ tookMs: 123,
23
+ });
24
+ expect(errorSpy).toHaveBeenCalledTimes(0);
25
+ });
26
+ test("logLeadTime merges extra fields", () => {
27
+ const infoSpy = vi
28
+ .spyOn(logger, "info")
29
+ .mockImplementation(() => undefined);
30
+ logLeadTime("mqtt-time", "mqtt", 88, {
31
+ customSource: "mqtt",
32
+ customRetriesCount: 2,
33
+ });
34
+ expect(infoSpy).toHaveBeenCalledTimes(1);
35
+ expect(infoSpy).toHaveBeenCalledWith({
36
+ method: "LeadTimeLogging.logLeadTime",
37
+ customLeadTime: true,
38
+ customName: "mqtt-time",
39
+ customTarget: "mqtt",
40
+ tookMs: 88,
41
+ customSource: "mqtt",
42
+ customRetriesCount: 2,
43
+ });
44
+ });
45
+ test("logLeadTime logs error if logger.info throws", () => {
46
+ const infoError = new Error("boom");
47
+ vi.spyOn(logger, "info").mockImplementation(() => {
48
+ throw infoError;
49
+ });
50
+ const errorSpy = vi
51
+ .spyOn(logger, "error")
52
+ .mockImplementation(() => undefined);
53
+ logLeadTime("process-time", "target", 10);
54
+ expect(errorSpy).toHaveBeenCalledTimes(1);
55
+ expect(errorSpy).toHaveBeenCalledWith({
56
+ method: "LeadTimeLogging.logLeadTime",
57
+ message: "Error logging lead time",
58
+ error: infoError,
59
+ });
60
+ });
61
+ test("logLeadTimes logs only lead-time when only leadTimeMs is safe", () => {
62
+ const infoSpy = vi
63
+ .spyOn(logger, "info")
64
+ .mockImplementation(() => undefined);
65
+ logLeadTimes({ target: "x", leadTimeMs: 10 });
66
+ expect(infoSpy).toHaveBeenCalledTimes(1);
67
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
68
+ method: "LeadTimeLogging.logLeadTime",
69
+ customLeadTime: true,
70
+ customName: "lead-time",
71
+ customTarget: "x",
72
+ tookMs: 10,
73
+ });
74
+ });
75
+ test("logLeadTimes logs only process-time when only processTimeMs is safe", () => {
76
+ const infoSpy = vi
77
+ .spyOn(logger, "info")
78
+ .mockImplementation(() => undefined);
79
+ logLeadTimes({ target: "x", processTimeMs: 20 });
80
+ expect(infoSpy).toHaveBeenCalledTimes(1);
81
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
82
+ method: "LeadTimeLogging.logLeadTime",
83
+ customLeadTime: true,
84
+ customName: "process-time",
85
+ customTarget: "x",
86
+ tookMs: 20,
87
+ });
88
+ });
89
+ test("logLeadTimes logs both in order with extra fields", () => {
90
+ const infoSpy = vi
91
+ .spyOn(logger, "info")
92
+ .mockImplementation(() => undefined);
93
+ const input = {
94
+ target: "device",
95
+ leadTimeMs: 11,
96
+ processTimeMs: 22,
97
+ extraFields: { customSource: "mqtt", customPartition: 3 },
98
+ };
99
+ logLeadTimes(input);
100
+ expect(infoSpy).toHaveBeenCalledTimes(2);
101
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
102
+ method: "LeadTimeLogging.logLeadTime",
103
+ customLeadTime: true,
104
+ customName: "lead-time",
105
+ customTarget: "device",
106
+ tookMs: 11,
107
+ customSource: "mqtt",
108
+ customPartition: 3,
109
+ });
110
+ expect(infoSpy).toHaveBeenNthCalledWith(2, {
111
+ method: "LeadTimeLogging.logLeadTime",
112
+ customLeadTime: true,
113
+ customName: "process-time",
114
+ customTarget: "device",
115
+ tookMs: 22,
116
+ customSource: "mqtt",
117
+ customPartition: 3,
118
+ });
119
+ });
120
+ test("logLeadTimes ignores non-safe values", () => {
121
+ const infoSpy = vi
122
+ .spyOn(logger, "info")
123
+ .mockImplementation(() => undefined);
124
+ logLeadTimes({
125
+ target: "x",
126
+ leadTimeMs: 1.5,
127
+ processTimeMs: Number.MAX_SAFE_INTEGER + 1,
128
+ });
129
+ logLeadTimes({
130
+ target: "x",
131
+ leadTimeMs: Number.NaN,
132
+ processTimeMs: Infinity,
133
+ });
134
+ logLeadTimes({ target: "x" });
135
+ expect(infoSpy).toHaveBeenCalledTimes(0);
136
+ });
137
+ test("logLeadTimes logs negative safe integer values", () => {
138
+ const infoSpy = vi
139
+ .spyOn(logger, "info")
140
+ .mockImplementation(() => undefined);
141
+ logLeadTimes({ target: "x", leadTimeMs: -5 });
142
+ expect(infoSpy).toHaveBeenCalledTimes(1);
143
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
144
+ method: "LeadTimeLogging.logLeadTime",
145
+ customLeadTime: true,
146
+ customName: "lead-time",
147
+ customTarget: "x",
148
+ tookMs: -5,
149
+ });
150
+ });
151
+ });
152
+ //# sourceMappingURL=lead-time-logging.test.js.map
@@ -1,6 +1,5 @@
1
1
  import synthetics from "Synthetics";
2
2
  import { inDatabaseReadonly } from "../../../database/database.js";
3
- import { getEnvVariable } from "../../../utils/utils.js";
4
3
  import { logger } from "../../runtime/dt-logger-default.js";
5
4
  import { ProxyHolder } from "../../runtime/secrets/proxy-holder.js";
6
5
  import { RdsHolder } from "../../runtime/secrets/rds-holder.js";
@@ -66,10 +65,10 @@ export class DatabaseCountChecker {
66
65
  synthetics.getConfiguration().withFailedCanaryMetric(true);
67
66
  }
68
67
  static createForProxy() {
69
- return new DatabaseCountChecker(() => new ProxyHolder(getEnvVariable("SECRET_ID")).setCredentials());
68
+ return new DatabaseCountChecker(() => ProxyHolder.create().setCredentials());
70
69
  }
71
70
  static createForRds() {
72
- return new DatabaseCountChecker(() => new RdsHolder(getEnvVariable("SECRET_ID")).setCredentials());
71
+ return new DatabaseCountChecker(() => RdsHolder.create().setCredentials());
73
72
  }
74
73
  /**
75
74
  * Expect that the count is 1
@@ -1,9 +1,14 @@
1
+ import type { RdsProxySecret } from "./dbsecret.js";
2
+ import { SecretHolder } from "./secret-holder.js";
1
3
  /**
2
4
  * Holds credentials for RDS Proxy access.
3
5
  */
4
6
  export declare class ProxyHolder {
5
7
  private readonly secretHolder;
6
- constructor(secretId: string);
8
+ private constructor();
9
+ /** Creates a new instance of ProxyHolder from given SecretHolder. */
10
+ static create(secretHolder: SecretHolder<RdsProxySecret>): ProxyHolder;
11
+ /** Creates a new instance of ProxyHolder with a new default SecretHolder(using env variable SECRET_ID). */
7
12
  static create(): ProxyHolder;
8
13
  setCredentials(): Promise<void>;
9
14
  }
@@ -8,11 +8,13 @@ const RDS_PROXY_SECRET_KEYS = Object.values(RdsProxySecretKey);
8
8
  */
9
9
  export class ProxyHolder {
10
10
  secretHolder;
11
- constructor(secretId) {
12
- this.secretHolder = new SecretHolder(secretId, "", RDS_PROXY_SECRET_KEYS);
11
+ constructor(secretHolder) {
12
+ this.secretHolder = secretHolder;
13
13
  }
14
- static create() {
15
- return new ProxyHolder(getEnvVariable("SECRET_ID"));
14
+ static create(secretHolder) {
15
+ const holder = secretHolder ??
16
+ new SecretHolder(getEnvVariable("SECRET_ID"), "", RDS_PROXY_SECRET_KEYS);
17
+ return new ProxyHolder(holder);
16
18
  }
17
19
  async setCredentials() {
18
20
  const secret = await this.secretHolder.get();
@@ -1,9 +1,12 @@
1
+ import type { RdsSecret } from "./dbsecret.js";
2
+ import { SecretHolder } from "./secret-holder.js";
1
3
  /**
2
4
  * Holds credentials for RDS access.
3
5
  */
4
6
  export declare class RdsHolder {
5
7
  private readonly secretHolder;
6
- constructor(secretId: string);
8
+ private constructor();
9
+ static create(rdsHolder: SecretHolder<RdsSecret>): RdsHolder;
7
10
  static create(): RdsHolder;
8
11
  setCredentials(): Promise<void>;
9
12
  }
@@ -8,11 +8,13 @@ const RDS_SECRET_KEYS = Object.values(RdsSecretKey);
8
8
  */
9
9
  export class RdsHolder {
10
10
  secretHolder;
11
- constructor(secretId) {
12
- this.secretHolder = new SecretHolder(secretId, "", RDS_SECRET_KEYS);
11
+ constructor(secretHolder) {
12
+ this.secretHolder = secretHolder;
13
13
  }
14
- static create() {
15
- return new RdsHolder(getEnvVariable("SECRET_ID"));
14
+ static create(secretHolder) {
15
+ const holder = secretHolder ??
16
+ new SecretHolder(getEnvVariable("SECRET_ID"), "", RDS_SECRET_KEYS);
17
+ return new RdsHolder(holder);
16
18
  }
17
19
  async setCredentials() {
18
20
  const secret = await this.secretHolder.get();
@@ -0,0 +1,10 @@
1
+ import type { CustomParams } from "../aws/runtime/dt-logger.js";
2
+ export interface LeadTimeLogging {
3
+ readonly target: string;
4
+ readonly leadTimeMs?: number;
5
+ readonly processTimeMs?: number;
6
+ readonly extraFields?: CustomParams;
7
+ }
8
+ export type LeadTimeType = "lead-time" | "process-time" | "mqtt-time";
9
+ export declare function logLeadTime(name: LeadTimeType, target: string, tookMs: number, extraFields?: CustomParams): void;
10
+ export declare function logLeadTimes(ptl: LeadTimeLogging): void;
@@ -0,0 +1,33 @@
1
+ import { logger } from "../aws/runtime/dt-logger-default.js";
2
+ export function logLeadTime(name, target, tookMs, extraFields) {
3
+ const method = "LeadTimeLogging.logLeadTime";
4
+ try {
5
+ logger.info({
6
+ method,
7
+ customLeadTime: true,
8
+ customName: name,
9
+ customTarget: target,
10
+ tookMs,
11
+ ...(extraFields || {}),
12
+ });
13
+ }
14
+ catch (error) {
15
+ logger.error({
16
+ method,
17
+ message: "Error logging lead time",
18
+ error,
19
+ });
20
+ }
21
+ }
22
+ function isSafe(value) {
23
+ return Number.isSafeInteger(value);
24
+ }
25
+ export function logLeadTimes(ptl) {
26
+ if (isSafe(ptl.leadTimeMs)) {
27
+ logLeadTime("lead-time", ptl.target, ptl.leadTimeMs, ptl.extraFields);
28
+ }
29
+ if (isSafe(ptl.processTimeMs)) {
30
+ logLeadTime("process-time", ptl.target, ptl.processTimeMs, ptl.extraFields);
31
+ }
32
+ }
33
+ //# sourceMappingURL=lead-time-logging.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitraffic/common",
3
- "version": "2026.5.27-1",
3
+ "version": "2026.6.29-1",
4
4
  "private": false,
5
5
  "description": "",
6
6
  "repository": {
@@ -36,6 +36,7 @@
36
36
  "./dist/marine/id_utils": "./dist/marine/id_utils.js",
37
37
  "./dist/index": "./dist/index.js",
38
38
  "./dist/utils/api-model": "./dist/utils/api-model.js",
39
+ "./dist/utils/lead-time-logging": "./dist/utils/lead-time-logging.js",
39
40
  "./dist/utils/logging": "./dist/utils/logging.js",
40
41
  "./dist/utils/base64": "./dist/utils/base64.js",
41
42
  "./dist/utils/date-utils": "./dist/utils/date-utils.js",
@@ -126,7 +127,7 @@
126
127
  "@types/geojson-validation": "1.0.3",
127
128
  "@types/madge": "5.0.3",
128
129
  "@types/node": "24.12.4",
129
- "@vitest/coverage-v8": "4.1.6",
130
+ "@vitest/coverage-v8": "4.1.9",
130
131
  "aws-cdk-lib": "2.254.0",
131
132
  "change-case": "5.4.4",
132
133
  "constructs": "10.6.0",
@@ -144,7 +145,7 @@
144
145
  "sort-package-json": "3.6.1",
145
146
  "typescript": "5.9.3",
146
147
  "velocityjs": "2.1.6",
147
- "vitest": "4.1.6",
148
+ "vitest": "4.1.9",
148
149
  "zod": "4.4.3"
149
150
  },
150
151
  "peerDependencies": {