@zintrust/trace 0.5.4 → 0.5.5
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.
|
@@ -22,58 +22,6 @@ const describeValueType = (value) => {
|
|
|
22
22
|
return 'null';
|
|
23
23
|
return typeof value;
|
|
24
24
|
};
|
|
25
|
-
const chooseLargerCandidate = (left, right) => {
|
|
26
|
-
if (left === null)
|
|
27
|
-
return right;
|
|
28
|
-
if (right === null)
|
|
29
|
-
return left;
|
|
30
|
-
return right.size > left.size ? right : left;
|
|
31
|
-
};
|
|
32
|
-
const fallbackCandidate = (value, path) => {
|
|
33
|
-
return path.length === 0 ? null : { path, size: serializedSize(value) };
|
|
34
|
-
};
|
|
35
|
-
const findLargestDroppablePathInArray = (value, path) => {
|
|
36
|
-
let best = null;
|
|
37
|
-
for (const [index, item] of value.entries()) {
|
|
38
|
-
best = chooseLargerCandidate(best, findLargestDroppablePath(item, [...path, index]));
|
|
39
|
-
}
|
|
40
|
-
return best ?? fallbackCandidate(value, path);
|
|
41
|
-
};
|
|
42
|
-
const findLargestDroppablePathInObject = (value, path) => {
|
|
43
|
-
let best = null;
|
|
44
|
-
for (const [key, entryValue] of Object.entries(value)) {
|
|
45
|
-
if (key === '__traceNotice')
|
|
46
|
-
continue;
|
|
47
|
-
best = chooseLargerCandidate(best, findLargestDroppablePath(entryValue, [...path, key]));
|
|
48
|
-
}
|
|
49
|
-
return best ?? fallbackCandidate(value, path);
|
|
50
|
-
};
|
|
51
|
-
const findLargestDroppablePath = (value, path = []) => {
|
|
52
|
-
if (Array.isArray(value))
|
|
53
|
-
return findLargestDroppablePathInArray(value, path);
|
|
54
|
-
if (typeof value === 'object' && value !== null) {
|
|
55
|
-
return findLargestDroppablePathInObject(value, path);
|
|
56
|
-
}
|
|
57
|
-
return fallbackCandidate(value, path);
|
|
58
|
-
};
|
|
59
|
-
const replaceAtPath = (value, path, replacement) => {
|
|
60
|
-
if (path.length === 0)
|
|
61
|
-
return replacement;
|
|
62
|
-
const [segment, ...rest] = path;
|
|
63
|
-
if (Array.isArray(value) && typeof segment === 'number') {
|
|
64
|
-
const next = value.slice();
|
|
65
|
-
next[segment] = replaceAtPath(next[segment], rest, replacement);
|
|
66
|
-
return next;
|
|
67
|
-
}
|
|
68
|
-
if (typeof value === 'object' && value !== null && typeof segment === 'string') {
|
|
69
|
-
const current = value;
|
|
70
|
-
return {
|
|
71
|
-
...current,
|
|
72
|
-
[segment]: replaceAtPath(current[segment], rest, replacement),
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
return value;
|
|
76
|
-
};
|
|
77
25
|
const compactValue = (value, depth) => {
|
|
78
26
|
if (depth >= DEFAULT_MAX_DEPTH) {
|
|
79
27
|
return DROPPED_FIELD_MESSAGE;
|
|
@@ -106,17 +54,28 @@ const compactValue = (value, depth) => {
|
|
|
106
54
|
return Object.fromEntries(compactedEntries);
|
|
107
55
|
};
|
|
108
56
|
const compactStructuredValueToBudget = (value) => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
:
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
57
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
const compacted = {
|
|
61
|
+
...value,
|
|
62
|
+
__traceNotice: COMPACTED_CONTENT_MESSAGE,
|
|
63
|
+
};
|
|
64
|
+
const topLevelCandidates = Object.entries(compacted)
|
|
65
|
+
.filter(([key]) => key !== '__traceNotice')
|
|
66
|
+
.map(([key, entryValue]) => ({ key, size: serializedSize(entryValue) }))
|
|
67
|
+
.sort((left, right) => right.size - left.size);
|
|
68
|
+
let droppedCount = 0;
|
|
69
|
+
for (const candidate of topLevelCandidates) {
|
|
70
|
+
if (serializedSize(compacted) <= DEFAULT_MAX_ENTRY_BYTES) {
|
|
118
71
|
break;
|
|
119
|
-
|
|
72
|
+
}
|
|
73
|
+
compacted[candidate.key] = DROPPED_FIELD_MESSAGE;
|
|
74
|
+
droppedCount += 1;
|
|
75
|
+
}
|
|
76
|
+
if (droppedCount > 0) {
|
|
77
|
+
compacted['__traceNotice'] =
|
|
78
|
+
`${COMPACTED_CONTENT_MESSAGE} ${String(droppedCount)} top-level field(s) were dropped.`;
|
|
120
79
|
}
|
|
121
80
|
return compacted;
|
|
122
81
|
};
|
|
@@ -158,23 +117,24 @@ const closePort = (port) => {
|
|
|
158
117
|
port.close();
|
|
159
118
|
}
|
|
160
119
|
};
|
|
161
|
-
const scheduleTask = (task) => {
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
channel.port1.onmessage = null;
|
|
166
|
-
closePort(channel.port1);
|
|
167
|
-
closePort(channel.port2);
|
|
168
|
-
void task().catch(() => undefined);
|
|
120
|
+
const scheduleTask = async (task) => {
|
|
121
|
+
return await new Promise((resolve, reject) => {
|
|
122
|
+
const runTask = () => {
|
|
123
|
+
void task().then(resolve).catch(reject);
|
|
169
124
|
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
125
|
+
if (typeof MessageChannel === 'function') {
|
|
126
|
+
const channel = new MessageChannel();
|
|
127
|
+
channel.port1.onmessage = () => {
|
|
128
|
+
channel.port1.onmessage = null;
|
|
129
|
+
closePort(channel.port1);
|
|
130
|
+
closePort(channel.port2);
|
|
131
|
+
runTask();
|
|
132
|
+
};
|
|
133
|
+
channel.port2.postMessage(undefined);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
Promise.resolve().then(runTask).catch(reject);
|
|
137
|
+
});
|
|
178
138
|
};
|
|
179
139
|
const getReplacementContent = (content) => {
|
|
180
140
|
return {
|
|
@@ -283,7 +243,7 @@ const startInternalDispatchWorker = (storage, config, runtime) => {
|
|
|
283
243
|
if (startedWorkerKeys.has(key))
|
|
284
244
|
return;
|
|
285
245
|
startedWorkerKeys.add(key);
|
|
286
|
-
scheduleTask(async () => {
|
|
246
|
+
void scheduleTask(async () => {
|
|
287
247
|
const workersApi = runtime?.queueWorkerApi ?? (await getQueueWorkerApi());
|
|
288
248
|
if (workersApi === null) {
|
|
289
249
|
startedWorkerKeys.delete(key);
|
|
@@ -323,10 +283,12 @@ const startInternalDispatchWorker = (storage, config, runtime) => {
|
|
|
323
283
|
ensureWorkerTimer(key, setInterval(() => {
|
|
324
284
|
void runWorker();
|
|
325
285
|
}, intervalMs));
|
|
286
|
+
}).catch(() => {
|
|
287
|
+
startedWorkerKeys.delete(key);
|
|
326
288
|
});
|
|
327
289
|
};
|
|
328
|
-
const dispatchWrite = (storage, config, entry, runtime) => {
|
|
329
|
-
scheduleTask(async () => {
|
|
290
|
+
const dispatchWrite = async (storage, config, entry, runtime) => {
|
|
291
|
+
await scheduleTask(async () => {
|
|
330
292
|
if (hasQueueDispatch(config)) {
|
|
331
293
|
const enqueued = await enqueueTraceDispatch(config, { operation: 'write', entry }, runtime);
|
|
332
294
|
if (enqueued)
|
|
@@ -335,8 +297,8 @@ const dispatchWrite = (storage, config, entry, runtime) => {
|
|
|
335
297
|
await persistWriteFallback(storage, entry);
|
|
336
298
|
});
|
|
337
299
|
};
|
|
338
|
-
const dispatchUpdate = (storage, config, uuid, patch, runtime) => {
|
|
339
|
-
scheduleTask(async () => {
|
|
300
|
+
const dispatchUpdate = async (storage, config, uuid, patch, runtime) => {
|
|
301
|
+
await scheduleTask(async () => {
|
|
340
302
|
if (hasQueueDispatch(config)) {
|
|
341
303
|
const enqueued = await enqueueTraceDispatch(config, { operation: 'update', uuid, patch }, runtime);
|
|
342
304
|
if (enqueued)
|
|
@@ -351,10 +313,10 @@ export const TraceContentBudget = Object.freeze({
|
|
|
351
313
|
return Object.freeze({
|
|
352
314
|
...storage,
|
|
353
315
|
writeEntry: async (entry) => {
|
|
354
|
-
dispatchWrite(storage, config, entry, runtime);
|
|
316
|
+
await dispatchWrite(storage, config, entry, runtime);
|
|
355
317
|
},
|
|
356
318
|
updateEntry: async (uuid, patch) => {
|
|
357
|
-
dispatchUpdate(storage, config, uuid, patch, runtime);
|
|
319
|
+
await dispatchUpdate(storage, config, uuid, patch, runtime);
|
|
358
320
|
},
|
|
359
321
|
});
|
|
360
322
|
},
|
package/package.json
CHANGED
|
@@ -28,87 +28,6 @@ const describeValueType = (value: unknown): string => {
|
|
|
28
28
|
return typeof value;
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
type TracePathSegment = string | number;
|
|
32
|
-
|
|
33
|
-
type TracePathCandidate = {
|
|
34
|
-
path: TracePathSegment[];
|
|
35
|
-
size: number;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const chooseLargerCandidate = (
|
|
39
|
-
left: TracePathCandidate | null,
|
|
40
|
-
right: TracePathCandidate | null
|
|
41
|
-
): TracePathCandidate | null => {
|
|
42
|
-
if (left === null) return right;
|
|
43
|
-
if (right === null) return left;
|
|
44
|
-
return right.size > left.size ? right : left;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const fallbackCandidate = (value: unknown, path: TracePathSegment[]): TracePathCandidate | null => {
|
|
48
|
-
return path.length === 0 ? null : { path, size: serializedSize(value) };
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const findLargestDroppablePathInArray = (
|
|
52
|
-
value: unknown[],
|
|
53
|
-
path: TracePathSegment[]
|
|
54
|
-
): TracePathCandidate | null => {
|
|
55
|
-
let best: TracePathCandidate | null = null;
|
|
56
|
-
|
|
57
|
-
for (const [index, item] of value.entries()) {
|
|
58
|
-
best = chooseLargerCandidate(best, findLargestDroppablePath(item, [...path, index]));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return best ?? fallbackCandidate(value, path);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const findLargestDroppablePathInObject = (
|
|
65
|
-
value: Record<string, unknown>,
|
|
66
|
-
path: TracePathSegment[]
|
|
67
|
-
): TracePathCandidate | null => {
|
|
68
|
-
let best: TracePathCandidate | null = null;
|
|
69
|
-
|
|
70
|
-
for (const [key, entryValue] of Object.entries(value)) {
|
|
71
|
-
if (key === '__traceNotice') continue;
|
|
72
|
-
best = chooseLargerCandidate(best, findLargestDroppablePath(entryValue, [...path, key]));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return best ?? fallbackCandidate(value, path);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const findLargestDroppablePath = (
|
|
79
|
-
value: unknown,
|
|
80
|
-
path: TracePathSegment[] = []
|
|
81
|
-
): TracePathCandidate | null => {
|
|
82
|
-
if (Array.isArray(value)) return findLargestDroppablePathInArray(value, path);
|
|
83
|
-
if (typeof value === 'object' && value !== null) {
|
|
84
|
-
return findLargestDroppablePathInObject(value as Record<string, unknown>, path);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return fallbackCandidate(value, path);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const replaceAtPath = (value: unknown, path: TracePathSegment[], replacement: unknown): unknown => {
|
|
91
|
-
if (path.length === 0) return replacement;
|
|
92
|
-
|
|
93
|
-
const [segment, ...rest] = path;
|
|
94
|
-
|
|
95
|
-
if (Array.isArray(value) && typeof segment === 'number') {
|
|
96
|
-
const next = value.slice();
|
|
97
|
-
next[segment] = replaceAtPath(next[segment], rest, replacement);
|
|
98
|
-
return next;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (typeof value === 'object' && value !== null && typeof segment === 'string') {
|
|
102
|
-
const current = value as Record<string, unknown>;
|
|
103
|
-
return {
|
|
104
|
-
...current,
|
|
105
|
-
[segment]: replaceAtPath(current[segment], rest, replacement),
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return value;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
31
|
const compactValue = (value: unknown, depth: number): unknown => {
|
|
113
32
|
if (depth >= DEFAULT_MAX_DEPTH) {
|
|
114
33
|
return DROPPED_FIELD_MESSAGE;
|
|
@@ -152,18 +71,34 @@ const compactValue = (value: unknown, depth: number): unknown => {
|
|
|
152
71
|
};
|
|
153
72
|
|
|
154
73
|
const compactStructuredValueToBudget = (value: unknown): unknown => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
74
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const compacted: Record<string, unknown> = {
|
|
79
|
+
...(value as Record<string, unknown>),
|
|
80
|
+
__traceNotice: COMPACTED_CONTENT_MESSAGE,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const topLevelCandidates = Object.entries(compacted)
|
|
84
|
+
.filter(([key]) => key !== '__traceNotice')
|
|
85
|
+
.map(([key, entryValue]) => ({ key, size: serializedSize(entryValue) }))
|
|
86
|
+
.sort((left, right) => right.size - left.size);
|
|
87
|
+
|
|
88
|
+
let droppedCount = 0;
|
|
89
|
+
|
|
90
|
+
for (const candidate of topLevelCandidates) {
|
|
91
|
+
if (serializedSize(compacted) <= DEFAULT_MAX_ENTRY_BYTES) {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
162
94
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
95
|
+
compacted[candidate.key] = DROPPED_FIELD_MESSAGE;
|
|
96
|
+
droppedCount += 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (droppedCount > 0) {
|
|
100
|
+
compacted['__traceNotice'] =
|
|
101
|
+
`${COMPACTED_CONTENT_MESSAGE} ${String(droppedCount)} top-level field(s) were dropped.`;
|
|
167
102
|
}
|
|
168
103
|
|
|
169
104
|
return compacted;
|
|
@@ -270,26 +205,28 @@ const closePort = (port: MessagePort): void => {
|
|
|
270
205
|
}
|
|
271
206
|
};
|
|
272
207
|
|
|
273
|
-
const scheduleTask = (task: () => Promise<void>): void => {
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
channel.port1.onmessage = (): void => {
|
|
278
|
-
channel.port1.onmessage = null;
|
|
279
|
-
closePort(channel.port1);
|
|
280
|
-
closePort(channel.port2);
|
|
281
|
-
void task().catch(() => undefined);
|
|
208
|
+
const scheduleTask = async (task: () => Promise<void>): Promise<void> => {
|
|
209
|
+
return await new Promise<void>((resolve, reject) => {
|
|
210
|
+
const runTask = (): void => {
|
|
211
|
+
void task().then(resolve).catch(reject);
|
|
282
212
|
};
|
|
283
213
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
214
|
+
if (typeof MessageChannel === 'function') {
|
|
215
|
+
const channel = new MessageChannel();
|
|
216
|
+
|
|
217
|
+
channel.port1.onmessage = (): void => {
|
|
218
|
+
channel.port1.onmessage = null;
|
|
219
|
+
closePort(channel.port1);
|
|
220
|
+
closePort(channel.port2);
|
|
221
|
+
runTask();
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
channel.port2.postMessage(undefined);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
287
227
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
void task().catch(() => undefined);
|
|
291
|
-
})
|
|
292
|
-
.catch(() => undefined);
|
|
228
|
+
Promise.resolve().then(runTask).catch(reject);
|
|
229
|
+
});
|
|
293
230
|
};
|
|
294
231
|
|
|
295
232
|
const getReplacementContent = (content: unknown): Record<string, unknown> => {
|
|
@@ -442,7 +379,7 @@ const startInternalDispatchWorker = (
|
|
|
442
379
|
if (startedWorkerKeys.has(key)) return;
|
|
443
380
|
startedWorkerKeys.add(key);
|
|
444
381
|
|
|
445
|
-
scheduleTask(async () => {
|
|
382
|
+
void scheduleTask(async () => {
|
|
446
383
|
const workersApi = runtime?.queueWorkerApi ?? (await getQueueWorkerApi());
|
|
447
384
|
if (workersApi === null) {
|
|
448
385
|
startedWorkerKeys.delete(key);
|
|
@@ -487,16 +424,18 @@ const startInternalDispatchWorker = (
|
|
|
487
424
|
void runWorker();
|
|
488
425
|
}, intervalMs)
|
|
489
426
|
);
|
|
427
|
+
}).catch(() => {
|
|
428
|
+
startedWorkerKeys.delete(key);
|
|
490
429
|
});
|
|
491
430
|
};
|
|
492
431
|
|
|
493
|
-
const dispatchWrite = (
|
|
432
|
+
const dispatchWrite = async (
|
|
494
433
|
storage: ITraceStorage,
|
|
495
434
|
config: ITraceConfig,
|
|
496
435
|
entry: ITraceEntry,
|
|
497
436
|
runtime?: TraceContentBudgetRuntime
|
|
498
|
-
): void => {
|
|
499
|
-
scheduleTask(async () => {
|
|
437
|
+
): Promise<void> => {
|
|
438
|
+
await scheduleTask(async () => {
|
|
500
439
|
if (hasQueueDispatch(config)) {
|
|
501
440
|
const enqueued = await enqueueTraceDispatch(config, { operation: 'write', entry }, runtime);
|
|
502
441
|
if (enqueued) return;
|
|
@@ -506,14 +445,14 @@ const dispatchWrite = (
|
|
|
506
445
|
});
|
|
507
446
|
};
|
|
508
447
|
|
|
509
|
-
const dispatchUpdate = (
|
|
448
|
+
const dispatchUpdate = async (
|
|
510
449
|
storage: ITraceStorage,
|
|
511
450
|
config: ITraceConfig,
|
|
512
451
|
uuid: string,
|
|
513
452
|
patch: Partial<Pick<ITraceEntry, 'content' | 'isLatest'>>,
|
|
514
453
|
runtime?: TraceContentBudgetRuntime
|
|
515
|
-
): void => {
|
|
516
|
-
scheduleTask(async () => {
|
|
454
|
+
): Promise<void> => {
|
|
455
|
+
await scheduleTask(async () => {
|
|
517
456
|
if (hasQueueDispatch(config)) {
|
|
518
457
|
const enqueued = await enqueueTraceDispatch(
|
|
519
458
|
config,
|
|
@@ -538,13 +477,13 @@ export const TraceContentBudget = Object.freeze({
|
|
|
538
477
|
return Object.freeze({
|
|
539
478
|
...storage,
|
|
540
479
|
writeEntry: async (entry: ITraceEntry): Promise<void> => {
|
|
541
|
-
dispatchWrite(storage, config, entry, runtime);
|
|
480
|
+
await dispatchWrite(storage, config, entry, runtime);
|
|
542
481
|
},
|
|
543
482
|
updateEntry: async (
|
|
544
483
|
uuid: string,
|
|
545
484
|
patch: Partial<Pick<ITraceEntry, 'content' | 'isLatest'>>
|
|
546
485
|
): Promise<void> => {
|
|
547
|
-
dispatchUpdate(storage, config, uuid, patch, runtime);
|
|
486
|
+
await dispatchUpdate(storage, config, uuid, patch, runtime);
|
|
548
487
|
},
|
|
549
488
|
});
|
|
550
489
|
},
|