@zintrust/trace 0.4.83 → 0.4.84

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.
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@zintrust/trace",
3
- "version": "0.4.83",
4
- "buildDate": "2026-04-08T17:13:19.081Z",
3
+ "version": "0.4.84",
4
+ "buildDate": "2026-04-08T17:51:22.444Z",
5
5
  "buildEnvironment": {
6
6
  "node": "v22.22.1",
7
7
  "platform": "darwin",
8
8
  "arch": "arm64"
9
9
  },
10
10
  "git": {
11
- "commit": "3c792064",
11
+ "commit": "d4c31a0d",
12
12
  "branch": "release"
13
13
  },
14
14
  "package": {
@@ -22,8 +22,8 @@
22
22
  },
23
23
  "files": {
24
24
  "build-manifest.json": {
25
- "size": 14439,
26
- "sha256": "dab00c1ade5c0b5fe2b10b5eeeae31dfd9a017f198794e18e7c2b69cfb5560d8"
25
+ "size": 14440,
26
+ "sha256": "04b7ac17fd2a9abf208db4df6218eea2f97a4ce4e1dc6ce8d826036924e7ab84"
27
27
  },
28
28
  "cli-register.d.ts": {
29
29
  "size": 255,
@@ -79,7 +79,7 @@
79
79
  },
80
80
  "index.js": {
81
81
  "size": 3255,
82
- "sha256": "a293d38a9e56a2ab802f99143eb1eaebb18f854e610f29bc95878746ffe26326"
82
+ "sha256": "f95401dc3b5ad76937e32978770c9568cf90e453bb1e77d0ecc8611e664b5ce0"
83
83
  },
84
84
  "migrations/20260331000001_create_zin_trace_entries_table.d.ts": {
85
85
  "size": 304,
@@ -174,8 +174,8 @@
174
174
  "sha256": "5f49df97a830ad895653fa4a18b3a1b31ca4a5066d6f8150ee02dca013e16397"
175
175
  },
176
176
  "storage/TraceWriteDiagnostics.js": {
177
- "size": 4162,
178
- "sha256": "06ba6979f5053956f7a5f9ec8dc301864f36276a2c74b0bf63cf733ad7c5eac2"
177
+ "size": 6714,
178
+ "sha256": "398b2cb74e2e7278c6a3b5d29537e7a95581e0a1cb9fb5831f7ff13ac70805e4"
179
179
  },
180
180
  "storage/index.d.ts": {
181
181
  "size": 100,
@@ -6,19 +6,98 @@ const diagnosticsState = {
6
6
  lastLoggedAtByFingerprint: new Map(),
7
7
  totalFailures: 0,
8
8
  };
9
+ const asRecord = (value) => {
10
+ if (value === null || typeof value !== 'object')
11
+ return null;
12
+ return value;
13
+ };
14
+ const getAttachedErrorDetails = (error) => {
15
+ if (error instanceof Error && 'details' in error) {
16
+ const details = error.details;
17
+ if (details !== undefined)
18
+ return details;
19
+ }
20
+ const record = asRecord(error);
21
+ return record?.['details'];
22
+ };
23
+ const getTextValue = (value) => {
24
+ if (typeof value !== 'string')
25
+ return null;
26
+ const trimmed = value.trim();
27
+ return trimmed === '' ? null : trimmed;
28
+ };
29
+ const describeBodyDetails = (body) => {
30
+ const code = getTextValue(body['code']);
31
+ const message = getTextValue(body['message']);
32
+ if (code !== null && message !== null)
33
+ return `${code}: ${message}`;
34
+ if (code !== null)
35
+ return code;
36
+ if (message !== null)
37
+ return message;
38
+ return null;
39
+ };
40
+ const describeRecordDetails = (record) => {
41
+ const body = asRecord(record['body']);
42
+ if (body !== null) {
43
+ const describedBody = describeBodyDetails(body);
44
+ if (describedBody !== null)
45
+ return describedBody;
46
+ }
47
+ const nested = describeErrorDetails(record['details']);
48
+ if (nested !== null)
49
+ return nested;
50
+ const message = getTextValue(record['message']);
51
+ if (message !== null)
52
+ return message;
53
+ const code = getTextValue(record['code']);
54
+ if (code !== null)
55
+ return code;
56
+ return null;
57
+ };
58
+ const describeErrorDetails = (details) => {
59
+ const text = getTextValue(details);
60
+ if (text !== null)
61
+ return text;
62
+ const record = asRecord(details);
63
+ if (record === null)
64
+ return null;
65
+ return describeRecordDetails(record);
66
+ };
67
+ const withOptionalDetail = (context, errorDetails) => {
68
+ if (errorDetails === undefined)
69
+ return context;
70
+ return { ...context, errorDetails };
71
+ };
9
72
  const getErrorMessage = (error) => {
10
- if (error instanceof Error && error.message.trim() !== '')
11
- return error.message;
12
- if (typeof error === 'string' && error.trim() !== '')
13
- return error;
14
- try {
15
- const serialized = JSON.stringify(error);
16
- if (typeof serialized === 'string' && serialized !== '')
17
- return serialized;
73
+ let baseMessage = '';
74
+ if (error instanceof Error && error.message.trim() !== '') {
75
+ baseMessage = error.message;
76
+ }
77
+ else if (typeof error === 'string' && error.trim() !== '') {
78
+ baseMessage = error;
79
+ }
80
+ else {
81
+ try {
82
+ const serialized = JSON.stringify(error);
83
+ if (typeof serialized === 'string' && serialized !== '')
84
+ baseMessage = serialized;
85
+ }
86
+ catch {
87
+ // ignore serialization failures
88
+ }
18
89
  }
19
- catch {
20
- // ignore serialization failures
90
+ const detailsSummary = describeErrorDetails(getAttachedErrorDetails(error));
91
+ if (detailsSummary !== null &&
92
+ detailsSummary !== '' &&
93
+ baseMessage !== '' &&
94
+ !baseMessage.includes(detailsSummary)) {
95
+ return `${baseMessage} (${detailsSummary})`;
21
96
  }
97
+ if (baseMessage !== '')
98
+ return baseMessage;
99
+ if (detailsSummary !== null && detailsSummary !== '')
100
+ return detailsSummary;
22
101
  return 'Unknown trace storage error';
23
102
  };
24
103
  const buildFingerprint = (context) => {
@@ -32,25 +111,26 @@ const buildFingerprint = (context) => {
32
111
  const reportFailure = (logger, context) => {
33
112
  const now = Date.now();
34
113
  const errorMessage = getErrorMessage(context.error);
114
+ const errorDetails = getAttachedErrorDetails(context.error);
35
115
  const fingerprint = buildFingerprint(context);
36
116
  const lastLoggedAt = diagnosticsState.lastLoggedAtByFingerprint.get(fingerprint);
37
117
  diagnosticsState.degraded = true;
38
118
  diagnosticsState.lastErrorMessage = errorMessage;
39
119
  diagnosticsState.lastFailureAt = now;
40
120
  diagnosticsState.totalFailures += 1;
41
- if (!logger)
121
+ if (logger === undefined)
42
122
  return;
43
123
  if (typeof lastLoggedAt === 'number' && now - lastLoggedAt < LOG_WINDOW_MS)
44
124
  return;
45
125
  diagnosticsState.lastLoggedAtByFingerprint.set(fingerprint, now);
46
- logger.warn('[trace] Trace storage write degraded', {
126
+ logger.warn('[trace] Trace storage write degraded', withOptionalDetail({
47
127
  connectionName: context.connectionName,
48
128
  error: errorMessage,
49
129
  lastFailureAt: now,
50
130
  operation: context.operation,
51
131
  totalFailures: diagnosticsState.totalFailures,
52
132
  watcherType: context.watcherType ?? null,
53
- });
133
+ }, errorDetails));
54
134
  };
55
135
  const wrapStorageMethod = (method, describeFailure, connectionName, logger) => {
56
136
  return async (...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/trace",
3
- "version": "0.4.83",
3
+ "version": "0.4.84",
4
4
  "description": "Trace assistant for ZinTrust: logs requests, queries, exceptions, jobs, and more.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.0.0"
41
41
  },
42
42
  "peerDependencies": {
43
- "@zintrust/core": "^0.4.81"
43
+ "@zintrust/core": "^0.4.83"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
@@ -32,17 +32,104 @@ const diagnosticsState: TraceWriteDiagnosticsState = {
32
32
  totalFailures: 0,
33
33
  };
34
34
 
35
+ const asRecord = (value: unknown): Record<string, unknown> | null => {
36
+ if (value === null || typeof value !== 'object') return null;
37
+ return value as Record<string, unknown>;
38
+ };
39
+
40
+ const getAttachedErrorDetails = (error: unknown): unknown => {
41
+ if (error instanceof Error && 'details' in error) {
42
+ const details = (error as Error & { details?: unknown }).details;
43
+ if (details !== undefined) return details;
44
+ }
45
+
46
+ const record = asRecord(error);
47
+ return record?.['details'];
48
+ };
49
+
50
+ const getTextValue = (value: unknown): string | null => {
51
+ if (typeof value !== 'string') return null;
52
+
53
+ const trimmed = value.trim();
54
+ return trimmed === '' ? null : trimmed;
55
+ };
56
+
57
+ const describeBodyDetails = (body: Record<string, unknown>): string | null => {
58
+ const code = getTextValue(body['code']);
59
+ const message = getTextValue(body['message']);
60
+
61
+ if (code !== null && message !== null) return `${code}: ${message}`;
62
+ if (code !== null) return code;
63
+ if (message !== null) return message;
64
+
65
+ return null;
66
+ };
67
+
68
+ const describeRecordDetails = (record: Record<string, unknown>): string | null => {
69
+ const body = asRecord(record['body']);
70
+ if (body !== null) {
71
+ const describedBody = describeBodyDetails(body);
72
+ if (describedBody !== null) return describedBody;
73
+ }
74
+
75
+ const nested = describeErrorDetails(record['details']);
76
+ if (nested !== null) return nested;
77
+
78
+ const message = getTextValue(record['message']);
79
+ if (message !== null) return message;
80
+
81
+ const code = getTextValue(record['code']);
82
+ if (code !== null) return code;
83
+
84
+ return null;
85
+ };
86
+
87
+ const describeErrorDetails = (details: unknown): string | null => {
88
+ const text = getTextValue(details);
89
+ if (text !== null) return text;
90
+
91
+ const record = asRecord(details);
92
+ if (record === null) return null;
93
+ return describeRecordDetails(record);
94
+ };
95
+
96
+ const withOptionalDetail = (
97
+ context: Record<string, unknown>,
98
+ errorDetails: unknown
99
+ ): Record<string, unknown> => {
100
+ if (errorDetails === undefined) return context;
101
+ return { ...context, errorDetails };
102
+ };
103
+
35
104
  const getErrorMessage = (error: unknown): string => {
36
- if (error instanceof Error && error.message.trim() !== '') return error.message;
37
- if (typeof error === 'string' && error.trim() !== '') return error;
38
-
39
- try {
40
- const serialized = JSON.stringify(error);
41
- if (typeof serialized === 'string' && serialized !== '') return serialized;
42
- } catch {
43
- // ignore serialization failures
105
+ let baseMessage = '';
106
+ if (error instanceof Error && error.message.trim() !== '') {
107
+ baseMessage = error.message;
108
+ } else if (typeof error === 'string' && error.trim() !== '') {
109
+ baseMessage = error;
110
+ } else {
111
+ try {
112
+ const serialized = JSON.stringify(error);
113
+ if (typeof serialized === 'string' && serialized !== '') baseMessage = serialized;
114
+ } catch {
115
+ // ignore serialization failures
116
+ }
44
117
  }
45
118
 
119
+ const detailsSummary = describeErrorDetails(getAttachedErrorDetails(error));
120
+ if (
121
+ detailsSummary !== null &&
122
+ detailsSummary !== '' &&
123
+ baseMessage !== '' &&
124
+ !baseMessage.includes(detailsSummary)
125
+ ) {
126
+ return `${baseMessage} (${detailsSummary})`;
127
+ }
128
+
129
+ if (baseMessage !== '') return baseMessage;
130
+
131
+ if (detailsSummary !== null && detailsSummary !== '') return detailsSummary;
132
+
46
133
  return 'Unknown trace storage error';
47
134
  };
48
135
 
@@ -61,6 +148,7 @@ const reportFailure = (
61
148
  ): void => {
62
149
  const now = Date.now();
63
150
  const errorMessage = getErrorMessage(context.error);
151
+ const errorDetails = getAttachedErrorDetails(context.error);
64
152
  const fingerprint = buildFingerprint(context);
65
153
  const lastLoggedAt = diagnosticsState.lastLoggedAtByFingerprint.get(fingerprint);
66
154
 
@@ -69,18 +157,24 @@ const reportFailure = (
69
157
  diagnosticsState.lastFailureAt = now;
70
158
  diagnosticsState.totalFailures += 1;
71
159
 
72
- if (!logger) return;
160
+ if (logger === undefined) return;
73
161
  if (typeof lastLoggedAt === 'number' && now - lastLoggedAt < LOG_WINDOW_MS) return;
74
162
 
75
163
  diagnosticsState.lastLoggedAtByFingerprint.set(fingerprint, now);
76
- logger.warn('[trace] Trace storage write degraded', {
77
- connectionName: context.connectionName,
78
- error: errorMessage,
79
- lastFailureAt: now,
80
- operation: context.operation,
81
- totalFailures: diagnosticsState.totalFailures,
82
- watcherType: context.watcherType ?? null,
83
- });
164
+ logger.warn(
165
+ '[trace] Trace storage write degraded',
166
+ withOptionalDetail(
167
+ {
168
+ connectionName: context.connectionName,
169
+ error: errorMessage,
170
+ lastFailureAt: now,
171
+ operation: context.operation,
172
+ totalFailures: diagnosticsState.totalFailures,
173
+ watcherType: context.watcherType ?? null,
174
+ },
175
+ errorDetails
176
+ )
177
+ );
84
178
  };
85
179
 
86
180
  const wrapStorageMethod = <TArgs extends unknown[], TResult>(