@dash0/sdk-web 0.22.0 → 0.23.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.
@@ -2,7 +2,12 @@ import { AttributeValueType } from "../utils/otel";
2
2
  import { AnyValue } from "./otlp";
3
3
  import { Endpoint, Vars, PropagatorConfig } from "../vars";
4
4
 
5
- export type InstrumentationName = "@dash0/navigation" | "@dash0/web-vitals" | "@dash0/error" | "@dash0/fetch";
5
+ export type InstrumentationName =
6
+ | "@dash0/navigation"
7
+ | "@dash0/web-vitals"
8
+ | "@dash0/error"
9
+ | "@dash0/fetch"
10
+ | "@dash0/xhr";
6
11
 
7
12
  /**
8
13
  * VCS (version control) context describing the build the SDK is running
package/src/utils/wrap.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { debug } from "./debug";
1
+ import { debug, warn } from "./debug";
2
2
 
3
3
  const INSTRUMENTED_BY_DASH0_SYMBOL = Symbol.for("INSTRUMENTED_BY_DASH0");
4
4
 
@@ -29,6 +29,18 @@ export function wrap<ModuleType extends object, TargetNameType extends keyof Mod
29
29
  return;
30
30
  }
31
31
 
32
- markAsInstrumented(original);
33
- module[target] = wrapper(original);
32
+ try {
33
+ const wrapped = wrapper(original);
34
+ // Mark the replacement as well: a later wrap() call reads the replacement from module[target],
35
+ // so marking only the original would let repeated instrumentation wrap the wrapper.
36
+ markAsInstrumented(original);
37
+ if (wrapped) {
38
+ markAsInstrumented(wrapped);
39
+ }
40
+ module[target] = wrapped;
41
+ } catch (e) {
42
+ // Pages can lock properties via Object.defineProperty/Object.freeze -- failing to install
43
+ // one instrumentation must not throw out of init() and abort the remaining ones.
44
+ warn(`failed to instrument ${String(target)}, the page may have locked the property`, e);
45
+ }
34
46
  }
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { wrap } from "./wrap";
3
+
4
+ describe("wrap", () => {
5
+ it("replaces the target with the wrapper's return value", () => {
6
+ const original = () => "original";
7
+ const module = { fn: original };
8
+
9
+ wrap(module, "fn", (orig) => () => `wrapped ${orig()}`);
10
+
11
+ expect(module.fn()).toBe("wrapped original");
12
+ });
13
+
14
+ it("does not wrap the same target twice", () => {
15
+ const module = { fn: () => "original" };
16
+ const wrapper = vi.fn((orig: () => string) => () => `wrapped ${orig()}`);
17
+
18
+ wrap(module, "fn", wrapper);
19
+ wrap(module, "fn", wrapper);
20
+
21
+ expect(wrapper).toHaveBeenCalledTimes(1);
22
+ expect(module.fn()).toBe("wrapped original");
23
+ });
24
+
25
+ it("skips undefined targets", () => {
26
+ const module: { fn?: () => string } = {};
27
+ const wrapper = vi.fn();
28
+
29
+ expect(() => wrap(module, "fn", wrapper)).not.toThrow();
30
+ expect(wrapper).not.toHaveBeenCalled();
31
+ });
32
+
33
+ it("does not throw when the page locked the target property", () => {
34
+ const original = () => "original";
35
+ const module = {} as { fn: () => string };
36
+ Object.defineProperty(module, "fn", { value: original, writable: false, configurable: false });
37
+
38
+ expect(() => wrap(module, "fn", (orig) => () => `wrapped ${orig()}`)).not.toThrow();
39
+ expect(module.fn).toBe(original);
40
+ });
41
+ });