@loggerjs/browser 0.5.6 → 0.7.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 (60) hide show
  1. package/README.md +13 -16
  2. package/dist/chunks/http-capture-utils-DbhpUirh.cjs +83 -0
  3. package/dist/chunks/http-capture-utils-DbhpUirh.cjs.map +1 -0
  4. package/dist/chunks/http-capture-utils-_hG5wepA.js +48 -0
  5. package/dist/chunks/http-capture-utils-_hG5wepA.js.map +1 -0
  6. package/dist/context-propagation-integration.cjs +5 -4
  7. package/dist/context-propagation-integration.cjs.map +1 -1
  8. package/dist/context-propagation-integration.d.ts +2 -1
  9. package/dist/context-propagation-integration.d.ts.map +1 -1
  10. package/dist/context-propagation-integration.js +2 -1
  11. package/dist/context-propagation-integration.js.map +1 -1
  12. package/dist/fetch-integration.cjs +8 -52
  13. package/dist/fetch-integration.cjs.map +1 -1
  14. package/dist/fetch-integration.js +1 -45
  15. package/dist/fetch-integration.js.map +1 -1
  16. package/dist/http-transport.cjs +121 -29
  17. package/dist/http-transport.cjs.map +1 -1
  18. package/dist/http-transport.d.ts +18 -0
  19. package/dist/http-transport.d.ts.map +1 -1
  20. package/dist/http-transport.js +121 -29
  21. package/dist/http-transport.js.map +1 -1
  22. package/dist/index.cjs +58 -4148
  23. package/dist/index.d.ts +243 -17
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +25 -4116
  26. package/dist/indexeddb-offline-queue.cjs +8 -1
  27. package/dist/indexeddb-offline-queue.cjs.map +1 -1
  28. package/dist/indexeddb-offline-queue.d.ts.map +1 -1
  29. package/dist/indexeddb-offline-queue.js +8 -1
  30. package/dist/indexeddb-offline-queue.js.map +1 -1
  31. package/dist/indexeddb-transport.cjs +24 -4
  32. package/dist/indexeddb-transport.cjs.map +1 -1
  33. package/dist/indexeddb-transport.d.ts.map +1 -1
  34. package/dist/indexeddb-transport.js +24 -4
  35. package/dist/indexeddb-transport.js.map +1 -1
  36. package/dist/offline-first-transport.cjs +3 -1029
  37. package/dist/offline-first-transport.cjs.map +1 -1
  38. package/dist/offline-first-transport.d.ts.map +1 -1
  39. package/dist/offline-first-transport.js +3 -1029
  40. package/dist/offline-first-transport.js.map +1 -1
  41. package/dist/payload-transforms.cjs +3 -3
  42. package/dist/payload-transforms.cjs.map +1 -1
  43. package/dist/payload-transforms.d.ts.map +1 -1
  44. package/dist/payload-transforms.js +1 -1
  45. package/dist/payload-transforms.js.map +1 -1
  46. package/dist/websocket-integration.cjs +5 -32
  47. package/dist/websocket-integration.cjs.map +1 -1
  48. package/dist/websocket-integration.js +1 -28
  49. package/dist/websocket-integration.js.map +1 -1
  50. package/dist/websocket-transport.cjs +1 -1
  51. package/dist/websocket-transport.cjs.map +1 -1
  52. package/dist/websocket-transport.js +2 -2
  53. package/dist/websocket-transport.js.map +1 -1
  54. package/dist/xhr-integration.cjs +6 -33
  55. package/dist/xhr-integration.cjs.map +1 -1
  56. package/dist/xhr-integration.js +1 -28
  57. package/dist/xhr-integration.js.map +1 -1
  58. package/package.json +5 -2
  59. package/dist/index.cjs.map +0 -1
  60. package/dist/index.js.map +0 -1
package/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ <p align="center">
2
+ <a href="https://jskits.github.io/loggerjs/"><img src="https://raw.githubusercontent.com/jskits/loggerjs/main/docs/public/logo.png" alt="LoggerJS logo" width="64" height="64" /></a>
3
+ </p>
4
+
1
5
  # @loggerjs/browser
2
6
 
3
7
  > Browser transports, offline persistence, and 19 automatic integrations — re-exports all of `@loggerjs/core`.
@@ -20,12 +24,12 @@ import {
20
24
  browserHttpTransport,
21
25
  captureBrowserErrorsIntegration,
22
26
  captureConsoleIntegration,
23
- captureFetchIntegration,
24
- captureWebVitalsIntegration,
25
27
  createLogger,
26
28
  memoryBrowserHttpOfflineQueue,
27
29
  pageLifecycleIntegration,
28
30
  } from "@loggerjs/browser";
31
+ import { captureFetchIntegration } from "@loggerjs/browser/integration-fetch";
32
+ import { captureWebVitalsIntegration } from "@loggerjs/browser/integration-web-vitals";
29
33
  import { redactProcessor } from "@loggerjs/processors";
30
34
 
31
35
  const logger = createLogger({
@@ -62,7 +66,7 @@ Logs batch over HTTP, queue while offline, replay with backoff when the network
62
66
  | `browserWebSocketTransport` | a WebSocket (codec-encoded batches, queues while closed) |
63
67
  | `browserServiceWorkerTransport` | a service worker for centralized delivery; `ready()` waits for `serviceWorker.ready` with `target: "ready"` |
64
68
  | `browserBroadcastChannelTransport` | other tabs via `BroadcastChannel` |
65
- | `offlineFirstTransport` | a local store first, then forwards online |
69
+ | `offlineFirstTransport` | your remote transport, queueing to IndexedDB while offline or when delivery fails and replaying later |
66
70
 
67
71
  ### Offline queues & export
68
72
 
@@ -71,8 +75,7 @@ Logs batch over HTTP, queue while offline, replay with backoff when the network
71
75
  - `exportLogsToZip()` + `downloadBlob()` — export a persisted store as a zip containing `logs.ndjson` or `logs.json`, `manifest.json`, optional per-session files, and optional `recent.ndjson` or `recent.json`.
72
76
  - Call the `indexedDbTransport()` instance's `stats()` to read flush, prune, query, drop, and buffer-depth counters.
73
77
 
74
- For a support-log store that survives reloads and exports per page session, the
75
- short setup is:
78
+ For a support-log store that survives reloads and exports per page session, the short setup is:
76
79
 
77
80
  ```ts
78
81
  import { createLogger } from "@loggerjs/core";
@@ -102,17 +105,9 @@ export async function downloadSupportLogs() {
102
105
  }
103
106
  ```
104
107
 
105
- `indexedDbTransport()` assigns a page-session id by default for browser support
106
- stores. Use `query({ sessionId })`, `sessions()`, and
107
- `exportLogsToZip(..., { groupBySession: true, includeRecent: true })` to build
108
- support bundles around reload-sized sessions. Enable `localStorageSpill` only
109
- as a bounded last-chance buffer for the still-unconfirmed memory tail during
110
- ordinary reloads or tab closes; IndexedDB remains the queryable source of truth.
108
+ `indexedDbTransport()` assigns a page-session id by default for browser support stores. Use `query({ sessionId })`, `sessions()`, and `exportLogsToZip(..., { groupBySession: true, includeRecent: true })` to build support bundles around reload-sized sessions. Enable `localStorageSpill` only as a bounded last-chance buffer for the still-unconfirmed memory tail during ordinary reloads or tab closes; IndexedDB remains the queryable source of truth.
111
109
 
112
- Browser delivery has runtime loss windows: tab close can cut off async work,
113
- `sendBeacon` is size- and user-agent-limited, service worker delivery depends on
114
- activation and lifetime, and IndexedDB persistence depends on quota and browser
115
- storage policy. Use an IndexedDB offline queue when reload survival matters.
110
+ Browser delivery has runtime loss windows: tab close can cut off async work, `sendBeacon` is size- and user-agent-limited, service worker delivery depends on activation and lifetime, and IndexedDB persistence depends on quota and browser storage policy. Use an IndexedDB offline queue when reload survival matters.
116
111
 
117
112
  ## Integrations (19)
118
113
 
@@ -134,7 +129,9 @@ const frameworkErrors = captureFrameworkErrorsIntegration({ framework: "react" }
134
129
 
135
130
  ## Subpath exports
136
131
 
137
- Transports — `transport-http` · `transport-indexeddb` · `transport-websocket` · `transport-service-worker` · `transport-broadcast-channel` · `offline-first-transport` · `offline-indexeddb` · `export-zip` · `payload-transforms`
132
+ Transports — `transport-http` · `transport-indexeddb` · `transport-websocket` · `transport-service-worker` · `transport-broadcast-channel` · `offline-first-transport`
133
+
134
+ Utilities — `offline-indexeddb` · `export-zip` · `payload-transforms`
138
135
 
139
136
  Integrations — `integration-console` · `integration-errors` · `integration-framework-errors` · `integration-reporting` · `integration-fetch` · `integration-xhr` · `integration-websocket` · `integration-web-vitals` · `integration-performance` · `integration-router` · `integration-framework-routers` · `integration-page-lifecycle` · `integration-user-actions` · `integration-service-worker` · `integration-runtime-host` · `integration-context`
140
137
 
@@ -0,0 +1,83 @@
1
+ //#region src/http-capture-utils.ts
2
+ function nowMs() {
3
+ return typeof performance !== "undefined" ? performance.now() : Date.now();
4
+ }
5
+ function durationMs(started) {
6
+ return nowMs() - started;
7
+ }
8
+ function sanitizeHttpUrl(rawUrl, sanitizer) {
9
+ const stripped = stripSensitiveUrlParts(rawUrl);
10
+ return sanitizer ? sanitizer(stripped) : stripped;
11
+ }
12
+ function pickAllowedHeaders(headers, allowList) {
13
+ if (!headers || !allowList || allowList.length === 0) return void 0;
14
+ const out = {};
15
+ for (const name of allowList) {
16
+ const value = headers.get(name);
17
+ if (value !== null) out[name.toLowerCase()] = value;
18
+ }
19
+ return Object.keys(out).length > 0 ? out : void 0;
20
+ }
21
+ function headersFromInit(headers) {
22
+ if (!headers) return void 0;
23
+ try {
24
+ return new Headers(headers);
25
+ } catch {
26
+ return;
27
+ }
28
+ }
29
+ function shouldSample(sampleRate, random) {
30
+ if (sampleRate >= 1) return true;
31
+ if (sampleRate <= 0) return false;
32
+ return random() < sampleRate;
33
+ }
34
+ function stripSensitiveUrlParts(rawUrl) {
35
+ if (!/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(rawUrl)) return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
36
+ try {
37
+ const url = new URL(rawUrl);
38
+ url.search = "";
39
+ url.hash = "";
40
+ return url.toString();
41
+ } catch {
42
+ return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
43
+ }
44
+ }
45
+ //#endregion
46
+ Object.defineProperty(exports, "durationMs", {
47
+ enumerable: true,
48
+ get: function() {
49
+ return durationMs;
50
+ }
51
+ });
52
+ Object.defineProperty(exports, "headersFromInit", {
53
+ enumerable: true,
54
+ get: function() {
55
+ return headersFromInit;
56
+ }
57
+ });
58
+ Object.defineProperty(exports, "nowMs", {
59
+ enumerable: true,
60
+ get: function() {
61
+ return nowMs;
62
+ }
63
+ });
64
+ Object.defineProperty(exports, "pickAllowedHeaders", {
65
+ enumerable: true,
66
+ get: function() {
67
+ return pickAllowedHeaders;
68
+ }
69
+ });
70
+ Object.defineProperty(exports, "sanitizeHttpUrl", {
71
+ enumerable: true,
72
+ get: function() {
73
+ return sanitizeHttpUrl;
74
+ }
75
+ });
76
+ Object.defineProperty(exports, "shouldSample", {
77
+ enumerable: true,
78
+ get: function() {
79
+ return shouldSample;
80
+ }
81
+ });
82
+
83
+ //# sourceMappingURL=http-capture-utils-DbhpUirh.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-capture-utils-DbhpUirh.cjs","names":[],"sources":["../../src/http-capture-utils.ts"],"sourcesContent":["export function nowMs(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\nexport function durationMs(started: number): number {\n return nowMs() - started;\n}\n\nexport function sanitizeHttpUrl(rawUrl: string, sanitizer?: (url: string) => string): string {\n const stripped = stripSensitiveUrlParts(rawUrl);\n return sanitizer ? sanitizer(stripped) : stripped;\n}\n\nexport function pickAllowedHeaders(\n headers: Headers | undefined,\n allowList: readonly string[] | undefined,\n): Record<string, string> | undefined {\n if (!headers || !allowList || allowList.length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const name of allowList) {\n const value = headers.get(name);\n if (value !== null) out[name.toLowerCase()] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport function headersFromInit(headers: HeadersInit | undefined): Headers | undefined {\n if (!headers) return undefined;\n try {\n return new Headers(headers);\n } catch {\n return undefined;\n }\n}\n\nexport function shouldSample(sampleRate: number, random: () => number): boolean {\n if (sampleRate >= 1) return true;\n if (sampleRate <= 0) return false;\n return random() < sampleRate;\n}\n\nfunction stripSensitiveUrlParts(rawUrl: string): string {\n if (!/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(rawUrl)) {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n\n try {\n const url = new URL(rawUrl);\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n } catch {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n}\n"],"mappings":";AAAA,SAAgB,QAAgB;CAC9B,OAAO,OAAO,gBAAgB,cAAc,YAAY,IAAI,IAAI,KAAK,IAAI;AAC3E;AAEA,SAAgB,WAAW,SAAyB;CAClD,OAAO,MAAM,IAAI;AACnB;AAEA,SAAgB,gBAAgB,QAAgB,WAA6C;CAC3F,MAAM,WAAW,uBAAuB,MAAM;CAC9C,OAAO,YAAY,UAAU,QAAQ,IAAI;AAC3C;AAEA,SAAgB,mBACd,SACA,WACoC;CACpC,IAAI,CAAC,WAAW,CAAC,aAAa,UAAU,WAAW,GAAG,OAAO,KAAA;CAC7D,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,QAAQ,WAAW;EAC5B,MAAM,QAAQ,QAAQ,IAAI,IAAI;EAC9B,IAAI,UAAU,MAAM,IAAI,KAAK,YAAY,KAAK;CAChD;CACA,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,MAAM,KAAA;AAC7C;AAEA,SAAgB,gBAAgB,SAAuD;CACrF,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI;EACF,OAAO,IAAI,QAAQ,OAAO;CAC5B,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,aAAa,YAAoB,QAA+B;CAC9E,IAAI,cAAc,GAAG,OAAO;CAC5B,IAAI,cAAc,GAAG,OAAO;CAC5B,OAAO,OAAO,IAAI;AACpB;AAEA,SAAS,uBAAuB,QAAwB;CACtD,IAAI,CAAC,2BAA2B,KAAK,MAAM,GACzC,OAAO,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM;CAGvC,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM;EAC1B,IAAI,SAAS;EACb,IAAI,OAAO;EACX,OAAO,IAAI,SAAS;CACtB,QAAQ;EACN,OAAO,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM;CACvC;AACF"}
@@ -0,0 +1,48 @@
1
+ //#region src/http-capture-utils.ts
2
+ function nowMs() {
3
+ return typeof performance !== "undefined" ? performance.now() : Date.now();
4
+ }
5
+ function durationMs(started) {
6
+ return nowMs() - started;
7
+ }
8
+ function sanitizeHttpUrl(rawUrl, sanitizer) {
9
+ const stripped = stripSensitiveUrlParts(rawUrl);
10
+ return sanitizer ? sanitizer(stripped) : stripped;
11
+ }
12
+ function pickAllowedHeaders(headers, allowList) {
13
+ if (!headers || !allowList || allowList.length === 0) return void 0;
14
+ const out = {};
15
+ for (const name of allowList) {
16
+ const value = headers.get(name);
17
+ if (value !== null) out[name.toLowerCase()] = value;
18
+ }
19
+ return Object.keys(out).length > 0 ? out : void 0;
20
+ }
21
+ function headersFromInit(headers) {
22
+ if (!headers) return void 0;
23
+ try {
24
+ return new Headers(headers);
25
+ } catch {
26
+ return;
27
+ }
28
+ }
29
+ function shouldSample(sampleRate, random) {
30
+ if (sampleRate >= 1) return true;
31
+ if (sampleRate <= 0) return false;
32
+ return random() < sampleRate;
33
+ }
34
+ function stripSensitiveUrlParts(rawUrl) {
35
+ if (!/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(rawUrl)) return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
36
+ try {
37
+ const url = new URL(rawUrl);
38
+ url.search = "";
39
+ url.hash = "";
40
+ return url.toString();
41
+ } catch {
42
+ return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
43
+ }
44
+ }
45
+ //#endregion
46
+ export { sanitizeHttpUrl as a, pickAllowedHeaders as i, headersFromInit as n, shouldSample as o, nowMs as r, durationMs as t };
47
+
48
+ //# sourceMappingURL=http-capture-utils-_hG5wepA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-capture-utils-_hG5wepA.js","names":[],"sources":["../../src/http-capture-utils.ts"],"sourcesContent":["export function nowMs(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\nexport function durationMs(started: number): number {\n return nowMs() - started;\n}\n\nexport function sanitizeHttpUrl(rawUrl: string, sanitizer?: (url: string) => string): string {\n const stripped = stripSensitiveUrlParts(rawUrl);\n return sanitizer ? sanitizer(stripped) : stripped;\n}\n\nexport function pickAllowedHeaders(\n headers: Headers | undefined,\n allowList: readonly string[] | undefined,\n): Record<string, string> | undefined {\n if (!headers || !allowList || allowList.length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const name of allowList) {\n const value = headers.get(name);\n if (value !== null) out[name.toLowerCase()] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport function headersFromInit(headers: HeadersInit | undefined): Headers | undefined {\n if (!headers) return undefined;\n try {\n return new Headers(headers);\n } catch {\n return undefined;\n }\n}\n\nexport function shouldSample(sampleRate: number, random: () => number): boolean {\n if (sampleRate >= 1) return true;\n if (sampleRate <= 0) return false;\n return random() < sampleRate;\n}\n\nfunction stripSensitiveUrlParts(rawUrl: string): string {\n if (!/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(rawUrl)) {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n\n try {\n const url = new URL(rawUrl);\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n } catch {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n}\n"],"mappings":";AAAA,SAAgB,QAAgB;CAC9B,OAAO,OAAO,gBAAgB,cAAc,YAAY,IAAI,IAAI,KAAK,IAAI;AAC3E;AAEA,SAAgB,WAAW,SAAyB;CAClD,OAAO,MAAM,IAAI;AACnB;AAEA,SAAgB,gBAAgB,QAAgB,WAA6C;CAC3F,MAAM,WAAW,uBAAuB,MAAM;CAC9C,OAAO,YAAY,UAAU,QAAQ,IAAI;AAC3C;AAEA,SAAgB,mBACd,SACA,WACoC;CACpC,IAAI,CAAC,WAAW,CAAC,aAAa,UAAU,WAAW,GAAG,OAAO,KAAA;CAC7D,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,QAAQ,WAAW;EAC5B,MAAM,QAAQ,QAAQ,IAAI,IAAI;EAC9B,IAAI,UAAU,MAAM,IAAI,KAAK,YAAY,KAAK;CAChD;CACA,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,MAAM,KAAA;AAC7C;AAEA,SAAgB,gBAAgB,SAAuD;CACrF,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI;EACF,OAAO,IAAI,QAAQ,OAAO;CAC5B,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,aAAa,YAAoB,QAA+B;CAC9E,IAAI,cAAc,GAAG,OAAO;CAC5B,IAAI,cAAc,GAAG,OAAO;CAC5B,OAAO,OAAO,IAAI;AACpB;AAEA,SAAS,uBAAuB,QAAwB;CACtD,IAAI,CAAC,2BAA2B,KAAK,MAAM,GACzC,OAAO,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM;CAGvC,IAAI;EACF,MAAM,MAAM,IAAI,IAAI,MAAM;EAC1B,IAAI,SAAS;EACb,IAAI,OAAO;EACX,OAAO,IAAI,SAAS;CACtB,QAAQ;EACN,OAAO,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM;CACvC;AACF"}
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _loggerjs_core = require("@loggerjs/core");
3
+ let _loggerjs_core_trace_propagation = require("@loggerjs/core/trace-propagation");
3
4
  //#region src/context-propagation-integration.ts
4
5
  const defaultActionEvents = [
5
6
  "click",
@@ -17,7 +18,7 @@ function resolveValue(value) {
17
18
  return typeof value === "function" ? value() : value;
18
19
  }
19
20
  function normalizeBaggage(value) {
20
- if (typeof value === "string") return (0, _loggerjs_core.parseBaggage)(value);
21
+ if (typeof value === "string") return (0, _loggerjs_core_trace_propagation.parseBaggage)(value);
21
22
  return value;
22
23
  }
23
24
  function actionTargetName(target) {
@@ -38,9 +39,9 @@ function browserContextPropagationIntegration(options = {}) {
38
39
  const disposeProvider = (0, _loggerjs_core.addContextProvider)(() => {
39
40
  const sessionId = resolveValue(options.sessionId);
40
41
  const requestId = options.requestId?.();
41
- const trace = resolveValue(options.trace) ?? (0, _loggerjs_core.parseTraceparent)(resolveValue(options.traceparent));
42
+ const trace = resolveValue(options.trace) ?? (0, _loggerjs_core_trace_propagation.parseTraceparent)(resolveValue(options.traceparent));
42
43
  const baggage = normalizeBaggage(resolveValue(options.baggage)) ?? trace?.baggage;
43
- const traceparent = (0, _loggerjs_core.formatTraceparent)(trace);
44
+ const traceparent = (0, _loggerjs_core_trace_propagation.formatTraceparent)(trace);
44
45
  const now = clock();
45
46
  const action = lastAction && now - lastAction.time <= actionTtlMs ? {
46
47
  actionId: lastAction.id,
@@ -51,7 +52,7 @@ function browserContextPropagationIntegration(options = {}) {
51
52
  sessionId,
52
53
  requestId,
53
54
  traceparent,
54
- baggage: (0, _loggerjs_core.formatBaggage)(baggage),
55
+ baggage: (0, _loggerjs_core_trace_propagation.formatBaggage)(baggage),
55
56
  ...action
56
57
  };
57
58
  });
@@ -1 +1 @@
1
- {"version":3,"file":"context-propagation-integration.cjs","names":[],"sources":["../src/context-propagation-integration.ts"],"sourcesContent":["import {\n addContextProvider,\n formatBaggage,\n formatTraceparent,\n parseBaggage,\n parseTraceparent,\n type Baggage,\n type Integration,\n type TraceContext,\n} from \"@loggerjs/core\";\n\nexport type BrowserContextActionEventName = \"change\" | \"click\" | \"input\" | \"keydown\" | \"submit\";\n\nexport interface BrowserContextEventTargetLike {\n addEventListener: typeof globalThis.addEventListener;\n removeEventListener: typeof globalThis.removeEventListener;\n}\n\nexport interface BrowserContextPropagationOptions {\n sessionId?: string | (() => string | undefined);\n requestId?: () => string | undefined;\n trace?: TraceContext | (() => TraceContext | undefined);\n traceparent?: string | (() => string | undefined);\n baggage?: Baggage | string | (() => Baggage | string | undefined);\n actionEvents?: readonly BrowserContextActionEventName[];\n actionTtlMs?: number;\n root?: BrowserContextEventTargetLike;\n clock?: () => number;\n idFactory?: () => string;\n}\n\nconst defaultActionEvents: readonly BrowserContextActionEventName[] = [\n \"click\",\n \"input\",\n \"change\",\n \"submit\",\n];\n\nlet fallbackIdSeq = 0;\n\nfunction defaultIdFactory(): string {\n const cryptoRandomUUID = globalThis.crypto?.randomUUID;\n if (cryptoRandomUUID) return cryptoRandomUUID.call(globalThis.crypto);\n return `${Date.now().toString(36)}-${(fallbackIdSeq++).toString(36)}`;\n}\n\nfunction resolveValue<T>(value: T | (() => T | undefined) | undefined): T | undefined {\n return typeof value === \"function\" ? (value as () => T | undefined)() : value;\n}\n\nfunction normalizeBaggage(value: Baggage | string | undefined): Baggage | undefined {\n if (typeof value === \"string\") return parseBaggage(value);\n return value;\n}\n\nfunction actionTargetName(target: EventTarget | null): string | undefined {\n const item = target as { tagName?: string; id?: string; name?: string } | null;\n if (!item) return undefined;\n return item.id || item.name || item.tagName?.toLowerCase();\n}\n\nexport function browserContextPropagationIntegration(\n options: BrowserContextPropagationOptions = {},\n): Integration {\n const actionEvents = options.actionEvents ?? defaultActionEvents;\n const actionTtlMs = Math.max(0, Math.floor(options.actionTtlMs ?? 5000));\n const clock = options.clock ?? Date.now;\n const idFactory = options.idFactory ?? defaultIdFactory;\n let lastAction:\n | {\n id: string;\n type: string;\n target?: string;\n time: number;\n }\n | undefined;\n\n return {\n name: \"browser-context-propagation\",\n setup() {\n const root = options.root ?? globalThis.document;\n const disposeProvider = addContextProvider(() => {\n const sessionId = resolveValue(options.sessionId);\n const requestId = options.requestId?.();\n const explicitTrace = resolveValue(options.trace);\n const trace = explicitTrace ?? parseTraceparent(resolveValue(options.traceparent));\n const baggage = normalizeBaggage(resolveValue(options.baggage)) ?? trace?.baggage;\n const traceparent = formatTraceparent(trace);\n const now = clock();\n const action =\n lastAction && now - lastAction.time <= actionTtlMs\n ? {\n actionId: lastAction.id,\n actionType: lastAction.type,\n actionTarget: lastAction.target,\n }\n : undefined;\n\n return {\n sessionId,\n requestId,\n traceparent,\n baggage: formatBaggage(baggage),\n ...action,\n };\n });\n\n if (!root?.addEventListener || !root.removeEventListener || actionEvents.length === 0) {\n return disposeProvider;\n }\n\n const onAction = (event: Event) => {\n lastAction = {\n id: idFactory(),\n type: event.type,\n target: actionTargetName(event.target),\n time: clock(),\n };\n };\n\n for (const event of actionEvents) root.addEventListener(event, onAction, true);\n\n return () => {\n for (const event of actionEvents) root.removeEventListener(event, onAction, true);\n disposeProvider();\n };\n },\n };\n}\n"],"mappings":";;;AA+BA,MAAM,sBAAgE;CACpE;CACA;CACA;CACA;AACF;AAEA,IAAI,gBAAgB;AAEpB,SAAS,mBAA2B;CAClC,MAAM,mBAAmB,WAAW,QAAQ;CAC5C,IAAI,kBAAkB,OAAO,iBAAiB,KAAK,WAAW,MAAM;CACpE,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,gBAAA,CAAiB,SAAS,EAAE;AACpE;AAEA,SAAS,aAAgB,OAA6D;CACpF,OAAO,OAAO,UAAU,aAAc,MAA8B,IAAI;AAC1E;AAEA,SAAS,iBAAiB,OAA0D;CAClF,IAAI,OAAO,UAAU,UAAU,QAAA,GAAA,eAAA,aAAA,CAAoB,KAAK;CACxD,OAAO;AACT;AAEA,SAAS,iBAAiB,QAAgD;CACxE,MAAM,OAAO;CACb,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO,KAAK,MAAM,KAAK,QAAQ,KAAK,SAAS,YAAY;AAC3D;AAEA,SAAgB,qCACd,UAA4C,CAAC,GAChC;CACb,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,GAAI,CAAC;CACvE,MAAM,QAAQ,QAAQ,SAAS,KAAK;CACpC,MAAM,YAAY,QAAQ,aAAa;CACvC,IAAI;CASJ,OAAO;EACL,MAAM;EACN,QAAQ;GACN,MAAM,OAAO,QAAQ,QAAQ,WAAW;GACxC,MAAM,mBAAA,GAAA,eAAA,mBAAA,OAA2C;IAC/C,MAAM,YAAY,aAAa,QAAQ,SAAS;IAChD,MAAM,YAAY,QAAQ,YAAY;IAEtC,MAAM,QADgB,aAAa,QAAQ,KACjB,MAAA,GAAA,eAAA,iBAAA,CAAsB,aAAa,QAAQ,WAAW,CAAC;IACjF,MAAM,UAAU,iBAAiB,aAAa,QAAQ,OAAO,CAAC,KAAK,OAAO;IAC1E,MAAM,eAAA,GAAA,eAAA,kBAAA,CAAgC,KAAK;IAC3C,MAAM,MAAM,MAAM;IAClB,MAAM,SACJ,cAAc,MAAM,WAAW,QAAQ,cACnC;KACE,UAAU,WAAW;KACrB,YAAY,WAAW;KACvB,cAAc,WAAW;IAC3B,IACA,KAAA;IAEN,OAAO;KACL;KACA;KACA;KACA,UAAA,GAAA,eAAA,cAAA,CAAuB,OAAO;KAC9B,GAAG;IACL;GACF,CAAC;GAED,IAAI,CAAC,MAAM,oBAAoB,CAAC,KAAK,uBAAuB,aAAa,WAAW,GAClF,OAAO;GAGT,MAAM,YAAY,UAAiB;IACjC,aAAa;KACX,IAAI,UAAU;KACd,MAAM,MAAM;KACZ,QAAQ,iBAAiB,MAAM,MAAM;KACrC,MAAM,MAAM;IACd;GACF;GAEA,KAAK,MAAM,SAAS,cAAc,KAAK,iBAAiB,OAAO,UAAU,IAAI;GAE7E,aAAa;IACX,KAAK,MAAM,SAAS,cAAc,KAAK,oBAAoB,OAAO,UAAU,IAAI;IAChF,gBAAgB;GAClB;EACF;CACF;AACF"}
1
+ {"version":3,"file":"context-propagation-integration.cjs","names":[],"sources":["../src/context-propagation-integration.ts"],"sourcesContent":["import { addContextProvider, type Integration, type TraceContext } from \"@loggerjs/core\";\nimport {\n formatBaggage,\n formatTraceparent,\n parseBaggage,\n parseTraceparent,\n type Baggage,\n} from \"@loggerjs/core/trace-propagation\";\n\nexport type BrowserContextActionEventName = \"change\" | \"click\" | \"input\" | \"keydown\" | \"submit\";\n\nexport interface BrowserContextEventTargetLike {\n addEventListener: typeof globalThis.addEventListener;\n removeEventListener: typeof globalThis.removeEventListener;\n}\n\nexport interface BrowserContextPropagationOptions {\n sessionId?: string | (() => string | undefined);\n requestId?: () => string | undefined;\n trace?: TraceContext | (() => TraceContext | undefined);\n traceparent?: string | (() => string | undefined);\n baggage?: Baggage | string | (() => Baggage | string | undefined);\n actionEvents?: readonly BrowserContextActionEventName[];\n actionTtlMs?: number;\n root?: BrowserContextEventTargetLike;\n clock?: () => number;\n idFactory?: () => string;\n}\n\nconst defaultActionEvents: readonly BrowserContextActionEventName[] = [\n \"click\",\n \"input\",\n \"change\",\n \"submit\",\n];\n\nlet fallbackIdSeq = 0;\n\nfunction defaultIdFactory(): string {\n const cryptoRandomUUID = globalThis.crypto?.randomUUID;\n if (cryptoRandomUUID) return cryptoRandomUUID.call(globalThis.crypto);\n return `${Date.now().toString(36)}-${(fallbackIdSeq++).toString(36)}`;\n}\n\nfunction resolveValue<T>(value: T | (() => T | undefined) | undefined): T | undefined {\n return typeof value === \"function\" ? (value as () => T | undefined)() : value;\n}\n\nfunction normalizeBaggage(value: Baggage | string | undefined): Baggage | undefined {\n if (typeof value === \"string\") return parseBaggage(value);\n return value;\n}\n\nfunction actionTargetName(target: EventTarget | null): string | undefined {\n const item = target as { tagName?: string; id?: string; name?: string } | null;\n if (!item) return undefined;\n return item.id || item.name || item.tagName?.toLowerCase();\n}\n\nexport function browserContextPropagationIntegration(\n options: BrowserContextPropagationOptions = {},\n): Integration {\n const actionEvents = options.actionEvents ?? defaultActionEvents;\n const actionTtlMs = Math.max(0, Math.floor(options.actionTtlMs ?? 5000));\n const clock = options.clock ?? Date.now;\n const idFactory = options.idFactory ?? defaultIdFactory;\n let lastAction:\n | {\n id: string;\n type: string;\n target?: string;\n time: number;\n }\n | undefined;\n\n return {\n name: \"browser-context-propagation\",\n setup() {\n const root = options.root ?? globalThis.document;\n const disposeProvider = addContextProvider(() => {\n const sessionId = resolveValue(options.sessionId);\n const requestId = options.requestId?.();\n const explicitTrace = resolveValue(options.trace);\n const trace = explicitTrace ?? parseTraceparent(resolveValue(options.traceparent));\n const baggage = normalizeBaggage(resolveValue(options.baggage)) ?? trace?.baggage;\n const traceparent = formatTraceparent(trace);\n const now = clock();\n const action =\n lastAction && now - lastAction.time <= actionTtlMs\n ? {\n actionId: lastAction.id,\n actionType: lastAction.type,\n actionTarget: lastAction.target,\n }\n : undefined;\n\n return {\n sessionId,\n requestId,\n traceparent,\n baggage: formatBaggage(baggage),\n ...action,\n };\n });\n\n if (!root?.addEventListener || !root.removeEventListener || actionEvents.length === 0) {\n return disposeProvider;\n }\n\n const onAction = (event: Event) => {\n lastAction = {\n id: idFactory(),\n type: event.type,\n target: actionTargetName(event.target),\n time: clock(),\n };\n };\n\n for (const event of actionEvents) root.addEventListener(event, onAction, true);\n\n return () => {\n for (const event of actionEvents) root.removeEventListener(event, onAction, true);\n disposeProvider();\n };\n },\n };\n}\n"],"mappings":";;;;AA6BA,MAAM,sBAAgE;CACpE;CACA;CACA;CACA;AACF;AAEA,IAAI,gBAAgB;AAEpB,SAAS,mBAA2B;CAClC,MAAM,mBAAmB,WAAW,QAAQ;CAC5C,IAAI,kBAAkB,OAAO,iBAAiB,KAAK,WAAW,MAAM;CACpE,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,gBAAA,CAAiB,SAAS,EAAE;AACpE;AAEA,SAAS,aAAgB,OAA6D;CACpF,OAAO,OAAO,UAAU,aAAc,MAA8B,IAAI;AAC1E;AAEA,SAAS,iBAAiB,OAA0D;CAClF,IAAI,OAAO,UAAU,UAAU,QAAA,GAAA,iCAAA,aAAA,CAAoB,KAAK;CACxD,OAAO;AACT;AAEA,SAAS,iBAAiB,QAAgD;CACxE,MAAM,OAAO;CACb,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO,KAAK,MAAM,KAAK,QAAQ,KAAK,SAAS,YAAY;AAC3D;AAEA,SAAgB,qCACd,UAA4C,CAAC,GAChC;CACb,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,GAAI,CAAC;CACvE,MAAM,QAAQ,QAAQ,SAAS,KAAK;CACpC,MAAM,YAAY,QAAQ,aAAa;CACvC,IAAI;CASJ,OAAO;EACL,MAAM;EACN,QAAQ;GACN,MAAM,OAAO,QAAQ,QAAQ,WAAW;GACxC,MAAM,mBAAA,GAAA,eAAA,mBAAA,OAA2C;IAC/C,MAAM,YAAY,aAAa,QAAQ,SAAS;IAChD,MAAM,YAAY,QAAQ,YAAY;IAEtC,MAAM,QADgB,aAAa,QAAQ,KACjB,MAAA,GAAA,iCAAA,iBAAA,CAAsB,aAAa,QAAQ,WAAW,CAAC;IACjF,MAAM,UAAU,iBAAiB,aAAa,QAAQ,OAAO,CAAC,KAAK,OAAO;IAC1E,MAAM,eAAA,GAAA,iCAAA,kBAAA,CAAgC,KAAK;IAC3C,MAAM,MAAM,MAAM;IAClB,MAAM,SACJ,cAAc,MAAM,WAAW,QAAQ,cACnC;KACE,UAAU,WAAW;KACrB,YAAY,WAAW;KACvB,cAAc,WAAW;IAC3B,IACA,KAAA;IAEN,OAAO;KACL;KACA;KACA;KACA,UAAA,GAAA,iCAAA,cAAA,CAAuB,OAAO;KAC9B,GAAG;IACL;GACF,CAAC;GAED,IAAI,CAAC,MAAM,oBAAoB,CAAC,KAAK,uBAAuB,aAAa,WAAW,GAClF,OAAO;GAGT,MAAM,YAAY,UAAiB;IACjC,aAAa;KACX,IAAI,UAAU;KACd,MAAM,MAAM;KACZ,QAAQ,iBAAiB,MAAM,MAAM;KACrC,MAAM,MAAM;IACd;GACF;GAEA,KAAK,MAAM,SAAS,cAAc,KAAK,iBAAiB,OAAO,UAAU,IAAI;GAE7E,aAAa;IACX,KAAK,MAAM,SAAS,cAAc,KAAK,oBAAoB,OAAO,UAAU,IAAI;IAChF,gBAAgB;GAClB;EACF;CACF;AACF"}
@@ -1,4 +1,5 @@
1
- import { type Baggage, type Integration, type TraceContext } from "@loggerjs/core";
1
+ import { type Integration, type TraceContext } from "@loggerjs/core";
2
+ import { type Baggage } from "@loggerjs/core/trace-propagation";
2
3
  export type BrowserContextActionEventName = "change" | "click" | "input" | "keydown" | "submit";
3
4
  export interface BrowserContextEventTargetLike {
4
5
  addEventListener: typeof globalThis.addEventListener;
@@ -1 +1 @@
1
- {"version":3,"file":"context-propagation-integration.d.ts","sourceRoot":"","sources":["../src/context-propagation-integration.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,6BAA6B,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhG,MAAM,WAAW,6BAA6B;IAC5C,gBAAgB,EAAE,OAAO,UAAU,CAAC,gBAAgB,CAAC;IACrD,mBAAmB,EAAE,OAAO,UAAU,CAAC,mBAAmB,CAAC;CAC5D;AAED,MAAM,WAAW,gCAAgC;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACrC,KAAK,CAAC,EAAE,YAAY,GAAG,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,YAAY,CAAC,EAAE,SAAS,6BAA6B,EAAE,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,6BAA6B,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;CAC1B;AAgCD,wBAAgB,oCAAoC,CAClD,OAAO,GAAE,gCAAqC,GAC7C,WAAW,CAiEb"}
1
+ {"version":3,"file":"context-propagation-integration.d.ts","sourceRoot":"","sources":["../src/context-propagation-integration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,kCAAkC,CAAC;AAE1C,MAAM,MAAM,6BAA6B,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhG,MAAM,WAAW,6BAA6B;IAC5C,gBAAgB,EAAE,OAAO,UAAU,CAAC,gBAAgB,CAAC;IACrD,mBAAmB,EAAE,OAAO,UAAU,CAAC,mBAAmB,CAAC;CAC5D;AAED,MAAM,WAAW,gCAAgC;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACrC,KAAK,CAAC,EAAE,YAAY,GAAG,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,YAAY,CAAC,EAAE,SAAS,6BAA6B,EAAE,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,6BAA6B,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;CAC1B;AAgCD,wBAAgB,oCAAoC,CAClD,OAAO,GAAE,gCAAqC,GAC7C,WAAW,CAiEb"}
@@ -1,4 +1,5 @@
1
- import { addContextProvider, formatBaggage, formatTraceparent, parseBaggage, parseTraceparent } from "@loggerjs/core";
1
+ import { addContextProvider } from "@loggerjs/core";
2
+ import { formatBaggage, formatTraceparent, parseBaggage, parseTraceparent } from "@loggerjs/core/trace-propagation";
2
3
  //#region src/context-propagation-integration.ts
3
4
  const defaultActionEvents = [
4
5
  "click",
@@ -1 +1 @@
1
- {"version":3,"file":"context-propagation-integration.js","names":[],"sources":["../src/context-propagation-integration.ts"],"sourcesContent":["import {\n addContextProvider,\n formatBaggage,\n formatTraceparent,\n parseBaggage,\n parseTraceparent,\n type Baggage,\n type Integration,\n type TraceContext,\n} from \"@loggerjs/core\";\n\nexport type BrowserContextActionEventName = \"change\" | \"click\" | \"input\" | \"keydown\" | \"submit\";\n\nexport interface BrowserContextEventTargetLike {\n addEventListener: typeof globalThis.addEventListener;\n removeEventListener: typeof globalThis.removeEventListener;\n}\n\nexport interface BrowserContextPropagationOptions {\n sessionId?: string | (() => string | undefined);\n requestId?: () => string | undefined;\n trace?: TraceContext | (() => TraceContext | undefined);\n traceparent?: string | (() => string | undefined);\n baggage?: Baggage | string | (() => Baggage | string | undefined);\n actionEvents?: readonly BrowserContextActionEventName[];\n actionTtlMs?: number;\n root?: BrowserContextEventTargetLike;\n clock?: () => number;\n idFactory?: () => string;\n}\n\nconst defaultActionEvents: readonly BrowserContextActionEventName[] = [\n \"click\",\n \"input\",\n \"change\",\n \"submit\",\n];\n\nlet fallbackIdSeq = 0;\n\nfunction defaultIdFactory(): string {\n const cryptoRandomUUID = globalThis.crypto?.randomUUID;\n if (cryptoRandomUUID) return cryptoRandomUUID.call(globalThis.crypto);\n return `${Date.now().toString(36)}-${(fallbackIdSeq++).toString(36)}`;\n}\n\nfunction resolveValue<T>(value: T | (() => T | undefined) | undefined): T | undefined {\n return typeof value === \"function\" ? (value as () => T | undefined)() : value;\n}\n\nfunction normalizeBaggage(value: Baggage | string | undefined): Baggage | undefined {\n if (typeof value === \"string\") return parseBaggage(value);\n return value;\n}\n\nfunction actionTargetName(target: EventTarget | null): string | undefined {\n const item = target as { tagName?: string; id?: string; name?: string } | null;\n if (!item) return undefined;\n return item.id || item.name || item.tagName?.toLowerCase();\n}\n\nexport function browserContextPropagationIntegration(\n options: BrowserContextPropagationOptions = {},\n): Integration {\n const actionEvents = options.actionEvents ?? defaultActionEvents;\n const actionTtlMs = Math.max(0, Math.floor(options.actionTtlMs ?? 5000));\n const clock = options.clock ?? Date.now;\n const idFactory = options.idFactory ?? defaultIdFactory;\n let lastAction:\n | {\n id: string;\n type: string;\n target?: string;\n time: number;\n }\n | undefined;\n\n return {\n name: \"browser-context-propagation\",\n setup() {\n const root = options.root ?? globalThis.document;\n const disposeProvider = addContextProvider(() => {\n const sessionId = resolveValue(options.sessionId);\n const requestId = options.requestId?.();\n const explicitTrace = resolveValue(options.trace);\n const trace = explicitTrace ?? parseTraceparent(resolveValue(options.traceparent));\n const baggage = normalizeBaggage(resolveValue(options.baggage)) ?? trace?.baggage;\n const traceparent = formatTraceparent(trace);\n const now = clock();\n const action =\n lastAction && now - lastAction.time <= actionTtlMs\n ? {\n actionId: lastAction.id,\n actionType: lastAction.type,\n actionTarget: lastAction.target,\n }\n : undefined;\n\n return {\n sessionId,\n requestId,\n traceparent,\n baggage: formatBaggage(baggage),\n ...action,\n };\n });\n\n if (!root?.addEventListener || !root.removeEventListener || actionEvents.length === 0) {\n return disposeProvider;\n }\n\n const onAction = (event: Event) => {\n lastAction = {\n id: idFactory(),\n type: event.type,\n target: actionTargetName(event.target),\n time: clock(),\n };\n };\n\n for (const event of actionEvents) root.addEventListener(event, onAction, true);\n\n return () => {\n for (const event of actionEvents) root.removeEventListener(event, onAction, true);\n disposeProvider();\n };\n },\n };\n}\n"],"mappings":";;AA+BA,MAAM,sBAAgE;CACpE;CACA;CACA;CACA;AACF;AAEA,IAAI,gBAAgB;AAEpB,SAAS,mBAA2B;CAClC,MAAM,mBAAmB,WAAW,QAAQ;CAC5C,IAAI,kBAAkB,OAAO,iBAAiB,KAAK,WAAW,MAAM;CACpE,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,gBAAA,CAAiB,SAAS,EAAE;AACpE;AAEA,SAAS,aAAgB,OAA6D;CACpF,OAAO,OAAO,UAAU,aAAc,MAA8B,IAAI;AAC1E;AAEA,SAAS,iBAAiB,OAA0D;CAClF,IAAI,OAAO,UAAU,UAAU,OAAO,aAAa,KAAK;CACxD,OAAO;AACT;AAEA,SAAS,iBAAiB,QAAgD;CACxE,MAAM,OAAO;CACb,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO,KAAK,MAAM,KAAK,QAAQ,KAAK,SAAS,YAAY;AAC3D;AAEA,SAAgB,qCACd,UAA4C,CAAC,GAChC;CACb,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,GAAI,CAAC;CACvE,MAAM,QAAQ,QAAQ,SAAS,KAAK;CACpC,MAAM,YAAY,QAAQ,aAAa;CACvC,IAAI;CASJ,OAAO;EACL,MAAM;EACN,QAAQ;GACN,MAAM,OAAO,QAAQ,QAAQ,WAAW;GACxC,MAAM,kBAAkB,yBAAyB;IAC/C,MAAM,YAAY,aAAa,QAAQ,SAAS;IAChD,MAAM,YAAY,QAAQ,YAAY;IAEtC,MAAM,QADgB,aAAa,QAAQ,KACjB,KAAK,iBAAiB,aAAa,QAAQ,WAAW,CAAC;IACjF,MAAM,UAAU,iBAAiB,aAAa,QAAQ,OAAO,CAAC,KAAK,OAAO;IAC1E,MAAM,cAAc,kBAAkB,KAAK;IAC3C,MAAM,MAAM,MAAM;IAClB,MAAM,SACJ,cAAc,MAAM,WAAW,QAAQ,cACnC;KACE,UAAU,WAAW;KACrB,YAAY,WAAW;KACvB,cAAc,WAAW;IAC3B,IACA,KAAA;IAEN,OAAO;KACL;KACA;KACA;KACA,SAAS,cAAc,OAAO;KAC9B,GAAG;IACL;GACF,CAAC;GAED,IAAI,CAAC,MAAM,oBAAoB,CAAC,KAAK,uBAAuB,aAAa,WAAW,GAClF,OAAO;GAGT,MAAM,YAAY,UAAiB;IACjC,aAAa;KACX,IAAI,UAAU;KACd,MAAM,MAAM;KACZ,QAAQ,iBAAiB,MAAM,MAAM;KACrC,MAAM,MAAM;IACd;GACF;GAEA,KAAK,MAAM,SAAS,cAAc,KAAK,iBAAiB,OAAO,UAAU,IAAI;GAE7E,aAAa;IACX,KAAK,MAAM,SAAS,cAAc,KAAK,oBAAoB,OAAO,UAAU,IAAI;IAChF,gBAAgB;GAClB;EACF;CACF;AACF"}
1
+ {"version":3,"file":"context-propagation-integration.js","names":[],"sources":["../src/context-propagation-integration.ts"],"sourcesContent":["import { addContextProvider, type Integration, type TraceContext } from \"@loggerjs/core\";\nimport {\n formatBaggage,\n formatTraceparent,\n parseBaggage,\n parseTraceparent,\n type Baggage,\n} from \"@loggerjs/core/trace-propagation\";\n\nexport type BrowserContextActionEventName = \"change\" | \"click\" | \"input\" | \"keydown\" | \"submit\";\n\nexport interface BrowserContextEventTargetLike {\n addEventListener: typeof globalThis.addEventListener;\n removeEventListener: typeof globalThis.removeEventListener;\n}\n\nexport interface BrowserContextPropagationOptions {\n sessionId?: string | (() => string | undefined);\n requestId?: () => string | undefined;\n trace?: TraceContext | (() => TraceContext | undefined);\n traceparent?: string | (() => string | undefined);\n baggage?: Baggage | string | (() => Baggage | string | undefined);\n actionEvents?: readonly BrowserContextActionEventName[];\n actionTtlMs?: number;\n root?: BrowserContextEventTargetLike;\n clock?: () => number;\n idFactory?: () => string;\n}\n\nconst defaultActionEvents: readonly BrowserContextActionEventName[] = [\n \"click\",\n \"input\",\n \"change\",\n \"submit\",\n];\n\nlet fallbackIdSeq = 0;\n\nfunction defaultIdFactory(): string {\n const cryptoRandomUUID = globalThis.crypto?.randomUUID;\n if (cryptoRandomUUID) return cryptoRandomUUID.call(globalThis.crypto);\n return `${Date.now().toString(36)}-${(fallbackIdSeq++).toString(36)}`;\n}\n\nfunction resolveValue<T>(value: T | (() => T | undefined) | undefined): T | undefined {\n return typeof value === \"function\" ? (value as () => T | undefined)() : value;\n}\n\nfunction normalizeBaggage(value: Baggage | string | undefined): Baggage | undefined {\n if (typeof value === \"string\") return parseBaggage(value);\n return value;\n}\n\nfunction actionTargetName(target: EventTarget | null): string | undefined {\n const item = target as { tagName?: string; id?: string; name?: string } | null;\n if (!item) return undefined;\n return item.id || item.name || item.tagName?.toLowerCase();\n}\n\nexport function browserContextPropagationIntegration(\n options: BrowserContextPropagationOptions = {},\n): Integration {\n const actionEvents = options.actionEvents ?? defaultActionEvents;\n const actionTtlMs = Math.max(0, Math.floor(options.actionTtlMs ?? 5000));\n const clock = options.clock ?? Date.now;\n const idFactory = options.idFactory ?? defaultIdFactory;\n let lastAction:\n | {\n id: string;\n type: string;\n target?: string;\n time: number;\n }\n | undefined;\n\n return {\n name: \"browser-context-propagation\",\n setup() {\n const root = options.root ?? globalThis.document;\n const disposeProvider = addContextProvider(() => {\n const sessionId = resolveValue(options.sessionId);\n const requestId = options.requestId?.();\n const explicitTrace = resolveValue(options.trace);\n const trace = explicitTrace ?? parseTraceparent(resolveValue(options.traceparent));\n const baggage = normalizeBaggage(resolveValue(options.baggage)) ?? trace?.baggage;\n const traceparent = formatTraceparent(trace);\n const now = clock();\n const action =\n lastAction && now - lastAction.time <= actionTtlMs\n ? {\n actionId: lastAction.id,\n actionType: lastAction.type,\n actionTarget: lastAction.target,\n }\n : undefined;\n\n return {\n sessionId,\n requestId,\n traceparent,\n baggage: formatBaggage(baggage),\n ...action,\n };\n });\n\n if (!root?.addEventListener || !root.removeEventListener || actionEvents.length === 0) {\n return disposeProvider;\n }\n\n const onAction = (event: Event) => {\n lastAction = {\n id: idFactory(),\n type: event.type,\n target: actionTargetName(event.target),\n time: clock(),\n };\n };\n\n for (const event of actionEvents) root.addEventListener(event, onAction, true);\n\n return () => {\n for (const event of actionEvents) root.removeEventListener(event, onAction, true);\n disposeProvider();\n };\n },\n };\n}\n"],"mappings":";;;AA6BA,MAAM,sBAAgE;CACpE;CACA;CACA;CACA;AACF;AAEA,IAAI,gBAAgB;AAEpB,SAAS,mBAA2B;CAClC,MAAM,mBAAmB,WAAW,QAAQ;CAC5C,IAAI,kBAAkB,OAAO,iBAAiB,KAAK,WAAW,MAAM;CACpE,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,IAAI,gBAAA,CAAiB,SAAS,EAAE;AACpE;AAEA,SAAS,aAAgB,OAA6D;CACpF,OAAO,OAAO,UAAU,aAAc,MAA8B,IAAI;AAC1E;AAEA,SAAS,iBAAiB,OAA0D;CAClF,IAAI,OAAO,UAAU,UAAU,OAAO,aAAa,KAAK;CACxD,OAAO;AACT;AAEA,SAAS,iBAAiB,QAAgD;CACxE,MAAM,OAAO;CACb,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO,KAAK,MAAM,KAAK,QAAQ,KAAK,SAAS,YAAY;AAC3D;AAEA,SAAgB,qCACd,UAA4C,CAAC,GAChC;CACb,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,GAAI,CAAC;CACvE,MAAM,QAAQ,QAAQ,SAAS,KAAK;CACpC,MAAM,YAAY,QAAQ,aAAa;CACvC,IAAI;CASJ,OAAO;EACL,MAAM;EACN,QAAQ;GACN,MAAM,OAAO,QAAQ,QAAQ,WAAW;GACxC,MAAM,kBAAkB,yBAAyB;IAC/C,MAAM,YAAY,aAAa,QAAQ,SAAS;IAChD,MAAM,YAAY,QAAQ,YAAY;IAEtC,MAAM,QADgB,aAAa,QAAQ,KACjB,KAAK,iBAAiB,aAAa,QAAQ,WAAW,CAAC;IACjF,MAAM,UAAU,iBAAiB,aAAa,QAAQ,OAAO,CAAC,KAAK,OAAO;IAC1E,MAAM,cAAc,kBAAkB,KAAK;IAC3C,MAAM,MAAM,MAAM;IAClB,MAAM,SACJ,cAAc,MAAM,WAAW,QAAQ,cACnC;KACE,UAAU,WAAW;KACrB,YAAY,WAAW;KACvB,cAAc,WAAW;IAC3B,IACA,KAAA;IAEN,OAAO;KACL;KACA;KACA;KACA,SAAS,cAAc,OAAO;KAC9B,GAAG;IACL;GACF,CAAC;GAED,IAAI,CAAC,MAAM,oBAAoB,CAAC,KAAK,uBAAuB,aAAa,WAAW,GAClF,OAAO;GAGT,MAAM,YAAY,UAAiB;IACjC,aAAa;KACX,IAAI,UAAU;KACd,MAAM,MAAM;KACZ,QAAQ,iBAAiB,MAAM,MAAM;KACrC,MAAM,MAAM;IACd;GACF;GAEA,KAAK,MAAM,SAAS,cAAc,KAAK,iBAAiB,OAAO,UAAU,IAAI;GAE7E,aAAa;IACX,KAAK,MAAM,SAAS,cAAc,KAAK,oBAAoB,OAAO,UAAU,IAAI;IAChF,gBAAgB;GAClB;EACF;CACF;AACF"}
@@ -1,50 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_http_capture_utils = require("./chunks/http-capture-utils-DbhpUirh.cjs");
2
3
  let _loggerjs_core = require("@loggerjs/core");
3
- //#region src/http-capture-utils.ts
4
- function nowMs() {
5
- return typeof performance !== "undefined" ? performance.now() : Date.now();
6
- }
7
- function durationMs(started) {
8
- return nowMs() - started;
9
- }
10
- function sanitizeHttpUrl(rawUrl, sanitizer) {
11
- const stripped = stripSensitiveUrlParts(rawUrl);
12
- return sanitizer ? sanitizer(stripped) : stripped;
13
- }
14
- function pickAllowedHeaders(headers, allowList) {
15
- if (!headers || !allowList || allowList.length === 0) return void 0;
16
- const out = {};
17
- for (const name of allowList) {
18
- const value = headers.get(name);
19
- if (value !== null) out[name.toLowerCase()] = value;
20
- }
21
- return Object.keys(out).length > 0 ? out : void 0;
22
- }
23
- function headersFromInit(headers) {
24
- if (!headers) return void 0;
25
- try {
26
- return new Headers(headers);
27
- } catch {
28
- return;
29
- }
30
- }
31
- function shouldSample(sampleRate, random) {
32
- if (sampleRate >= 1) return true;
33
- if (sampleRate <= 0) return false;
34
- return random() < sampleRate;
35
- }
36
- function stripSensitiveUrlParts(rawUrl) {
37
- if (!/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(rawUrl)) return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
38
- try {
39
- const url = new URL(rawUrl);
40
- url.search = "";
41
- url.hash = "";
42
- return url.toString();
43
- } catch {
44
- return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
45
- }
46
- }
47
- //#endregion
48
4
  //#region src/fetch-integration.ts
49
5
  function requestUrl(input) {
50
6
  if (typeof input === "string") return input;
@@ -70,12 +26,12 @@ function captureFetchIntegration(options = {}) {
70
26
  api.unpatched.fetch ??= original;
71
27
  const capture = api.guard((input) => api.capture(input));
72
28
  globalThis.fetch = async (input, init) => {
73
- const started = nowMs();
74
- const url = sanitizeHttpUrl(requestUrl(input), options.sanitizeUrl);
29
+ const started = require_http_capture_utils.nowMs();
30
+ const url = require_http_capture_utils.sanitizeHttpUrl(requestUrl(input), options.sanitizeUrl);
75
31
  const method = requestMethod(input, init);
76
32
  try {
77
33
  const response = await original(input, init);
78
- if (response.status >= minStatus || captureAll && shouldSample(sampleRate, random)) capture({
34
+ if (response.status >= minStatus || captureAll && require_http_capture_utils.shouldSample(sampleRate, random)) capture({
79
35
  level: response.status >= minStatus ? "warn" : "debug",
80
36
  message: `Fetch ${response.status} ${method} ${url}`,
81
37
  props: { http: {
@@ -84,9 +40,9 @@ function captureFetchIntegration(options = {}) {
84
40
  url,
85
41
  status: response.status,
86
42
  ok: response.ok,
87
- durationMs: durationMs(started),
88
- requestHeaders: pickAllowedHeaders(headersFromInit(init?.headers), options.captureRequestHeaders),
89
- responseHeaders: pickAllowedHeaders(response.headers, options.captureResponseHeaders)
43
+ durationMs: require_http_capture_utils.durationMs(started),
44
+ requestHeaders: require_http_capture_utils.pickAllowedHeaders(require_http_capture_utils.headersFromInit(init?.headers), options.captureRequestHeaders),
45
+ responseHeaders: require_http_capture_utils.pickAllowedHeaders(response.headers, options.captureResponseHeaders)
90
46
  } }
91
47
  });
92
48
  return response;
@@ -100,7 +56,7 @@ function captureFetchIntegration(options = {}) {
100
56
  kind: "fetch",
101
57
  method,
102
58
  url,
103
- durationMs: durationMs(started)
59
+ durationMs: require_http_capture_utils.durationMs(started)
104
60
  },
105
61
  input: (0, _loggerjs_core.normalizeValue)(input, { maxDepth: 3 })
106
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-integration.cjs","names":[],"sources":["../src/http-capture-utils.ts","../src/fetch-integration.ts"],"sourcesContent":["export function nowMs(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\nexport function durationMs(started: number): number {\n return nowMs() - started;\n}\n\nexport function sanitizeHttpUrl(rawUrl: string, sanitizer?: (url: string) => string): string {\n const stripped = stripSensitiveUrlParts(rawUrl);\n return sanitizer ? sanitizer(stripped) : stripped;\n}\n\nexport function pickAllowedHeaders(\n headers: Headers | undefined,\n allowList: readonly string[] | undefined,\n): Record<string, string> | undefined {\n if (!headers || !allowList || allowList.length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const name of allowList) {\n const value = headers.get(name);\n if (value !== null) out[name.toLowerCase()] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport function headersFromInit(headers: HeadersInit | undefined): Headers | undefined {\n if (!headers) return undefined;\n try {\n return new Headers(headers);\n } catch {\n return undefined;\n }\n}\n\nexport function shouldSample(sampleRate: number, random: () => number): boolean {\n if (sampleRate >= 1) return true;\n if (sampleRate <= 0) return false;\n return random() < sampleRate;\n}\n\nfunction stripSensitiveUrlParts(rawUrl: string): string {\n if (!/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(rawUrl)) {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n\n try {\n const url = new URL(rawUrl);\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n } catch {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n}\n","import {\n normalizeValue,\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type UnpatchedFunction,\n} from \"@loggerjs/core\";\nimport {\n durationMs,\n headersFromInit,\n nowMs,\n pickAllowedHeaders,\n sanitizeHttpUrl,\n shouldSample,\n} from \"./http-capture-utils\";\n\nexport interface CaptureFetchOptions {\n minStatus?: number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n sanitizeUrl?: (url: string) => string;\n}\n\ntype BrowserFetch = typeof fetch;\n\nfunction requestUrl(input: RequestInfo | URL): string {\n if (typeof input === \"string\") return input;\n if (input instanceof URL) return input.toString();\n return input.url;\n}\n\nfunction requestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) return init.method.toUpperCase();\n if (typeof input === \"object\" && \"method\" in input && input.method)\n return input.method.toUpperCase();\n return \"GET\";\n}\n\nexport function captureFetchIntegration(options: CaptureFetchOptions = {}): Integration {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? Math.random;\n\n return {\n name: \"capture-fetch\",\n setup(api: IntegrationSetupContext) {\n const current = globalThis.fetch;\n if (!current) return;\n const original =\n (api.unpatched.fetch as BrowserFetch | undefined) ?? current.bind(globalThis);\n api.unpatched.fetch ??= original as UnpatchedFunction;\n\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n\n globalThis.fetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const started = nowMs();\n const url = sanitizeHttpUrl(requestUrl(input), options.sanitizeUrl);\n const method = requestMethod(input, init);\n try {\n const response = await original(input, init);\n const shouldCapture =\n response.status >= minStatus || (captureAll && shouldSample(sampleRate, random));\n if (shouldCapture) {\n capture({\n level: response.status >= minStatus ? \"warn\" : \"debug\",\n message: `Fetch ${response.status} ${method} ${url}`,\n props: {\n http: {\n kind: \"fetch\",\n method,\n url,\n status: response.status,\n ok: response.ok,\n durationMs: durationMs(started),\n requestHeaders: pickAllowedHeaders(\n headersFromInit(init?.headers),\n options.captureRequestHeaders,\n ),\n responseHeaders: pickAllowedHeaders(\n response.headers,\n options.captureResponseHeaders,\n ),\n },\n },\n });\n }\n return response;\n } catch (error) {\n capture({\n level: \"error\",\n message: `Fetch network error ${method} ${url}`,\n error,\n props: {\n http: { kind: \"fetch\", method, url, durationMs: durationMs(started) },\n input: normalizeValue(input, { maxDepth: 3 }),\n },\n });\n throw error;\n }\n };\n\n return () => {\n globalThis.fetch = current;\n };\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"fetch-integration.cjs","names":["nowMs","sanitizeHttpUrl","shouldSample","durationMs","pickAllowedHeaders","headersFromInit"],"sources":["../src/fetch-integration.ts"],"sourcesContent":["import {\n normalizeValue,\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type UnpatchedFunction,\n} from \"@loggerjs/core\";\nimport {\n durationMs,\n headersFromInit,\n nowMs,\n pickAllowedHeaders,\n sanitizeHttpUrl,\n shouldSample,\n} from \"./http-capture-utils\";\n\nexport interface CaptureFetchOptions {\n minStatus?: number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n sanitizeUrl?: (url: string) => string;\n}\n\ntype BrowserFetch = typeof fetch;\n\nfunction requestUrl(input: RequestInfo | URL): string {\n if (typeof input === \"string\") return input;\n if (input instanceof URL) return input.toString();\n return input.url;\n}\n\nfunction requestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) return init.method.toUpperCase();\n if (typeof input === \"object\" && \"method\" in input && input.method)\n return input.method.toUpperCase();\n return \"GET\";\n}\n\nexport function captureFetchIntegration(options: CaptureFetchOptions = {}): Integration {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? Math.random;\n\n return {\n name: \"capture-fetch\",\n setup(api: IntegrationSetupContext) {\n const current = globalThis.fetch;\n if (!current) return;\n const original =\n (api.unpatched.fetch as BrowserFetch | undefined) ?? current.bind(globalThis);\n api.unpatched.fetch ??= original as UnpatchedFunction;\n\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n\n globalThis.fetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const started = nowMs();\n const url = sanitizeHttpUrl(requestUrl(input), options.sanitizeUrl);\n const method = requestMethod(input, init);\n try {\n const response = await original(input, init);\n const shouldCapture =\n response.status >= minStatus || (captureAll && shouldSample(sampleRate, random));\n if (shouldCapture) {\n capture({\n level: response.status >= minStatus ? \"warn\" : \"debug\",\n message: `Fetch ${response.status} ${method} ${url}`,\n props: {\n http: {\n kind: \"fetch\",\n method,\n url,\n status: response.status,\n ok: response.ok,\n durationMs: durationMs(started),\n requestHeaders: pickAllowedHeaders(\n headersFromInit(init?.headers),\n options.captureRequestHeaders,\n ),\n responseHeaders: pickAllowedHeaders(\n response.headers,\n options.captureResponseHeaders,\n ),\n },\n },\n });\n }\n return response;\n } catch (error) {\n capture({\n level: \"error\",\n message: `Fetch network error ${method} ${url}`,\n error,\n props: {\n http: { kind: \"fetch\", method, url, durationMs: durationMs(started) },\n input: normalizeValue(input, { maxDepth: 3 }),\n },\n });\n throw error;\n }\n };\n\n return () => {\n globalThis.fetch = current;\n };\n },\n };\n}\n"],"mappings":";;;;AA6BA,SAAS,WAAW,OAAkC;CACpD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,iBAAiB,KAAK,OAAO,MAAM,SAAS;CAChD,OAAO,MAAM;AACf;AAEA,SAAS,cAAc,OAA0B,MAA4B;CAC3E,IAAI,MAAM,QAAQ,OAAO,KAAK,OAAO,YAAY;CACjD,IAAI,OAAO,UAAU,YAAY,YAAY,SAAS,MAAM,QAC1D,OAAO,MAAM,OAAO,YAAY;CAClC,OAAO;AACT;AAEA,SAAgB,wBAAwB,UAA+B,CAAC,GAAgB;CACtF,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,QAAQ,cAAc,QAAQ,qBAAqB;CACtE,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,SAAS,QAAQ,UAAU,KAAK;CAEtC,OAAO;EACL,MAAM;EACN,MAAM,KAA8B;GAClC,MAAM,UAAU,WAAW;GAC3B,IAAI,CAAC,SAAS;GACd,MAAM,WACH,IAAI,UAAU,SAAsC,QAAQ,KAAK,UAAU;GAC9E,IAAI,UAAU,UAAU;GAExB,MAAM,UAAU,IAAI,OAAO,UAAwB,IAAI,QAAQ,KAAK,CAAC;GAErE,WAAW,QAAQ,OACjB,OACA,SACsB;IACtB,MAAM,UAAUA,2BAAAA,MAAM;IACtB,MAAM,MAAMC,2BAAAA,gBAAgB,WAAW,KAAK,GAAG,QAAQ,WAAW;IAClE,MAAM,SAAS,cAAc,OAAO,IAAI;IACxC,IAAI;KACF,MAAM,WAAW,MAAM,SAAS,OAAO,IAAI;KAG3C,IADE,SAAS,UAAU,aAAc,cAAcC,2BAAAA,aAAa,YAAY,MAAM,GAE9E,QAAQ;MACN,OAAO,SAAS,UAAU,YAAY,SAAS;MAC/C,SAAS,SAAS,SAAS,OAAO,GAAG,OAAO,GAAG;MAC/C,OAAO,EACL,MAAM;OACJ,MAAM;OACN;OACA;OACA,QAAQ,SAAS;OACjB,IAAI,SAAS;OACb,YAAYC,2BAAAA,WAAW,OAAO;OAC9B,gBAAgBC,2BAAAA,mBACdC,2BAAAA,gBAAgB,MAAM,OAAO,GAC7B,QAAQ,qBACV;OACA,iBAAiBD,2BAAAA,mBACf,SAAS,SACT,QAAQ,sBACV;MACF,EACF;KACF,CAAC;KAEH,OAAO;IACT,SAAS,OAAO;KACd,QAAQ;MACN,OAAO;MACP,SAAS,uBAAuB,OAAO,GAAG;MAC1C;MACA,OAAO;OACL,MAAM;QAAE,MAAM;QAAS;QAAQ;QAAK,YAAYD,2BAAAA,WAAW,OAAO;OAAE;OACpE,QAAA,GAAA,eAAA,eAAA,CAAsB,OAAO,EAAE,UAAU,EAAE,CAAC;MAC9C;KACF,CAAC;KACD,MAAM;IACR;GACF;GAEA,aAAa;IACX,WAAW,QAAQ;GACrB;EACF;CACF;AACF"}
@@ -1,49 +1,5 @@
1
+ import { a as sanitizeHttpUrl, i as pickAllowedHeaders, n as headersFromInit, o as shouldSample, r as nowMs, t as durationMs } from "./chunks/http-capture-utils-_hG5wepA.js";
1
2
  import { normalizeValue } from "@loggerjs/core";
2
- //#region src/http-capture-utils.ts
3
- function nowMs() {
4
- return typeof performance !== "undefined" ? performance.now() : Date.now();
5
- }
6
- function durationMs(started) {
7
- return nowMs() - started;
8
- }
9
- function sanitizeHttpUrl(rawUrl, sanitizer) {
10
- const stripped = stripSensitiveUrlParts(rawUrl);
11
- return sanitizer ? sanitizer(stripped) : stripped;
12
- }
13
- function pickAllowedHeaders(headers, allowList) {
14
- if (!headers || !allowList || allowList.length === 0) return void 0;
15
- const out = {};
16
- for (const name of allowList) {
17
- const value = headers.get(name);
18
- if (value !== null) out[name.toLowerCase()] = value;
19
- }
20
- return Object.keys(out).length > 0 ? out : void 0;
21
- }
22
- function headersFromInit(headers) {
23
- if (!headers) return void 0;
24
- try {
25
- return new Headers(headers);
26
- } catch {
27
- return;
28
- }
29
- }
30
- function shouldSample(sampleRate, random) {
31
- if (sampleRate >= 1) return true;
32
- if (sampleRate <= 0) return false;
33
- return random() < sampleRate;
34
- }
35
- function stripSensitiveUrlParts(rawUrl) {
36
- if (!/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(rawUrl)) return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
37
- try {
38
- const url = new URL(rawUrl);
39
- url.search = "";
40
- url.hash = "";
41
- return url.toString();
42
- } catch {
43
- return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;
44
- }
45
- }
46
- //#endregion
47
3
  //#region src/fetch-integration.ts
48
4
  function requestUrl(input) {
49
5
  if (typeof input === "string") return input;
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-integration.js","names":[],"sources":["../src/http-capture-utils.ts","../src/fetch-integration.ts"],"sourcesContent":["export function nowMs(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n}\n\nexport function durationMs(started: number): number {\n return nowMs() - started;\n}\n\nexport function sanitizeHttpUrl(rawUrl: string, sanitizer?: (url: string) => string): string {\n const stripped = stripSensitiveUrlParts(rawUrl);\n return sanitizer ? sanitizer(stripped) : stripped;\n}\n\nexport function pickAllowedHeaders(\n headers: Headers | undefined,\n allowList: readonly string[] | undefined,\n): Record<string, string> | undefined {\n if (!headers || !allowList || allowList.length === 0) return undefined;\n const out: Record<string, string> = {};\n for (const name of allowList) {\n const value = headers.get(name);\n if (value !== null) out[name.toLowerCase()] = value;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nexport function headersFromInit(headers: HeadersInit | undefined): Headers | undefined {\n if (!headers) return undefined;\n try {\n return new Headers(headers);\n } catch {\n return undefined;\n }\n}\n\nexport function shouldSample(sampleRate: number, random: () => number): boolean {\n if (sampleRate >= 1) return true;\n if (sampleRate <= 0) return false;\n return random() < sampleRate;\n}\n\nfunction stripSensitiveUrlParts(rawUrl: string): string {\n if (!/^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(rawUrl)) {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n\n try {\n const url = new URL(rawUrl);\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n } catch {\n return rawUrl.split(/[?#]/, 1)[0] ?? rawUrl;\n }\n}\n","import {\n normalizeValue,\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type UnpatchedFunction,\n} from \"@loggerjs/core\";\nimport {\n durationMs,\n headersFromInit,\n nowMs,\n pickAllowedHeaders,\n sanitizeHttpUrl,\n shouldSample,\n} from \"./http-capture-utils\";\n\nexport interface CaptureFetchOptions {\n minStatus?: number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n sanitizeUrl?: (url: string) => string;\n}\n\ntype BrowserFetch = typeof fetch;\n\nfunction requestUrl(input: RequestInfo | URL): string {\n if (typeof input === \"string\") return input;\n if (input instanceof URL) return input.toString();\n return input.url;\n}\n\nfunction requestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) return init.method.toUpperCase();\n if (typeof input === \"object\" && \"method\" in input && input.method)\n return input.method.toUpperCase();\n return \"GET\";\n}\n\nexport function captureFetchIntegration(options: CaptureFetchOptions = {}): Integration {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? Math.random;\n\n return {\n name: \"capture-fetch\",\n setup(api: IntegrationSetupContext) {\n const current = globalThis.fetch;\n if (!current) return;\n const original =\n (api.unpatched.fetch as BrowserFetch | undefined) ?? current.bind(globalThis);\n api.unpatched.fetch ??= original as UnpatchedFunction;\n\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n\n globalThis.fetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const started = nowMs();\n const url = sanitizeHttpUrl(requestUrl(input), options.sanitizeUrl);\n const method = requestMethod(input, init);\n try {\n const response = await original(input, init);\n const shouldCapture =\n response.status >= minStatus || (captureAll && shouldSample(sampleRate, random));\n if (shouldCapture) {\n capture({\n level: response.status >= minStatus ? \"warn\" : \"debug\",\n message: `Fetch ${response.status} ${method} ${url}`,\n props: {\n http: {\n kind: \"fetch\",\n method,\n url,\n status: response.status,\n ok: response.ok,\n durationMs: durationMs(started),\n requestHeaders: pickAllowedHeaders(\n headersFromInit(init?.headers),\n options.captureRequestHeaders,\n ),\n responseHeaders: pickAllowedHeaders(\n response.headers,\n options.captureResponseHeaders,\n ),\n },\n },\n });\n }\n return response;\n } catch (error) {\n capture({\n level: \"error\",\n message: `Fetch network error ${method} ${url}`,\n error,\n props: {\n http: { kind: \"fetch\", method, url, durationMs: durationMs(started) },\n input: normalizeValue(input, { maxDepth: 3 }),\n },\n });\n throw error;\n }\n };\n\n return () => {\n globalThis.fetch = current;\n };\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"fetch-integration.js","names":[],"sources":["../src/fetch-integration.ts"],"sourcesContent":["import {\n normalizeValue,\n type CaptureInput,\n type Integration,\n type IntegrationSetupContext,\n type UnpatchedFunction,\n} from \"@loggerjs/core\";\nimport {\n durationMs,\n headersFromInit,\n nowMs,\n pickAllowedHeaders,\n sanitizeHttpUrl,\n shouldSample,\n} from \"./http-capture-utils\";\n\nexport interface CaptureFetchOptions {\n minStatus?: number;\n captureRequestHeaders?: readonly string[];\n captureResponseHeaders?: readonly string[];\n captureAll?: boolean;\n captureSuccessful?: boolean;\n sampleRate?: number;\n random?: () => number;\n sanitizeUrl?: (url: string) => string;\n}\n\ntype BrowserFetch = typeof fetch;\n\nfunction requestUrl(input: RequestInfo | URL): string {\n if (typeof input === \"string\") return input;\n if (input instanceof URL) return input.toString();\n return input.url;\n}\n\nfunction requestMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) return init.method.toUpperCase();\n if (typeof input === \"object\" && \"method\" in input && input.method)\n return input.method.toUpperCase();\n return \"GET\";\n}\n\nexport function captureFetchIntegration(options: CaptureFetchOptions = {}): Integration {\n const minStatus = options.minStatus ?? 400;\n const captureAll = options.captureAll ?? options.captureSuccessful ?? false;\n const sampleRate = options.sampleRate ?? 1;\n const random = options.random ?? Math.random;\n\n return {\n name: \"capture-fetch\",\n setup(api: IntegrationSetupContext) {\n const current = globalThis.fetch;\n if (!current) return;\n const original =\n (api.unpatched.fetch as BrowserFetch | undefined) ?? current.bind(globalThis);\n api.unpatched.fetch ??= original as UnpatchedFunction;\n\n const capture = api.guard((input: CaptureInput) => api.capture(input));\n\n globalThis.fetch = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const started = nowMs();\n const url = sanitizeHttpUrl(requestUrl(input), options.sanitizeUrl);\n const method = requestMethod(input, init);\n try {\n const response = await original(input, init);\n const shouldCapture =\n response.status >= minStatus || (captureAll && shouldSample(sampleRate, random));\n if (shouldCapture) {\n capture({\n level: response.status >= minStatus ? \"warn\" : \"debug\",\n message: `Fetch ${response.status} ${method} ${url}`,\n props: {\n http: {\n kind: \"fetch\",\n method,\n url,\n status: response.status,\n ok: response.ok,\n durationMs: durationMs(started),\n requestHeaders: pickAllowedHeaders(\n headersFromInit(init?.headers),\n options.captureRequestHeaders,\n ),\n responseHeaders: pickAllowedHeaders(\n response.headers,\n options.captureResponseHeaders,\n ),\n },\n },\n });\n }\n return response;\n } catch (error) {\n capture({\n level: \"error\",\n message: `Fetch network error ${method} ${url}`,\n error,\n props: {\n http: { kind: \"fetch\", method, url, durationMs: durationMs(started) },\n input: normalizeValue(input, { maxDepth: 3 }),\n },\n });\n throw error;\n }\n };\n\n return () => {\n globalThis.fetch = current;\n };\n },\n };\n}\n"],"mappings":";;;AA6BA,SAAS,WAAW,OAAkC;CACpD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,iBAAiB,KAAK,OAAO,MAAM,SAAS;CAChD,OAAO,MAAM;AACf;AAEA,SAAS,cAAc,OAA0B,MAA4B;CAC3E,IAAI,MAAM,QAAQ,OAAO,KAAK,OAAO,YAAY;CACjD,IAAI,OAAO,UAAU,YAAY,YAAY,SAAS,MAAM,QAC1D,OAAO,MAAM,OAAO,YAAY;CAClC,OAAO;AACT;AAEA,SAAgB,wBAAwB,UAA+B,CAAC,GAAgB;CACtF,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,QAAQ,cAAc,QAAQ,qBAAqB;CACtE,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,SAAS,QAAQ,UAAU,KAAK;CAEtC,OAAO;EACL,MAAM;EACN,MAAM,KAA8B;GAClC,MAAM,UAAU,WAAW;GAC3B,IAAI,CAAC,SAAS;GACd,MAAM,WACH,IAAI,UAAU,SAAsC,QAAQ,KAAK,UAAU;GAC9E,IAAI,UAAU,UAAU;GAExB,MAAM,UAAU,IAAI,OAAO,UAAwB,IAAI,QAAQ,KAAK,CAAC;GAErE,WAAW,QAAQ,OACjB,OACA,SACsB;IACtB,MAAM,UAAU,MAAM;IACtB,MAAM,MAAM,gBAAgB,WAAW,KAAK,GAAG,QAAQ,WAAW;IAClE,MAAM,SAAS,cAAc,OAAO,IAAI;IACxC,IAAI;KACF,MAAM,WAAW,MAAM,SAAS,OAAO,IAAI;KAG3C,IADE,SAAS,UAAU,aAAc,cAAc,aAAa,YAAY,MAAM,GAE9E,QAAQ;MACN,OAAO,SAAS,UAAU,YAAY,SAAS;MAC/C,SAAS,SAAS,SAAS,OAAO,GAAG,OAAO,GAAG;MAC/C,OAAO,EACL,MAAM;OACJ,MAAM;OACN;OACA;OACA,QAAQ,SAAS;OACjB,IAAI,SAAS;OACb,YAAY,WAAW,OAAO;OAC9B,gBAAgB,mBACd,gBAAgB,MAAM,OAAO,GAC7B,QAAQ,qBACV;OACA,iBAAiB,mBACf,SAAS,SACT,QAAQ,sBACV;MACF,EACF;KACF,CAAC;KAEH,OAAO;IACT,SAAS,OAAO;KACd,QAAQ;MACN,OAAO;MACP,SAAS,uBAAuB,OAAO,GAAG;MAC1C;MACA,OAAO;OACL,MAAM;QAAE,MAAM;QAAS;QAAQ;QAAK,YAAY,WAAW,OAAO;OAAE;OACpE,OAAO,eAAe,OAAO,EAAE,UAAU,EAAE,CAAC;MAC9C;KACF,CAAC;KACD,MAAM;IACR;GACF;GAEA,aAAa;IACX,WAAW,QAAQ;GACrB;EACF;CACF;AACF"}