@salesforcedevs/dx-components 1.38.0 → 1.39.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.38.0",
3
+ "version": "1.39.0",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -44,5 +44,5 @@
44
44
  "luxon": "3.4.4",
45
45
  "msw": "^2.12.4"
46
46
  },
47
- "gitHead": "fc9d953dd79b76e37578fc43691fa56d6c4dd028"
47
+ "gitHead": "055e2a716cf3e946add92e953e136835730bc5fc"
48
48
  }
@@ -38,6 +38,47 @@ function archTrack(
38
38
  }
39
39
  }
40
40
 
41
+ interface NamespaceConfig {
42
+ eventName: string;
43
+ queue: string;
44
+ indicator: string;
45
+ replay: (
46
+ element: EventTarget,
47
+ event: string,
48
+ payload: Record<string, unknown>
49
+ ) => void;
50
+ }
51
+
52
+ // The two tracking-event namespaces dx-instrumentation can bridge. Keyed by the
53
+ // values accepted by the `namespaces` attribute.
54
+ const NAMESPACE_CONFIGS: Record<"developer" | "architect", NamespaceConfig> = {
55
+ developer: {
56
+ eventName: DX_TRACKING_EVENT_NAME,
57
+ queue: DX_LISTENER_QUEUE,
58
+ indicator: DX_LISTENER_INDICATOR,
59
+ replay: dxTrack
60
+ },
61
+ architect: {
62
+ eventName: ARCH_TRACKING_EVENT_NAME,
63
+ queue: ARCH_LISTENER_QUEUE,
64
+ indicator: ARCH_LISTENER_INDICATOR,
65
+ replay: archTrack
66
+ }
67
+ };
68
+
69
+ // Maps the `namespaces` attribute to the configs it activates.
70
+ function resolveNamespaceConfigs(namespaces: string): NamespaceConfig[] {
71
+ switch (namespaces) {
72
+ case "developer":
73
+ return [NAMESPACE_CONFIGS.developer];
74
+ case "architect":
75
+ return [NAMESPACE_CONFIGS.architect];
76
+ case "both":
77
+ default:
78
+ return [NAMESPACE_CONFIGS.developer, NAMESPACE_CONFIGS.architect];
79
+ }
80
+ }
81
+
41
82
  const googleTagManager = {
42
83
  track: function (e: Event) {
43
84
  if ((window as any).dataLayer === undefined) {
@@ -54,13 +95,14 @@ interface TrackEventListener {
54
95
  }
55
96
 
56
97
  /**
57
- * Attaches a listener for BOTH the developer (`developerwebsite_track`) and
58
- * architect (`architectssite_track`) tracking events, forwarding each caught
59
- * event to every tracker function. A single component can therefore bridge both
60
- * event namespaces into the dataLayer.
98
+ * Attaches a listener for each of the given tracking event names (e.g.
99
+ * `developerwebsite_track` and/or `architectssite_track`), forwarding every
100
+ * caught event to every tracker function. A single component can therefore
101
+ * bridge one or both event namespaces into the dataLayer.
61
102
  */
62
103
  export function instrumentationTrackEventListener(
63
- trackerFns: { track: (e: Event) => void }[] = []
104
+ trackerFns: { track: (e: Event) => void }[] = [],
105
+ eventNames: string[] = [DX_TRACKING_EVENT_NAME, ARCH_TRACKING_EVENT_NAME]
64
106
  ): TrackEventListener {
65
107
  if (trackerFns.length === 0) {
66
108
  throw new Error("No tracker functions passed");
@@ -73,16 +115,15 @@ export function instrumentationTrackEventListener(
73
115
  };
74
116
 
75
117
  const attachEventListener = () => {
76
- document.addEventListener(DX_TRACKING_EVENT_NAME, handleTrackEvent);
77
- document.addEventListener(ARCH_TRACKING_EVENT_NAME, handleTrackEvent);
118
+ eventNames.forEach((eventName) => {
119
+ document.addEventListener(eventName, handleTrackEvent);
120
+ });
78
121
  };
79
122
 
80
123
  const removeEventListener = () => {
81
- document.removeEventListener(DX_TRACKING_EVENT_NAME, handleTrackEvent);
82
- document.removeEventListener(
83
- ARCH_TRACKING_EVENT_NAME,
84
- handleTrackEvent
85
- );
124
+ eventNames.forEach((eventName) => {
125
+ document.removeEventListener(eventName, handleTrackEvent);
126
+ });
86
127
  };
87
128
 
88
129
  return {
@@ -93,49 +134,54 @@ export function instrumentationTrackEventListener(
93
134
 
94
135
  /**
95
136
  * Unified instrumentation bridge. Mount a single <dx-instrumentation> to forward
96
- * both developer-website and architect-website tracking events into the GTM
97
- * dataLayer replacing the need to mount <dw-instrumentation> and
98
- * <arch-instrumentation> separately. Renders nothing.
137
+ * developer-website and/or architect-website tracking events into the GTM
138
+ * dataLayer. Renders nothing.
139
+ *
140
+ * By default (`namespaces="both"`) it bridges both the developer
141
+ * (`developerwebsite_track`) and architect (`architectssite_track`) namespaces,
142
+ * replacing the need to mount <dw-instrumentation> and <arch-instrumentation>
143
+ * separately. Set `namespaces="developer"` (or `"architect"`) to bridge only one
144
+ * — e.g. on a site whose header analytics already reach the dataLayer through
145
+ * another path, so draining the architect queue here would double-count.
99
146
  */
100
147
  export default class Instrumentation extends LightningElement {
101
148
  @api useGoogleTagManager = false;
102
149
 
150
+ // "both" (default) | "developer" | "architect"
151
+ @api namespaces = "both";
152
+
103
153
  private tracker: TrackEventListener | null = null;
104
154
 
105
155
  private setupTracker() {
156
+ const configs = resolveNamespaceConfigs(this.namespaces);
106
157
  const trackerFunctions = this.useGoogleTagManager
107
158
  ? [googleTagManager]
108
159
  : [];
109
- this.tracker = instrumentationTrackEventListener(trackerFunctions);
160
+ this.tracker = instrumentationTrackEventListener(
161
+ trackerFunctions,
162
+ configs.map((c) => c.eventName)
163
+ );
110
164
  this.tracker.add();
111
- // Mark both namespaces initialized so track() calls from either the
112
- // developer or architect stacks dispatch live events instead of queueing.
113
- (window as any)[DX_LISTENER_INDICATOR] = true;
114
- (window as any)[ARCH_LISTENER_INDICATOR] = true;
165
+ // Mark each active namespace initialized so track() calls from that
166
+ // stack dispatch live events instead of queueing.
167
+ configs.forEach((c) => {
168
+ (window as any)[c.indicator] = true;
169
+ });
115
170
  }
116
171
 
117
172
  private dispatchQueuedEvents() {
118
- const dxQueue = (window as any)[DX_LISTENER_QUEUE];
119
- if (Array.isArray(dxQueue)) {
120
- while (dxQueue.length > 0) {
121
- const event = dxQueue.pop() as {
122
- event: string;
123
- payload: Record<string, unknown>;
124
- };
125
- dxTrack(this, event.event, event.payload);
173
+ resolveNamespaceConfigs(this.namespaces).forEach((config) => {
174
+ const queue = (window as any)[config.queue];
175
+ if (Array.isArray(queue)) {
176
+ while (queue.length > 0) {
177
+ const event = queue.pop() as {
178
+ event: string;
179
+ payload: Record<string, unknown>;
180
+ };
181
+ config.replay(this, event.event, event.payload);
182
+ }
126
183
  }
127
- }
128
-
129
- const archQueue = (window as any)[ARCH_LISTENER_QUEUE];
130
- if (Array.isArray(archQueue)) {
131
- while (archQueue.length > 0) {
132
- const event = archQueue.pop() as {
133
- event: string;
134
- payload: Record<string, unknown>;
135
- };
136
- archTrack(this, event.event, event.payload);
137
- }
138
- }
184
+ });
139
185
  }
140
186
 
141
187
  renderedCallback() {