@ooopsstudio/performance 0.9.0

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/dist/budget-engine-KDA4FRYU.js +160 -0
  4. package/dist/budget-engine-KDA4FRYU.js.map +1 -0
  5. package/dist/chunk-2XXIOHOO.js +58 -0
  6. package/dist/chunk-2XXIOHOO.js.map +1 -0
  7. package/dist/chunk-3GMKPRQP.js +197 -0
  8. package/dist/chunk-3GMKPRQP.js.map +1 -0
  9. package/dist/chunk-J6KBSLYO.js +118 -0
  10. package/dist/chunk-J6KBSLYO.js.map +1 -0
  11. package/dist/chunk-MMO5UEUU.js +20 -0
  12. package/dist/chunk-MMO5UEUU.js.map +1 -0
  13. package/dist/chunk-RL2752FW.js +31 -0
  14. package/dist/chunk-RL2752FW.js.map +1 -0
  15. package/dist/chunk-RY65GERM.js +159 -0
  16. package/dist/chunk-RY65GERM.js.map +1 -0
  17. package/dist/chunk-W72QW2AD.js +29 -0
  18. package/dist/chunk-W72QW2AD.js.map +1 -0
  19. package/dist/chunk-ZAXGEDZW.js +1184 -0
  20. package/dist/chunk-ZAXGEDZW.js.map +1 -0
  21. package/dist/custom/exporters/http.d.ts +11 -0
  22. package/dist/custom/exporters/http.js +364 -0
  23. package/dist/custom/exporters/http.js.map +1 -0
  24. package/dist/custom/exporters/raw.d.ts +8 -0
  25. package/dist/custom/exporters/raw.js +6 -0
  26. package/dist/custom/exporters/raw.js.map +1 -0
  27. package/dist/custom.d.ts +58 -0
  28. package/dist/custom.js +299 -0
  29. package/dist/custom.js.map +1 -0
  30. package/dist/development.d.ts +19 -0
  31. package/dist/development.js +55 -0
  32. package/dist/development.js.map +1 -0
  33. package/dist/event-export-manager-DEB64LWZ.js +632 -0
  34. package/dist/event-export-manager-DEB64LWZ.js.map +1 -0
  35. package/dist/index.d.ts +26 -0
  36. package/dist/index.js +205 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/monitors-VNNUIKAK.js +753 -0
  39. package/dist/monitors-VNNUIKAK.js.map +1 -0
  40. package/dist/n1-detector-6IQ2DINP.js +247 -0
  41. package/dist/n1-detector-6IQ2DINP.js.map +1 -0
  42. package/dist/observability.d.ts +32 -0
  43. package/dist/observability.js +76 -0
  44. package/dist/observability.js.map +1 -0
  45. package/dist/ports-DwUYdKj-.d.ts +23 -0
  46. package/dist/production.d.ts +19 -0
  47. package/dist/production.js +42 -0
  48. package/dist/production.js.map +1 -0
  49. package/dist/public/types.d.ts +11 -0
  50. package/dist/public/types.js +3 -0
  51. package/dist/public/types.js.map +1 -0
  52. package/package.json +74 -0
@@ -0,0 +1,1184 @@
1
+ import { createHighResClock, createPerformanceOnError, nsToMs } from './chunk-RY65GERM.js';
2
+ import { hasControlCharacters, sanitizePerformanceEventName, snapshotPerformanceLabels, isSensitivePerformanceKey, sanitizePerformanceLabelValue } from './chunk-2XXIOHOO.js';
3
+ import { isResourceSnapshotEvent, snapshotSafeDBMetadata, deepFreezePerformanceValue, clonePerformanceValue } from './chunk-J6KBSLYO.js';
4
+ import { registerPerformanceDispatcher } from './chunk-MMO5UEUU.js';
5
+ import { ignoreRuntimePromiseRejection, isRuntimePromise, isRuntimeProxy, hasSafeRuntimePrototype } from './chunk-RL2752FW.js';
6
+ import { createHash } from 'crypto';
7
+
8
+ // src/performance/core/utils/request-helpers.ts
9
+ var UUID_SEGMENT = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10
+ var LONG_HEX_SEGMENT = /^[0-9a-f]{16,}$/i;
11
+ var NUMERIC_SEGMENT = /^\d+$/;
12
+ var EMAIL_SEGMENT = /^[^/@\s]+@[^/@\s]+\.[^/@\s]+$/u;
13
+ var OPAQUE_SEGMENT = /^[a-z0-9+_=-]{24,}$/iu;
14
+ var HTTP_OUTCOMES = /* @__PURE__ */ new Set(["ok", "client_error", "server_error", "timeout", "aborted"]);
15
+ var MAX_NORMALIZED_ROUTE_LENGTH = 256;
16
+ var isDynamicRouteSegment = (segment) => {
17
+ let decoded = segment;
18
+ try {
19
+ decoded = decodeURIComponent(segment);
20
+ } catch {
21
+ }
22
+ return UUID_SEGMENT.test(decoded) || LONG_HEX_SEGMENT.test(decoded) || NUMERIC_SEGMENT.test(decoded) || EMAIL_SEGMENT.test(decoded) || OPAQUE_SEGMENT.test(decoded);
23
+ };
24
+ function normalizeHttpRoute(route) {
25
+ if (typeof route !== "string" || route.length > 2048) {
26
+ throw new Error("Performance HTTP route must be a string of at most 2048 characters");
27
+ }
28
+ if (!route.trim()) {
29
+ return "/";
30
+ }
31
+ const withoutOrigin = route.replace(/^(?:[a-z][a-z0-9+.-]*:)?\/\/[^/]+/i, "");
32
+ const pathOnly = withoutOrigin.split("?")[0]?.split("#")[0] ?? "/";
33
+ const normalized = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
34
+ const parts = normalized.split("/").filter(Boolean).map((segment) => {
35
+ if (segment.startsWith(":") || segment.startsWith("[") && segment.endsWith("]")) {
36
+ return segment;
37
+ }
38
+ if (isDynamicRouteSegment(segment)) {
39
+ return ":id";
40
+ }
41
+ return segment;
42
+ });
43
+ return (parts.length === 0 ? "/" : `/${parts.join("/")}`).slice(0, MAX_NORMALIZED_ROUTE_LENGTH);
44
+ }
45
+ function classifyHttpOutcome(metadata) {
46
+ if (metadata.aborted) {
47
+ return "aborted";
48
+ }
49
+ if (metadata.timedOut) {
50
+ return "timeout";
51
+ }
52
+ if (typeof metadata.statusCode === "number") {
53
+ if (metadata.statusCode >= 500) {
54
+ return "server_error";
55
+ }
56
+ if (metadata.statusCode >= 400) {
57
+ return "client_error";
58
+ }
59
+ }
60
+ return "ok";
61
+ }
62
+ function normalizeHttpMetadata(metadata) {
63
+ if (!metadata || typeof metadata !== "object" || isRuntimeProxy(metadata) || Array.isArray(metadata)) {
64
+ throw new Error("Performance HTTP metadata must be an object");
65
+ }
66
+ const readField = (key) => {
67
+ let descriptor;
68
+ try {
69
+ descriptor = Object.getOwnPropertyDescriptor(metadata, key);
70
+ } catch {
71
+ throw new Error("Performance HTTP metadata must use readable data properties");
72
+ }
73
+ return descriptor?.enumerable && "value" in descriptor ? descriptor.value : void 0;
74
+ };
75
+ const rawRoute = readField("route");
76
+ const rawMethod = readField("method");
77
+ const rawStatusCode = readField("statusCode");
78
+ const rawRequestSize = readField("requestSize");
79
+ const rawResponseSize = readField("responseSize");
80
+ const rawHostKind = readField("hostKind");
81
+ const rawRuntime = readField("runtime");
82
+ const rawAborted = readField("aborted");
83
+ const rawTimedOut = readField("timedOut");
84
+ const rawOutcome = readField("outcome");
85
+ if (typeof rawRoute !== "string") throw new Error("Performance HTTP route must be a string");
86
+ const normalizedRoute = normalizeHttpRoute(rawRoute);
87
+ if (typeof rawMethod !== "string") {
88
+ throw new Error("Performance HTTP method must be a string");
89
+ }
90
+ const methodCandidate = rawMethod.length <= 32 ? rawMethod.trim().toUpperCase() : "";
91
+ const normalizedMethod = /^[A-Z][A-Z0-9_-]{0,31}$/.test(methodCandidate) ? methodCandidate : "UNKNOWN";
92
+ const statusCode = Number.isInteger(rawStatusCode) && rawStatusCode >= 100 && rawStatusCode <= 599 ? rawStatusCode : void 0;
93
+ const requestSize = Number.isSafeInteger(rawRequestSize) && rawRequestSize >= 0 ? rawRequestSize : void 0;
94
+ const responseSize = Number.isSafeInteger(rawResponseSize) && rawResponseSize >= 0 ? rawResponseSize : void 0;
95
+ const normalized = {
96
+ method: normalizedMethod,
97
+ route: normalizedRoute,
98
+ ...statusCode !== void 0 ? { statusCode } : {},
99
+ ...requestSize !== void 0 ? { requestSize } : {},
100
+ ...responseSize !== void 0 ? { responseSize } : {},
101
+ ...typeof rawHostKind === "string" && rawHostKind.length <= 256 ? { hostKind: sanitizePerformanceLabelValue(rawHostKind) } : {},
102
+ ...typeof rawRuntime === "string" && rawRuntime.length <= 256 ? { runtime: sanitizePerformanceLabelValue(rawRuntime) } : {},
103
+ ...rawAborted === true ? { aborted: true } : {},
104
+ ...rawTimedOut === true ? { timedOut: true } : {}
105
+ };
106
+ const observedOutcome = normalized.aborted || normalized.timedOut || typeof normalized.statusCode === "number" && normalized.statusCode >= 200 ? classifyHttpOutcome(normalized) : void 0;
107
+ const outcome = observedOutcome ?? (typeof rawOutcome === "string" && rawOutcome.length <= 16 && HTTP_OUTCOMES.has(rawOutcome) ? rawOutcome : classifyHttpOutcome(normalized));
108
+ normalized.outcome = outcome;
109
+ return normalized;
110
+ }
111
+ function buildHttpLabels(metadata, labels) {
112
+ const normalized = normalizeHttpMetadata(metadata);
113
+ return {
114
+ ...labels ?? {},
115
+ method: normalized.method,
116
+ route: normalized.route,
117
+ status_code: String(normalized.statusCode ?? 0),
118
+ status_class: typeof normalized.statusCode === "number" ? `${Math.floor(normalized.statusCode / 100)}xx` : "unknown",
119
+ ...normalized.hostKind ? { host_kind: normalized.hostKind } : {},
120
+ ...normalized.runtime ? { runtime: normalized.runtime } : {},
121
+ outcome: normalized.outcome ?? "ok"
122
+ };
123
+ }
124
+ function toPerformanceEventRecord(event, resource) {
125
+ return {
126
+ recordedAt: event.end,
127
+ event,
128
+ source: event.source,
129
+ ...event.traceId ? { traceId: event.traceId } : {},
130
+ ...event.spanId ? { spanId: event.spanId } : {},
131
+ ...event.http ? { http: event.http } : {},
132
+ ...event.dbMetadata ? { dbMetadata: event.dbMetadata } : {},
133
+ ...resource ? { resource } : {}
134
+ };
135
+ }
136
+
137
+ // src/performance/core/callback-dispatcher.ts
138
+ var captureCallback = (bundle, key) => {
139
+ if (isRuntimeProxy(bundle)) return void 0;
140
+ try {
141
+ let owner = bundle;
142
+ for (let depth = 0; owner && depth < 8; depth += 1) {
143
+ if (isRuntimeProxy(owner)) return void 0;
144
+ const descriptor = Object.getOwnPropertyDescriptor(owner, key);
145
+ if (descriptor) {
146
+ if (!("value" in descriptor) || typeof descriptor.value !== "function") return void 0;
147
+ const callback = descriptor.value;
148
+ return ((...args) => Reflect.apply(callback, bundle, args));
149
+ }
150
+ owner = Object.getPrototypeOf(owner);
151
+ }
152
+ } catch {
153
+ return void 0;
154
+ }
155
+ return void 0;
156
+ };
157
+ function createPerformanceCallbackDispatcher(initial) {
158
+ const callbacks = /* @__PURE__ */ new Set([initial]);
159
+ let pendingCallbacks = /* @__PURE__ */ new WeakMap();
160
+ return {
161
+ emit(name, ...args) {
162
+ const emissionCallbacks = [...callbacks];
163
+ const values = emissionCallbacks.length > 1 ? deepFreezePerformanceValue(clonePerformanceValue(args)) : args;
164
+ for (const bundle of emissionCallbacks) {
165
+ try {
166
+ if (pendingCallbacks.get(bundle)?.has(name)) continue;
167
+ const callback = captureCallback(bundle, name);
168
+ if (!callback) continue;
169
+ const pendingNames = pendingCallbacks.get(bundle) ?? /* @__PURE__ */ new Set();
170
+ pendingNames.add(name);
171
+ pendingCallbacks.set(bundle, pendingNames);
172
+ const release = () => {
173
+ if (pendingCallbacks.get(bundle) !== pendingNames) return;
174
+ pendingNames.delete(name);
175
+ if (pendingNames.size === 0) pendingCallbacks.delete(bundle);
176
+ };
177
+ let result;
178
+ try {
179
+ result = callback(...values);
180
+ } catch {
181
+ release();
182
+ continue;
183
+ }
184
+ ignoreRuntimePromiseRejection(result);
185
+ if (isRuntimePromise(result)) {
186
+ try {
187
+ void Reflect.apply(Promise.prototype.then, result, [release, release]);
188
+ } catch {
189
+ release();
190
+ }
191
+ } else release();
192
+ } catch {
193
+ }
194
+ }
195
+ },
196
+ add(bundle) {
197
+ if (callbacks.has(bundle) || callbacks.size >= 100) return;
198
+ callbacks.add(bundle);
199
+ },
200
+ remove(bundle) {
201
+ pendingCallbacks.delete(bundle);
202
+ return callbacks.delete(bundle);
203
+ },
204
+ reset() {
205
+ callbacks.clear();
206
+ pendingCallbacks = /* @__PURE__ */ new WeakMap();
207
+ callbacks.add(initial);
208
+ }
209
+ };
210
+ }
211
+ var digest = (value) => createHash("sha256").update(value, "utf16le").digest("base64url");
212
+ function fingerprintLabels(labels) {
213
+ if (!labels || Object.keys(labels).length === 0) return "";
214
+ const hash = createHash("sha256");
215
+ const entries = Object.entries(labels).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
216
+ for (const [key, value] of entries) {
217
+ hash.update(`${key.length}:${key}${value.length}:${value}`, "utf16le");
218
+ }
219
+ return hash.digest("base64url");
220
+ }
221
+ function createCardinalityGuard(options = {}) {
222
+ const maxCombinations = options.maxCombinations ?? Number.POSITIVE_INFINITY;
223
+ const mode = options.mode ?? "drop";
224
+ const onExceeded = options.onExceeded;
225
+ const maxMetrics = options.maxMetrics ?? 1e3;
226
+ const ttlMs = options.ttlMs ?? 60 * 60 * 1e3;
227
+ const now = options.now ?? Date.now;
228
+ if (maxCombinations !== Number.POSITIVE_INFINITY && (!Number.isInteger(maxCombinations) || maxCombinations < 0)) {
229
+ throw new Error("Cardinality maxCombinations must be a non-negative integer or Infinity");
230
+ }
231
+ if (maxMetrics !== Number.POSITIVE_INFINITY && (!Number.isInteger(maxMetrics) || maxMetrics <= 0)) {
232
+ throw new Error("Cardinality maxMetrics must be a positive integer or Infinity");
233
+ }
234
+ if (!Number.isFinite(ttlMs) || ttlMs < 0) {
235
+ throw new Error("Cardinality ttlMs must be a non-negative finite number");
236
+ }
237
+ if (mode !== "drop" && mode !== "warn") {
238
+ throw new Error("Cardinality mode must be drop or warn");
239
+ }
240
+ const combinations = /* @__PURE__ */ new Map();
241
+ const cleanupIntervalMs = ttlMs === 0 ? 0 : Math.min(ttlMs, 6e4);
242
+ let nextCleanupAt = Number.NEGATIVE_INFINITY;
243
+ function cleanup(currentTime) {
244
+ if (cleanupIntervalMs > 0 && currentTime < nextCleanupAt) return;
245
+ for (const [metricName, entry] of combinations.entries()) {
246
+ if (currentTime - entry.lastAccessed > ttlMs) {
247
+ combinations.delete(metricName);
248
+ }
249
+ }
250
+ nextCleanupAt = currentTime + cleanupIntervalMs;
251
+ }
252
+ return {
253
+ check(metricName, labels) {
254
+ if (!Number.isFinite(maxCombinations)) {
255
+ return { allowed: true };
256
+ }
257
+ let key;
258
+ try {
259
+ if (labels) {
260
+ for (const [, value] of Object.entries(labels)) {
261
+ if (typeof value !== "string") {
262
+ return { allowed: false, reason: "invalid-labels" };
263
+ }
264
+ }
265
+ }
266
+ key = fingerprintLabels(labels);
267
+ } catch {
268
+ return { allowed: false, reason: "invalid-labels" };
269
+ }
270
+ const currentTime = now();
271
+ cleanup(currentTime);
272
+ const metricKey = digest(metricName);
273
+ let metricCombinations = combinations.get(metricKey);
274
+ if (!metricCombinations) {
275
+ if (Number.isFinite(maxMetrics) && combinations.size >= maxMetrics) {
276
+ if (mode === "warn") {
277
+ try {
278
+ onExceeded?.(metricName, "limit-exceeded");
279
+ } catch {
280
+ }
281
+ return { allowed: true, reason: "limit-exceeded" };
282
+ }
283
+ return { allowed: false, reason: "limit-exceeded" };
284
+ }
285
+ metricCombinations = { labels: /* @__PURE__ */ new Set(), lastAccessed: currentTime };
286
+ combinations.set(metricKey, metricCombinations);
287
+ }
288
+ metricCombinations.lastAccessed = currentTime;
289
+ combinations.delete(metricKey);
290
+ combinations.set(metricKey, metricCombinations);
291
+ if (metricCombinations.labels.has(key)) {
292
+ return { allowed: true };
293
+ }
294
+ if (metricCombinations.labels.size >= maxCombinations) {
295
+ if (mode === "warn") {
296
+ if (onExceeded) {
297
+ try {
298
+ onExceeded(metricName, "limit-exceeded");
299
+ } catch {
300
+ }
301
+ }
302
+ return { allowed: true, reason: "limit-exceeded" };
303
+ }
304
+ return { allowed: false, reason: "limit-exceeded" };
305
+ }
306
+ metricCombinations.labels.add(key);
307
+ return { allowed: true };
308
+ },
309
+ reset() {
310
+ combinations.clear();
311
+ nextCleanupAt = Number.NEGATIVE_INFINITY;
312
+ }
313
+ };
314
+ }
315
+
316
+ // src/performance/core/factories/performance-port-measurements.ts
317
+ var safeContextValue = (value) => {
318
+ if (typeof value === "string") return value.slice(0, 128);
319
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
320
+ return "<invalid>";
321
+ };
322
+ var snapshotResponseStatus = (value) => {
323
+ if (!value || typeof value !== "object" || isRuntimeProxy(value)) return void 0;
324
+ try {
325
+ const descriptor = Object.getOwnPropertyDescriptor(value, "status");
326
+ if (descriptor && "value" in descriptor) {
327
+ return typeof descriptor.value === "number" ? descriptor.value : void 0;
328
+ }
329
+ if (typeof Response === "undefined" || !hasSafeRuntimePrototype(value, Response.prototype)) return void 0;
330
+ const getter = Object.getOwnPropertyDescriptor(Response.prototype, "status")?.get;
331
+ const status = typeof getter === "function" ? Reflect.apply(getter, value, []) : void 0;
332
+ return typeof status === "number" ? status : void 0;
333
+ } catch {
334
+ return void 0;
335
+ }
336
+ };
337
+ var mergeHttpMetadata = (metadata, additions) => {
338
+ try {
339
+ return { ...metadata, ...additions };
340
+ } catch {
341
+ return { method: "UNKNOWN", route: "/", ...additions };
342
+ }
343
+ };
344
+ function createMeasurementPortMethods(deps) {
345
+ const { clock, emitEvent, onError, withFailedDBMetadata } = deps;
346
+ const invalidLabels = Object.freeze({ "": "" });
347
+ const captureLabels = (labels) => {
348
+ try {
349
+ return snapshotPerformanceLabels(labels);
350
+ } catch {
351
+ return invalidLabels;
352
+ }
353
+ };
354
+ const recordRequest = (name, duration, metadata, labels) => {
355
+ try {
356
+ const capturedLabels = captureLabels(labels);
357
+ const http = normalizeHttpMetadata(metadata);
358
+ const end = clock.now();
359
+ emitEvent({
360
+ name,
361
+ duration,
362
+ start: end - duration,
363
+ end,
364
+ source: "mark",
365
+ http,
366
+ labels: buildHttpLabels(http, capturedLabels),
367
+ ...http.outcome ? { outcome: http.outcome } : {}
368
+ });
369
+ } catch (error) {
370
+ onError(error, { measureName: safeContextValue(name), operation: "record-request" });
371
+ }
372
+ };
373
+ const timedEvent = (name, start, startHr, labels, failed = false) => ({
374
+ name,
375
+ duration: nsToMs(clock.nowHr() - startHr),
376
+ start,
377
+ end: Math.max(start, clock.now()),
378
+ source: "mark",
379
+ ...labels ? { labels } : {},
380
+ ...failed ? { outcome: "server_error" } : {}
381
+ });
382
+ return {
383
+ measureSync(name, fn, labels) {
384
+ const start = clock.now();
385
+ const startHr = clock.nowHr();
386
+ const capturedLabels = captureLabels(labels);
387
+ try {
388
+ const result = fn();
389
+ emitEvent(timedEvent(name, start, startHr, capturedLabels));
390
+ return result;
391
+ } catch (error) {
392
+ emitEvent(timedEvent(name, start, startHr, capturedLabels, true));
393
+ throw error;
394
+ }
395
+ },
396
+ measureAsync(name, fn, labels) {
397
+ const start = clock.now();
398
+ const startHr = clock.nowHr();
399
+ const capturedLabels = captureLabels(labels);
400
+ return Promise.resolve().then(() => fn()).then(
401
+ (result) => {
402
+ emitEvent(timedEvent(name, start, startHr, capturedLabels));
403
+ return result;
404
+ },
405
+ (error) => {
406
+ emitEvent(timedEvent(name, start, startHr, capturedLabels, true));
407
+ throw error;
408
+ }
409
+ );
410
+ },
411
+ measureDBQuery(name, fn, metadata, labels) {
412
+ const start = clock.now();
413
+ const startHr = clock.nowHr();
414
+ const capturedLabels = captureLabels(labels);
415
+ const capturedMetadata = snapshotSafeDBMetadata(metadata);
416
+ return Promise.resolve().then(() => fn()).then(
417
+ (result) => {
418
+ emitEvent(timedEvent(name, start, startHr, capturedLabels), capturedMetadata);
419
+ return result;
420
+ },
421
+ (error) => {
422
+ emitEvent(
423
+ timedEvent(name, start, startHr, capturedLabels, true),
424
+ withFailedDBMetadata(capturedMetadata)
425
+ );
426
+ throw error;
427
+ }
428
+ );
429
+ },
430
+ measureDBQuerySync(name, fn, metadata, labels) {
431
+ const start = clock.now();
432
+ const startHr = clock.nowHr();
433
+ const capturedLabels = captureLabels(labels);
434
+ const capturedMetadata = snapshotSafeDBMetadata(metadata);
435
+ try {
436
+ const result = fn();
437
+ emitEvent(timedEvent(name, start, startHr, capturedLabels), capturedMetadata);
438
+ return result;
439
+ } catch (error) {
440
+ emitEvent(
441
+ timedEvent(name, start, startHr, capturedLabels, true),
442
+ withFailedDBMetadata(capturedMetadata)
443
+ );
444
+ throw error;
445
+ }
446
+ },
447
+ record(metric, value, labels) {
448
+ const end = clock.now();
449
+ const capturedLabels = captureLabels(labels);
450
+ emitEvent({
451
+ name: metric,
452
+ duration: value,
453
+ start: end - value,
454
+ end,
455
+ source: "mark",
456
+ ...capturedLabels ? { labels: capturedLabels } : {}
457
+ });
458
+ },
459
+ async measureRequest(name, fn, metadata, labels) {
460
+ const startHr = clock.nowHr();
461
+ const capturedLabels = captureLabels(labels);
462
+ let capturedMetadata;
463
+ try {
464
+ capturedMetadata = normalizeHttpMetadata(metadata);
465
+ } catch {
466
+ capturedMetadata = { method: "UNKNOWN", route: "/" };
467
+ }
468
+ try {
469
+ const result = await fn();
470
+ const statusCode = capturedMetadata.statusCode ?? snapshotResponseStatus(result);
471
+ recordRequest(
472
+ name,
473
+ nsToMs(clock.nowHr() - startHr),
474
+ mergeHttpMetadata(capturedMetadata, statusCode !== void 0 ? { statusCode } : {}),
475
+ capturedLabels
476
+ );
477
+ return result;
478
+ } catch (error) {
479
+ let outcome = "server_error";
480
+ try {
481
+ if (capturedMetadata.aborted) outcome = "aborted";
482
+ else if (capturedMetadata.timedOut) outcome = "timeout";
483
+ } catch {
484
+ }
485
+ recordRequest(
486
+ name,
487
+ nsToMs(clock.nowHr() - startHr),
488
+ mergeHttpMetadata(capturedMetadata, { statusCode: void 0, outcome }),
489
+ capturedLabels
490
+ );
491
+ throw error;
492
+ }
493
+ },
494
+ recordRequest
495
+ };
496
+ }
497
+
498
+ // src/performance/utils/single-flight-method.ts
499
+ var createSingleFlightMethodCapture = () => {
500
+ const pendingMethods = /* @__PURE__ */ new WeakMap();
501
+ return (target, key) => {
502
+ if (!target || typeof target !== "object" && typeof target !== "function" || isRuntimeProxy(target)) return void 0;
503
+ try {
504
+ let owner = target;
505
+ for (let depth = 0; owner && depth < 16; depth += 1) {
506
+ if (isRuntimeProxy(owner)) return void 0;
507
+ const descriptor = Object.getOwnPropertyDescriptor(owner, key);
508
+ if (descriptor) {
509
+ if (!("value" in descriptor) || typeof descriptor.value !== "function") return void 0;
510
+ const method = descriptor.value;
511
+ return (...args) => {
512
+ const targetObject = target;
513
+ const active = pendingMethods.get(targetObject) ?? /* @__PURE__ */ new Set();
514
+ if (active.has(key)) return void 0;
515
+ active.add(key);
516
+ pendingMethods.set(targetObject, active);
517
+ const release = () => {
518
+ active.delete(key);
519
+ if (active.size === 0 && pendingMethods.get(targetObject) === active) {
520
+ pendingMethods.delete(targetObject);
521
+ }
522
+ };
523
+ let result;
524
+ try {
525
+ result = Reflect.apply(method, target, args);
526
+ } catch (error) {
527
+ release();
528
+ throw error;
529
+ }
530
+ if (isRuntimePromise(result)) {
531
+ try {
532
+ void Reflect.apply(Promise.prototype.then, result, [release, release]);
533
+ } catch {
534
+ release();
535
+ }
536
+ } else release();
537
+ return result;
538
+ };
539
+ }
540
+ owner = Object.getPrototypeOf(owner);
541
+ }
542
+ } catch {
543
+ return void 0;
544
+ }
545
+ return void 0;
546
+ };
547
+ };
548
+
549
+ // src/performance/core/tracing-bridge.ts
550
+ var sanitizeSpanValue = (value) => {
551
+ if (typeof value === "string") return value.length <= 256 ? sanitizePerformanceLabelValue(value) : "[redacted]";
552
+ if (typeof value === "number" && Number.isFinite(value)) return value;
553
+ if (typeof value === "boolean") return value;
554
+ return "[redacted]";
555
+ };
556
+ var SPAN_OPTION_FIELDS = ["labels", "kind", "attributes", "http", "dbMetadata", "createSpan"];
557
+ var snapshotPerformanceSpanOptions = (options) => {
558
+ if (options === void 0) return void 0;
559
+ if (!options || typeof options !== "object" || isRuntimeProxy(options) || Array.isArray(options)) return void 0;
560
+ const snapshot = /* @__PURE__ */ Object.create(null);
561
+ try {
562
+ for (const key of SPAN_OPTION_FIELDS) {
563
+ const descriptor = Object.getOwnPropertyDescriptor(options, key);
564
+ if (!descriptor?.enumerable || !("value" in descriptor)) continue;
565
+ if (key === "http") {
566
+ try {
567
+ snapshot[key] = normalizeHttpMetadata(descriptor.value);
568
+ } catch {
569
+ }
570
+ } else if (key === "dbMetadata") {
571
+ const metadata = snapshotSafeDBMetadata(descriptor.value);
572
+ if (metadata) snapshot[key] = metadata;
573
+ } else snapshot[key] = descriptor.value;
574
+ }
575
+ } catch {
576
+ return void 0;
577
+ }
578
+ return snapshot;
579
+ };
580
+ var sanitizeSpanAttributes = (attributes) => {
581
+ const sanitized = {};
582
+ try {
583
+ const source = attributes ?? {};
584
+ if (isRuntimeProxy(source)) return {};
585
+ const prototype = Object.getPrototypeOf(source);
586
+ if (prototype !== Object.prototype && prototype !== null) return {};
587
+ let inspected = 0;
588
+ for (const key in source) {
589
+ if (inspected >= 32) break;
590
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
591
+ if (!descriptor?.enumerable) continue;
592
+ if (!("value" in descriptor)) continue;
593
+ inspected += 1;
594
+ if (/^[a-z][a-z0-9_.-]{0,63}$/iu.test(key)) {
595
+ sanitized[key] = isSensitivePerformanceKey(key) ? "[redacted]" : sanitizeSpanValue(descriptor.value);
596
+ }
597
+ }
598
+ } catch {
599
+ return {};
600
+ }
601
+ return sanitized;
602
+ };
603
+ var sanitizeCorrelationId = (value, length) => typeof value === "string" && value.length === length && /^[0-9a-f]+$/iu.test(value) && !/^0+$/u.test(value) ? value.toLowerCase() : void 0;
604
+ var readCorrelationField = (context, key) => {
605
+ if (!context || typeof context !== "object" || isRuntimeProxy(context)) return void 0;
606
+ try {
607
+ const descriptor = Object.getOwnPropertyDescriptor(context, key);
608
+ return descriptor && "value" in descriptor ? descriptor.value : void 0;
609
+ } catch {
610
+ return void 0;
611
+ }
612
+ };
613
+ var toSpanAttributes = (options, duration, outcome) => ({
614
+ ...sanitizeSpanAttributes(options?.attributes),
615
+ ...sanitizeSpanAttributes(options?.labels),
616
+ "perf.duration_ms": duration,
617
+ "perf.outcome": outcome,
618
+ ...options?.http?.route ? { "http.route": sanitizeSpanValue(options.http.route) } : {},
619
+ ...options?.http?.method ? { "http.method": sanitizeSpanValue(options.http.method) } : {},
620
+ ...typeof options?.http?.statusCode === "number" ? { "http.status_code": sanitizeSpanValue(options.http.statusCode) } : {},
621
+ ...options?.dbMetadata?.collection ? { "db.collection": sanitizeSpanValue(options.dbMetadata.collection) } : {},
622
+ ...options?.dbMetadata?.table ? { "db.table": sanitizeSpanValue(options.dbMetadata.table) } : {},
623
+ ...options?.dbMetadata?.operation ? { "db.operation": sanitizeSpanValue(options.dbMetadata.operation) } : {},
624
+ ...options?.dbMetadata?.queryHash ? { "db.query_hash": sanitizeSpanValue(options.dbMetadata.queryHash) } : {}
625
+ });
626
+ function createPerformanceTracingBridge(tracer) {
627
+ const captureMethod = createSingleFlightMethodCapture();
628
+ const captureSpanMethod = createSingleFlightMethodCapture();
629
+ const getActiveSpan = captureMethod(tracer, "getActiveSpan");
630
+ const readCurrentTraceId = captureMethod(tracer, "currentTraceId");
631
+ const inSpan = captureMethod(tracer, "inSpan");
632
+ return {
633
+ getCorrelation() {
634
+ let context;
635
+ try {
636
+ const activeSpan = getActiveSpan?.();
637
+ context = captureSpanMethod(activeSpan, "getContext")?.();
638
+ } catch {
639
+ }
640
+ let currentTraceId;
641
+ try {
642
+ currentTraceId = readCurrentTraceId?.();
643
+ } catch {
644
+ }
645
+ const traceId = sanitizeCorrelationId(currentTraceId, 32) ?? sanitizeCorrelationId(readCorrelationField(context, "traceId"), 32);
646
+ const spanId = sanitizeCorrelationId(readCorrelationField(context, "spanId"), 16);
647
+ return {
648
+ ...traceId ? { traceId } : {},
649
+ ...spanId ? { spanId } : {}
650
+ };
651
+ },
652
+ async withSpan(name, options, fn) {
653
+ if (!tracer) {
654
+ return await fn(void 0);
655
+ }
656
+ const capturedOptions = snapshotPerformanceSpanOptions(options);
657
+ const createSpan = capturedOptions?.createSpan === true;
658
+ if (createSpan) {
659
+ if (!inSpan) return await fn(void 0);
660
+ let spanOptions;
661
+ try {
662
+ spanOptions = {
663
+ ...capturedOptions?.kind ? { kind: capturedOptions.kind } : {},
664
+ ...capturedOptions?.attributes ? { attributes: sanitizeSpanAttributes(capturedOptions.attributes) } : {}
665
+ };
666
+ } catch {
667
+ return await fn(void 0);
668
+ }
669
+ let invoked = false;
670
+ let callbackPromise;
671
+ const invokeOnce = (span) => {
672
+ callbackPromise ??= Promise.resolve().then(async () => await fn(span));
673
+ return callbackPromise;
674
+ };
675
+ try {
676
+ const tracerOperation = inSpan(name, async (span) => {
677
+ invoked = true;
678
+ try {
679
+ return await invokeOnce(span);
680
+ } catch {
681
+ return void 0;
682
+ }
683
+ }, { ...spanOptions });
684
+ ignoreRuntimePromiseRejection(tracerOperation);
685
+ await Promise.resolve();
686
+ if (!invoked) return await invokeOnce(void 0);
687
+ return await callbackPromise;
688
+ } catch {
689
+ if (!invoked) return await invokeOnce(void 0);
690
+ return await callbackPromise;
691
+ }
692
+ }
693
+ let activeSpan;
694
+ try {
695
+ activeSpan = getActiveSpan?.();
696
+ } catch {
697
+ }
698
+ return await fn(activeSpan);
699
+ },
700
+ annotate(span, options, duration, outcome) {
701
+ if (!span) {
702
+ return;
703
+ }
704
+ try {
705
+ const setAttribute = captureSpanMethod(span, "setAttribute");
706
+ const addEvent = captureSpanMethod(span, "addEvent");
707
+ const setStatus = captureSpanMethod(span, "setStatus");
708
+ const capturedOptions = snapshotPerformanceSpanOptions(options);
709
+ for (const [key, value] of Object.entries(toSpanAttributes(capturedOptions, duration, outcome))) {
710
+ setAttribute?.(key, value);
711
+ }
712
+ addEvent?.("performance.measurement", {
713
+ ...sanitizeSpanAttributes(capturedOptions?.labels),
714
+ duration_ms: duration,
715
+ outcome
716
+ });
717
+ setStatus?.({ code: outcome === "ok" ? "ok" : "error" });
718
+ } catch {
719
+ }
720
+ },
721
+ recordError(span, _error) {
722
+ if (!span) {
723
+ return;
724
+ }
725
+ try {
726
+ const recordException = captureSpanMethod(span, "recordException");
727
+ const setStatus = captureSpanMethod(span, "setStatus");
728
+ const message = "Performance measured operation failed";
729
+ recordException?.(new Error(message));
730
+ setStatus?.({ code: "error", description: message });
731
+ } catch {
732
+ }
733
+ }
734
+ };
735
+ }
736
+
737
+ // src/performance/core/base-handler.ts
738
+ var RESOURCE_VALUE_LABELS = /* @__PURE__ */ new Set(["user", "system", "utilization", "rss", "heapUsed", "heapTotal", "external"]);
739
+ var snapshotEventLabels = (labels, options = {}) => {
740
+ if (!labels) return void 0;
741
+ const entries = Object.entries(snapshotPerformanceLabels(labels) ?? {});
742
+ const snapshot = {};
743
+ for (const [key, value] of entries) {
744
+ if (!/^[a-z_][a-z0-9_.-]{0,63}$/i.test(key) || typeof value !== "string" || value.length > 256) {
745
+ throw new Error("Performance event labels exceed safe key/value limits");
746
+ }
747
+ if (options.preserveHttpRoute && key === "route") {
748
+ if (hasControlCharacters(value)) throw new Error("Performance HTTP routes cannot contain control characters");
749
+ snapshot[key] = value;
750
+ } else if (options.preserveResourceValues && RESOURCE_VALUE_LABELS.has(key)) {
751
+ const numeric = Number(value);
752
+ if (!Number.isFinite(numeric) || numeric < 0) throw new Error("Performance resource labels must be non-negative finite numbers");
753
+ snapshot[key] = value;
754
+ } else {
755
+ snapshot[key] = isSensitivePerformanceKey(key) ? "[redacted]" : sanitizePerformanceLabelValue(value);
756
+ }
757
+ }
758
+ return snapshot;
759
+ };
760
+ var VALID_EVENT_SOURCES = /* @__PURE__ */ new Set(["runtime", "mark", "feature"]);
761
+ var VALID_EVENT_OUTCOMES = /* @__PURE__ */ new Set(["ok", "client_error", "server_error", "timeout", "aborted"]);
762
+ function createBasePerformanceHandler(options) {
763
+ const clock = createHighResClock({ clock: options.clock });
764
+ const dispatcher = createPerformanceCallbackDispatcher(options.callbacks ?? {});
765
+ const cardinality = createCardinalityGuard({
766
+ maxCombinations: options.cardinalityLimit,
767
+ mode: options.cardinalityMode,
768
+ now: clock.now,
769
+ onExceeded: (name, reason) => dispatcher.emit("onDimensionExplosion", name, reason)
770
+ });
771
+ const tracing = createPerformanceTracingBridge(options.tracer);
772
+ const onError = createPerformanceOnError(options.errors, { operation: "measure" });
773
+ let extensions = {};
774
+ let state = "running";
775
+ let droppedEvents = 0;
776
+ let activeMeasurements = 0;
777
+ let activeBarrier;
778
+ let releaseActiveBarrier;
779
+ let monitorsStopped = false;
780
+ let finalizationFailureCode;
781
+ const beginMeasurement = () => {
782
+ if (state !== "running") return void 0;
783
+ activeMeasurements += 1;
784
+ dispatcher.emit("onSelfMetric", "_performance_active_measurements", activeMeasurements);
785
+ return () => {
786
+ activeMeasurements -= 1;
787
+ dispatcher.emit("onSelfMetric", "_performance_active_measurements", activeMeasurements);
788
+ if (activeMeasurements === 0) {
789
+ releaseActiveBarrier?.();
790
+ releaseActiveBarrier = void 0;
791
+ activeBarrier = void 0;
792
+ }
793
+ };
794
+ };
795
+ const waitForActive = async () => {
796
+ if (activeMeasurements === 0) return;
797
+ activeBarrier ??= new Promise((resolve) => {
798
+ releaseActiveBarrier = resolve;
799
+ });
800
+ let timer;
801
+ try {
802
+ await Promise.race([
803
+ activeBarrier,
804
+ new Promise((_, reject) => {
805
+ timer = setTimeout(() => reject(new Error("PERFORMANCE_DRAIN_TIMEOUT")), 5e3);
806
+ })
807
+ ]);
808
+ } finally {
809
+ try {
810
+ if (timer) clearTimeout(timer);
811
+ } catch {
812
+ }
813
+ }
814
+ };
815
+ const withFailedDBMetadata = (metadata) => {
816
+ try {
817
+ return { ...metadata ?? {}, success: false, failureCode: "query_failed" };
818
+ } catch {
819
+ return { success: false, failureCode: "query_failed" };
820
+ }
821
+ };
822
+ const emitEvent = (event, metadata) => {
823
+ if (state === "closed") return;
824
+ let enriched;
825
+ let eventName = "<invalid>";
826
+ try {
827
+ const rawName = event.name;
828
+ const validName = typeof rawName === "string" && rawName.length <= 128 && Boolean(rawName.trim()) && !hasControlCharacters(rawName);
829
+ eventName = validName ? sanitizePerformanceEventName(rawName) : "<invalid>";
830
+ if (!validName || !Number.isFinite(event.duration) || event.duration < 0 || !Number.isFinite(event.start) || !Number.isFinite(event.end) || event.end < event.start || !VALID_EVENT_SOURCES.has(event.source) || event.outcome !== void 0 && !VALID_EVENT_OUTCOMES.has(event.outcome)) {
831
+ throw new Error("Invalid performance event");
832
+ }
833
+ const correlation = tracing.getCorrelation();
834
+ const resourceSnapshot = isResourceSnapshotEvent(event.source, eventName);
835
+ const http = event.http ? normalizeHttpMetadata(event.http) : void 0;
836
+ const labels = snapshotEventLabels(
837
+ http ? buildHttpLabels(http, event.labels) : event.labels,
838
+ { preserveHttpRoute: Boolean(http), preserveResourceValues: resourceSnapshot }
839
+ );
840
+ const resolvedOutcome = event.outcome ?? http?.outcome;
841
+ enriched = {
842
+ ...event,
843
+ name: eventName,
844
+ ...labels ? { labels } : {},
845
+ ...http ? { http } : {},
846
+ ...resolvedOutcome ? { outcome: resolvedOutcome } : {},
847
+ ...metadata ? { dbMetadata: snapshotSafeDBMetadata(metadata) } : event.dbMetadata ? { dbMetadata: snapshotSafeDBMetadata(event.dbMetadata) } : {},
848
+ ...event.traceId ?? correlation.traceId ? { traceId: event.traceId ?? correlation.traceId } : {},
849
+ ...event.spanId ?? correlation.spanId ? { spanId: event.spanId ?? correlation.spanId } : {}
850
+ };
851
+ const cardinalityLabels = resourceSnapshot ? void 0 : enriched.labels;
852
+ const check = cardinality.check(enriched.name, cardinalityLabels);
853
+ if (!check.allowed) {
854
+ droppedEvents += 1;
855
+ dispatcher.emit("onSelfMetric", "_performance_dropped_total", 1, { reason: check.reason ?? "cardinality" });
856
+ dispatcher.emit("onDimensionDrop", enriched.name, check.reason ?? "limit-exceeded");
857
+ return;
858
+ }
859
+ if (check.reason) {
860
+ enriched = {
861
+ ...enriched,
862
+ name: "cardinality_overflow",
863
+ labels: { reason: check.reason }
864
+ };
865
+ }
866
+ } catch (error) {
867
+ droppedEvents += 1;
868
+ dispatcher.emit("onSelfMetric", "_performance_dropped_total", 1, { reason: "invalid_event" });
869
+ onError(error, { eventName });
870
+ return;
871
+ }
872
+ enriched = deepFreezePerformanceValue(enriched);
873
+ dispatcher.emit("onSelfMetric", "_performance_recorded_total", 1, { source: enriched.source });
874
+ try {
875
+ extensions.onAcceptedEvent?.(enriched);
876
+ } catch (error) {
877
+ onError(error, { eventName: enriched.name, operation: "accepted-event-extension" });
878
+ }
879
+ dispatcher.emit("onPerfEvent", enriched);
880
+ };
881
+ const measurements = createMeasurementPortMethods({
882
+ clock,
883
+ emitEvent,
884
+ onError,
885
+ withFailedDBMetadata
886
+ });
887
+ let monitoring;
888
+ try {
889
+ monitoring = options.createRuntimeMonitoring?.({
890
+ clock,
891
+ onPerfEvent: emitEvent,
892
+ onSaturationAlert: (alert) => dispatcher.emit("onSaturationAlert", alert),
893
+ ...options.errors ? { errors: options.errors } : {},
894
+ enableEventLoopMonitor: options.enableEventLoopMonitor,
895
+ enableGCMonitor: options.enableGCMonitor,
896
+ enableResourceMonitor: options.enableResourceMonitor
897
+ });
898
+ extensions = options.createExtensions?.(dispatcher, clock) ?? {};
899
+ } catch (error) {
900
+ try {
901
+ monitoring?.stop();
902
+ } catch {
903
+ }
904
+ throw error;
905
+ }
906
+ let shutdownPromise;
907
+ const port = {
908
+ record(name, value, labels) {
909
+ const finish = beginMeasurement();
910
+ if (!finish) return;
911
+ try {
912
+ measurements.record(name, value, labels);
913
+ } finally {
914
+ finish();
915
+ }
916
+ },
917
+ async measureAsync(name, fn, labels) {
918
+ const finish = beginMeasurement();
919
+ if (!finish) return await fn();
920
+ try {
921
+ return await measurements.measureAsync(name, fn, labels);
922
+ } finally {
923
+ finish();
924
+ }
925
+ },
926
+ measureSync(name, fn, labels) {
927
+ const finish = beginMeasurement();
928
+ if (!finish) return fn();
929
+ try {
930
+ return measurements.measureSync(name, fn, labels);
931
+ } finally {
932
+ finish();
933
+ }
934
+ },
935
+ async measureDBQuery(name, fn, metadata, labels) {
936
+ const finish = beginMeasurement();
937
+ if (!finish) return await fn();
938
+ try {
939
+ return await measurements.measureDBQuery(name, fn, metadata, labels);
940
+ } finally {
941
+ finish();
942
+ }
943
+ },
944
+ measureDBQuerySync(name, fn, metadata, labels) {
945
+ const finish = beginMeasurement();
946
+ if (!finish) return fn();
947
+ try {
948
+ return measurements.measureDBQuerySync(name, fn, metadata, labels);
949
+ } finally {
950
+ finish();
951
+ }
952
+ },
953
+ async measureRequest(name, fn, metadata, labels) {
954
+ const finish = beginMeasurement();
955
+ if (!finish) return await fn();
956
+ try {
957
+ return await measurements.measureRequest(name, fn, metadata, labels);
958
+ } finally {
959
+ finish();
960
+ }
961
+ },
962
+ async measureSpan(name, fn, spanOptions) {
963
+ const finish = beginMeasurement();
964
+ if (!finish) return await fn();
965
+ try {
966
+ const capturedSpanOptions = snapshotPerformanceSpanOptions(spanOptions);
967
+ const traceSpanName = typeof name === "string" && name.length <= 128 && name.trim() && !hasControlCharacters(name) ? sanitizePerformanceEventName(name) : "performance.measurement";
968
+ return await tracing.withSpan(traceSpanName, capturedSpanOptions, async (span) => {
969
+ let eventLabels;
970
+ let dbMetadata;
971
+ let httpMetadata;
972
+ try {
973
+ eventLabels = snapshotPerformanceLabels(capturedSpanOptions?.labels);
974
+ dbMetadata = snapshotSafeDBMetadata(capturedSpanOptions?.dbMetadata);
975
+ httpMetadata = capturedSpanOptions?.http ? normalizeHttpMetadata(capturedSpanOptions.http) : void 0;
976
+ } catch {
977
+ }
978
+ const started = clock.now();
979
+ const startedHr = clock.nowHr();
980
+ try {
981
+ const result = await fn();
982
+ const duration = Number(clock.nowHr() - startedHr) / 1e6;
983
+ const end = Math.max(started, clock.now());
984
+ tracing.annotate(span, capturedSpanOptions, duration, "ok");
985
+ emitEvent({
986
+ name,
987
+ duration,
988
+ start: started,
989
+ end,
990
+ source: "mark",
991
+ ...httpMetadata ? { http: httpMetadata } : {},
992
+ ...httpMetadata?.outcome ? { outcome: httpMetadata.outcome } : {},
993
+ labels: { ...eventLabels ?? {}, instrumentation: "span" }
994
+ }, dbMetadata);
995
+ return result;
996
+ } catch (error) {
997
+ const duration = Number(clock.nowHr() - startedHr) / 1e6;
998
+ const end = Math.max(started, clock.now());
999
+ const failureOutcome = httpMetadata?.aborted ? "aborted" : httpMetadata?.timedOut ? "timeout" : "server_error";
1000
+ tracing.annotate(span, capturedSpanOptions, duration, "error");
1001
+ tracing.recordError(span, error);
1002
+ emitEvent({
1003
+ name,
1004
+ duration,
1005
+ start: started,
1006
+ end,
1007
+ source: "mark",
1008
+ outcome: failureOutcome,
1009
+ ...httpMetadata ? { http: {
1010
+ ...httpMetadata,
1011
+ statusCode: void 0,
1012
+ outcome: failureOutcome
1013
+ } } : {},
1014
+ labels: { ...eventLabels ?? {}, instrumentation: "span" }
1015
+ }, dbMetadata ? withFailedDBMetadata(dbMetadata) : void 0);
1016
+ throw error;
1017
+ }
1018
+ });
1019
+ } finally {
1020
+ finish();
1021
+ }
1022
+ },
1023
+ getBudgetStatus(name) {
1024
+ if (typeof name !== "string" || name.length > 128) return void 0;
1025
+ try {
1026
+ const status = extensions.getBudgetStatus?.(name);
1027
+ return status ? Object.freeze({ ...status }) : void 0;
1028
+ } catch {
1029
+ return void 0;
1030
+ }
1031
+ },
1032
+ async flush() {
1033
+ if (state === "closed") return;
1034
+ if (state === "draining" && shutdownPromise) return await shutdownPromise;
1035
+ try {
1036
+ await extensions.flush?.();
1037
+ } catch (error) {
1038
+ dispatcher.emit("onSelfMetric", "_performance_finalization_failures_total", 1, { operation: "flush" });
1039
+ throw error;
1040
+ }
1041
+ },
1042
+ async shutdown() {
1043
+ if (state === "closed") return;
1044
+ if (!shutdownPromise) {
1045
+ shutdownPromise = (async () => {
1046
+ state = "draining";
1047
+ if (!monitorsStopped) {
1048
+ monitorsStopped = true;
1049
+ try {
1050
+ monitoring?.stop();
1051
+ } catch (error) {
1052
+ onError(error, { operation: "runtime-monitor.stop" });
1053
+ }
1054
+ }
1055
+ await waitForActive();
1056
+ await extensions.shutdown?.();
1057
+ state = "closed";
1058
+ finalizationFailureCode = void 0;
1059
+ })();
1060
+ }
1061
+ try {
1062
+ await shutdownPromise;
1063
+ } catch (error) {
1064
+ finalizationFailureCode = "PERFORMANCE_FINALIZATION_FAILURE";
1065
+ dispatcher.emit("onSelfMetric", "_performance_finalization_failures_total", 1, { operation: "shutdown" });
1066
+ shutdownPromise = void 0;
1067
+ throw error;
1068
+ }
1069
+ },
1070
+ getStatus() {
1071
+ let status;
1072
+ try {
1073
+ status = extensions.getExportStatus?.();
1074
+ } catch {
1075
+ status = {
1076
+ queueSize: 0,
1077
+ droppedTotal: 0,
1078
+ retriedTotal: 0,
1079
+ sinkState: "unhealthy",
1080
+ lastFailureCode: "PERFORMANCE_STATUS_FAILURE"
1081
+ };
1082
+ }
1083
+ return Object.freeze({
1084
+ state,
1085
+ activeMeasurements,
1086
+ queueSize: status?.queueSize ?? 0,
1087
+ droppedTotal: droppedEvents + (status?.droppedTotal ?? 0),
1088
+ retriedTotal: status?.retriedTotal ?? 0,
1089
+ sinkState: state === "closed" ? "closed" : finalizationFailureCode ? "unhealthy" : status?.sinkState ?? "healthy",
1090
+ ...finalizationFailureCode ?? status?.lastFailureCode ? { lastFailureCode: finalizationFailureCode ?? status?.lastFailureCode } : {}
1091
+ });
1092
+ }
1093
+ };
1094
+ registerPerformanceDispatcher(port, dispatcher);
1095
+ return port;
1096
+ }
1097
+
1098
+ // src/performance/utils/lifecycle-cleanup.ts
1099
+ var captureLifecycleMethod = (lifecycle, key) => {
1100
+ if (isRuntimeProxy(lifecycle)) return void 0;
1101
+ try {
1102
+ let owner = lifecycle;
1103
+ for (let depth = 0; owner && depth < 16; depth += 1) {
1104
+ if (isRuntimeProxy(owner)) return void 0;
1105
+ const descriptor = Object.getOwnPropertyDescriptor(owner, key);
1106
+ if (descriptor) {
1107
+ if (!("value" in descriptor) || typeof descriptor.value !== "function") return void 0;
1108
+ const method = descriptor.value;
1109
+ return ((...args) => Reflect.apply(method, lifecycle, args));
1110
+ }
1111
+ owner = Object.getPrototypeOf(owner);
1112
+ }
1113
+ } catch {
1114
+ return void 0;
1115
+ }
1116
+ return void 0;
1117
+ };
1118
+ function registerPerformanceLifecycleCleanup(lifecycle, handler) {
1119
+ if (!lifecycle) return;
1120
+ const registerFlushHook = captureLifecycleMethod(lifecycle, "registerFlushHook");
1121
+ const registerShutdownHook = captureLifecycleMethod(lifecycle, "registerShutdownHook");
1122
+ let disposers = [];
1123
+ const addDisposer = (value) => {
1124
+ if (typeof value === "function") disposers.push(value);
1125
+ else ignoreRuntimePromiseRejection(value);
1126
+ };
1127
+ try {
1128
+ if (registerFlushHook && handler.flush) {
1129
+ addDisposer(registerFlushHook(
1130
+ "performance-export",
1131
+ async () => await handler.flush?.()
1132
+ ));
1133
+ }
1134
+ if (registerShutdownHook && handler.shutdown) {
1135
+ addDisposer(registerShutdownHook(
1136
+ "runtime-monitors",
1137
+ async () => await handler.shutdown?.(),
1138
+ { name: "performance-cleanup", priority: 30 }
1139
+ ));
1140
+ }
1141
+ } catch (error) {
1142
+ const cleanupErrors = [];
1143
+ for (const disposer of disposers.reverse()) {
1144
+ try {
1145
+ ignoreRuntimePromiseRejection(disposer());
1146
+ } catch (cleanupError) {
1147
+ cleanupErrors.push(cleanupError);
1148
+ }
1149
+ }
1150
+ disposers = [];
1151
+ if (cleanupErrors.length > 0) {
1152
+ throw new AggregateError([error, ...cleanupErrors], "Performance lifecycle registration rollback failed");
1153
+ }
1154
+ throw error;
1155
+ }
1156
+ if (!handler.shutdown || disposers.length === 0) return;
1157
+ const shutdown = handler.shutdown.bind(handler);
1158
+ handler.shutdown = async () => {
1159
+ await shutdown();
1160
+ const activeDisposers = disposers;
1161
+ disposers = [];
1162
+ for (const disposer of activeDisposers.reverse()) {
1163
+ try {
1164
+ ignoreRuntimePromiseRejection(disposer());
1165
+ } catch {
1166
+ }
1167
+ }
1168
+ };
1169
+ }
1170
+ async function failPerformanceSetup(handler, setupError) {
1171
+ try {
1172
+ await handler.shutdown?.();
1173
+ } catch (cleanupError) {
1174
+ throw new AggregateError(
1175
+ [setupError, cleanupError],
1176
+ "Performance setup and cleanup failed"
1177
+ );
1178
+ }
1179
+ throw setupError;
1180
+ }
1181
+
1182
+ export { createBasePerformanceHandler, failPerformanceSetup, registerPerformanceLifecycleCleanup, toPerformanceEventRecord };
1183
+ //# sourceMappingURL=chunk-ZAXGEDZW.js.map
1184
+ //# sourceMappingURL=chunk-ZAXGEDZW.js.map