@equinor/fusion-framework-module-analytics 3.0.8-next.0 → 3.0.8

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/CHANGELOG.md CHANGED
@@ -1,13 +1,11 @@
1
1
  # @equinor/fusion-framework-module-analytics
2
2
 
3
- ## 3.0.8-next.0
3
+ ## 3.0.8
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - c8008e3: Internal: rebase `next` onto `main`, syncing in already-published stable releases so they carry a `next` pre-release tag.
8
- - Updated dependencies [c8008e3]
9
- - @equinor/fusion-framework-module-app@8.0.6-next.0
10
- - @equinor/fusion-framework-module-context@9.0.0-next.0
7
+ - Updated dependencies [6b449ae]
8
+ - @equinor/fusion-observable@9.2.0
11
9
 
12
10
  ## 3.0.7
13
11
 
package/README.md CHANGED
@@ -3,15 +3,6 @@
3
3
  Fusion Framework module for collecting and exporting application analytics using
4
4
  OpenTelemetry standards.
5
5
 
6
- ## Who should use this
7
-
8
- - **Application and portal developers** who want to track user interactions
9
- (clicks, context changes, app usage) without wiring up telemetry by hand.
10
- - **Module authors** who want their module's lifecycle events picked up by
11
- analytics automatically via a collector.
12
- - **Test authors** who need to assert which analytics events an app or
13
- collector produced.
14
-
15
6
  ## Overview
16
7
 
17
8
  The analytics module provides a pluggable **adapter/collector** architecture:
@@ -31,16 +22,6 @@ When a collector emits an event it is delivered to **every** registered adapter.
31
22
  | `@equinor/fusion-framework-module-analytics/adapters` | `ConsoleAnalyticsAdapter`, `FusionAnalyticsAdapter`, `IAnalyticsAdapter` |
32
23
  | `@equinor/fusion-framework-module-analytics/collectors` | `ContextSelectedCollector`, `AppSelectedCollector`, `AppLoadedCollector`, `IAnalyticsCollector` |
33
24
  | `@equinor/fusion-framework-module-analytics/logExporters` | `OTLPLogExporter`, `FusionOTLPLogExporter` |
34
- | `@equinor/fusion-framework-module-analytics/mock` | `MockAnalyticsAdapter` — record tracked events for test assertions |
35
-
36
- ## Documentation
37
-
38
- | Topic | Description |
39
- |---|---|
40
- | [Adapters](docs/adapters.md) | `ConsoleAnalyticsAdapter`, `FusionAnalyticsAdapter`, and creating a custom `IAnalyticsAdapter` |
41
- | [Collectors](docs/collectors.md) | Built-in collectors (context/app selection, app loaded) and creating a custom `IAnalyticsCollector` |
42
- | [Tracking Events Manually](docs/tracking-events.md) | `provider.trackAnalytic` / `trackAnalytic$` for ad-hoc event tracking |
43
- | [Testing](docs/testing.md) | `MockAnalyticsAdapter`, recording and awaiting tracked events, and using a bespoke `ModulesConfigurator` in tests |
44
25
 
45
26
  ## Quick Start
46
27
 
@@ -71,6 +52,217 @@ const configure = (configurator) => {
71
52
  > Fusion Framework module system. Manual initialisation is only required when
72
53
  > accessing the provider directly.
73
54
 
74
- See [Adapters](docs/adapters.md), [Collectors](docs/collectors.md), and
75
- [Tracking Events Manually](docs/tracking-events.md) for the full adapter/collector
76
- reference and how to build your own.
55
+ ## Adapters
56
+
57
+ Adapters implement `IAnalyticsAdapter` and are responsible for processing and
58
+ sending analytics data to their destinations. All adapters support async
59
+ initialisation and will be initialised automatically when the provider starts.
60
+
61
+ ### ConsoleAnalyticsAdapter
62
+
63
+ Logs every analytics event to the browser console. Useful for development and
64
+ debugging. No configuration required.
65
+
66
+ ```typescript
67
+ builder.setAdapter('console', async () => new ConsoleAnalyticsAdapter());
68
+ ```
69
+
70
+ ### FusionAnalyticsAdapter
71
+
72
+ Forwards analytics events to an OpenTelemetry-compatible log endpoint via a
73
+ bundled `LoggerProvider`.
74
+
75
+ Configuration options:
76
+
77
+ | Option | Type | Description |
78
+ |---|---|---|
79
+ | `portalId` | `string` | Portal identifier included in every log record |
80
+ | `logExporter` | `OTLPExporterBase` | OTLP log exporter for transport |
81
+
82
+ #### Using `OTLPLogExporter` (direct HTTP)
83
+
84
+ ```typescript
85
+ import { OTLPLogExporter } from '@equinor/fusion-framework-module-analytics/logExporters';
86
+ import { FusionAnalyticsAdapter } from '@equinor/fusion-framework-module-analytics/adapters';
87
+
88
+ builder.setAdapter('fusion-log', async () => {
89
+ const logExporter = new OTLPLogExporter({
90
+ url: 'https://example.com/v1/logs',
91
+ headers: { 'Content-Type': 'application/json' },
92
+ });
93
+ return new FusionAnalyticsAdapter({ portalId: 'my-portal', logExporter });
94
+ });
95
+ ```
96
+
97
+ #### Using `FusionOTLPLogExporter` (service discovery HTTP client)
98
+
99
+ ```typescript
100
+ import { FusionOTLPLogExporter } from '@equinor/fusion-framework-module-analytics/logExporters';
101
+ import { FusionAnalyticsAdapter } from '@equinor/fusion-framework-module-analytics/adapters';
102
+
103
+ builder.setAdapter('fusion', async (args) => {
104
+ if (args.hasModule('serviceDiscovery')) {
105
+ const sd = await args.requireInstance('serviceDiscovery');
106
+ const httpClient = await sd.createClient('analytics');
107
+ const logExporter = new FusionOTLPLogExporter(httpClient);
108
+ return new FusionAnalyticsAdapter({ portalId: 'my-portal', logExporter });
109
+ }
110
+ console.error('Service discovery unavailable — analytics adapter not created');
111
+ });
112
+ ```
113
+
114
+ ### Creating a Custom Adapter
115
+
116
+ Implement `IAnalyticsAdapter` and register it with `setAdapter`:
117
+
118
+ ```typescript
119
+ import type { IAnalyticsAdapter } from '@equinor/fusion-framework-module-analytics/adapters';
120
+ import type { AnalyticsEvent } from '@equinor/fusion-framework-module-analytics';
121
+
122
+ class MyRemoteAdapter implements IAnalyticsAdapter {
123
+ registerAnalytic(event: AnalyticsEvent): void {
124
+ navigator.sendBeacon('/analytics', JSON.stringify(event));
125
+ }
126
+
127
+ [Symbol.dispose](): void {
128
+ // cleanup if needed
129
+ }
130
+ }
131
+
132
+ builder.setAdapter('remote', async () => new MyRemoteAdapter());
133
+ ```
134
+
135
+ ## Collectors
136
+
137
+ Collectors implement `IAnalyticsCollector` (or extend `BaseCollector`) and emit
138
+ `AnalyticsEvent` objects that are forwarded to all adapters. All collectors
139
+ support async initialisation.
140
+
141
+ ### ContextSelectedCollector
142
+
143
+ Emits an event when the active Fusion context changes. Includes the new context,
144
+ the previous context, and the current app key in attributes.
145
+
146
+ ```typescript
147
+ builder.setCollector('context-selected', async (args) => {
148
+ const ctx = await args.requireInstance('context');
149
+ const app = await args.requireInstance('app');
150
+ return new ContextSelectedCollector(ctx, app);
151
+ });
152
+ ```
153
+
154
+ ### AppSelectedCollector
155
+
156
+ Emits an event when the active application changes. Includes the new and
157
+ previous app key metadata.
158
+
159
+ ```typescript
160
+ builder.setCollector('app-selected', async (args) => {
161
+ const app = await args.requireInstance('app');
162
+ return new AppSelectedCollector(app);
163
+ });
164
+ ```
165
+
166
+ ### AppLoadedCollector
167
+
168
+ Emits an event when an application's modules finish loading. Includes app
169
+ manifest metadata and the current context (if available).
170
+
171
+ ```typescript
172
+ builder.setCollector('app-loaded', async (args) => {
173
+ const event = await args.requireInstance('event');
174
+ const app = await args.requireInstance('app');
175
+ return new AppLoadedCollector(event, app);
176
+ });
177
+ ```
178
+
179
+ ### Creating a Custom Collector
180
+
181
+ Extend `BaseCollector` with a Zod schema for validation:
182
+
183
+ ```typescript
184
+ import { BaseCollector, createSchema } from '@equinor/fusion-framework-module-analytics/collectors';
185
+ import { z } from 'zod';
186
+ import { of } from 'rxjs';
187
+
188
+ const schema = createSchema(z.string(), z.object({ page: z.string() }));
189
+
190
+ class PageViewCollector extends BaseCollector<string, { page: string }> {
191
+ constructor() {
192
+ super('page-view', schema);
193
+ }
194
+
195
+ _initialize() {
196
+ return of({ value: window.location.pathname, attributes: { page: document.title } });
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## Tracking Events Manually
202
+
203
+ The provider exposes methods for ad-hoc event tracking outside of collectors:
204
+
205
+ ```typescript
206
+ // Single event
207
+ provider.trackAnalytic({
208
+ name: 'button-click',
209
+ value: 'save',
210
+ attributes: { section: 'toolbar' },
211
+ });
212
+
213
+ // Observable stream
214
+ const subscription = provider.trackAnalytic$(myEvent$);
215
+ // later: subscription.unsubscribe();
216
+ ```
217
+
218
+ #### Configuration
219
+
220
+ The Context Selected Collector needs the context provider.
221
+
222
+ ##### Example configuration
223
+
224
+ ```typescript
225
+ import { enableAnalytics } from '@equinor/fusion-framework-module-analytics';
226
+ import { ContextSelectedCollector } from '@equinor/fusion-framework-module-analytics/collectors';
227
+
228
+ const configure = (configurator: IModulesConfigurator<any, any>) => {
229
+ enableAnalytics(configurator, (builder) => {
230
+ builder.setCollector('context-selected', async (args) => {
231
+ const contextProvider = await args.requireInstance('context');
232
+ const appProvider = await args.requireInstance('app');
233
+ return new ContextSelectedCollector(contextProvider, appProvider);
234
+ });
235
+ });
236
+ }
237
+ ```
238
+
239
+ ### Creating Custom Collectors
240
+
241
+ You can create custom analytics collector by extending the `BaseCollector` class,
242
+ or implement the `IAnalyticsCollector` interface and add it in configuration.
243
+
244
+ #### Example Custom Collector
245
+
246
+ ```typescript
247
+ import { type AnalyticsEvent, enableAnalytics } from '@equinor/fusion-framework-module-analytics';
248
+
249
+ const configure = (configurator: IModulesConfigurator<any, any>) => {
250
+ enableAnalytics(configurator, (builder) => {
251
+ builder.setCollector('click-test', async () => {
252
+ const subject = new Subject<AnalyticsEvent>();
253
+ window.addEventListener('click', (e) => {
254
+ subject.next({
255
+ name: 'window-clicker',
256
+ value: 42,
257
+ });
258
+ });
259
+
260
+ return {
261
+ subscribe: (subscriber) => {
262
+ return subject.subscribe(subscriber);
263
+ },
264
+ };
265
+ });
266
+ });
267
+ }
268
+ ```
@@ -1,3 +1,3 @@
1
1
  // Generated by genversion.
2
- export const version = '3.0.8-next.0';
2
+ export const version = '3.0.8';
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,cAAc,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}