@streamscloud/streams-analytics-collector 2.0.10 → 3.0.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/dist/analytics-collector.d.ts +24 -0
- package/dist/analytics-collector.js +51 -0
- package/dist/{analytics/app-events-tracker.d.ts → app-events-tracker.d.ts} +37 -0
- package/dist/appearance-events-tracker.d.ts +14 -0
- package/dist/appearance-events-tracker.js +26 -0
- package/dist/contained-entity-measurements-tracker.d.ts +15 -0
- package/dist/contained-entity-measurements-tracker.js +78 -0
- package/dist/events-reporter.d.ts +14 -0
- package/dist/events-reporter.js +27 -0
- package/dist/gql-data-sender.d.ts +16 -0
- package/dist/gql-data-sender.js +38 -0
- package/dist/graphql/report-event.graphql.js +3 -0
- package/dist/graphql/report-external-event.graphql.js +3 -0
- package/dist/graphql/report-external-measurement.graphql.js +3 -0
- package/dist/graphql/report-measurement.graphql.js +3 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -4
- package/dist/measurements-batcher.d.ts +23 -0
- package/dist/measurements-batcher.js +90 -0
- package/dist/measurements-reporter.d.ts +15 -0
- package/dist/measurements-reporter.js +28 -0
- package/dist/report-event.graphql.js +3 -0
- package/dist/report-external-event.graphql.js +3 -0
- package/dist/report-external-measurement.graphql.js +3 -0
- package/dist/report-measurement.graphql.js +3 -0
- package/dist/reporting/events-reporter.d.ts +14 -0
- package/dist/reporting/events-reporter.js +30 -0
- package/dist/reporting/gql-data-sender.d.ts +12 -0
- package/dist/reporting/gql-data-sender.js +35 -0
- package/dist/reporting/index.d.ts +4 -0
- package/dist/reporting/measurements-reporter.d.ts +15 -0
- package/dist/reporting/measurements-reporter.js +31 -0
- package/dist/reporting/report-event.graphql.js +3 -0
- package/dist/reporting/report-external-event.graphql.js +3 -0
- package/dist/reporting/report-external-measurement.graphql.js +3 -0
- package/dist/reporting/report-measurement.graphql.js +3 -0
- package/dist/reporting/types.d.ts +54 -0
- package/dist/reporting/types.js +35 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.js +17 -0
- package/dist/types.d.ts +0 -4
- package/dist/types.js +38 -0
- package/dist/viewport-visibility-tracker.d.ts +13 -0
- package/dist/viewport-visibility-tracker.js +104 -0
- package/package.json +5 -6
- package/dist/adcampaignsquery.graphql.js +0 -3
- package/dist/analytics/ViewportVisibilityTracker.d.ts +0 -46
- package/dist/analytics/ViewportVisibilityTracker.js +0 -117
- package/dist/analytics/app-events-tracker.js +0 -430
- package/dist/analytics/index.d.ts +0 -3
- package/dist/analytics/index.js +0 -3
- package/dist/analytics/types.d.ts +0 -37
- package/dist/analytics/types.js +0 -33
- package/dist/analytics.graphql.js +0 -3
- package/dist/articlequery.graphql.js +0 -3
- package/dist/components/index.d.ts +0 -2
- package/dist/components/index.js +0 -1
- package/dist/components/types.d.ts +0 -19
- package/dist/components/types.js +0 -12
- package/dist/components-data/component-data-provider.service.d.ts +0 -3
- package/dist/components-data/component-data-provider.service.js +0 -35
- package/dist/components-data/components-data-fetcher.service.d.ts +0 -5
- package/dist/components-data/components-data-fetcher.service.js +0 -35
- package/dist/components-data/components-data-parameters-reader.service.d.ts +0 -2
- package/dist/components-data/components-data-parameters-reader.service.js +0 -20
- package/dist/components-data/index.d.ts +0 -4
- package/dist/components-data/index.js +0 -3
- package/dist/components-data/types.d.ts +0 -24
- package/dist/components-data/types.js +0 -6
- package/dist/contentlistsquery.graphql.js +0 -3
- package/dist/data-loaders/index.d.ts +0 -2
- package/dist/data-loaders/index.js +0 -2
- package/dist/data-loaders/short-videos-data-loader/index.d.ts +0 -2
- package/dist/data-loaders/short-videos-data-loader/loader.d.ts +0 -4
- package/dist/data-loaders/short-videos-data-loader/loader.js +0 -14
- package/dist/data-loaders/short-videos-data-loader/mapper.d.ts +0 -3
- package/dist/data-loaders/short-videos-data-loader/mapper.js +0 -27
- package/dist/data-loaders/short-videos-data-loader/types.d.ts +0 -14
- package/dist/data-loaders/streams-data-loader/index.d.ts +0 -2
- package/dist/data-loaders/streams-data-loader/loader.d.ts +0 -4
- package/dist/data-loaders/streams-data-loader/loader.js +0 -14
- package/dist/data-loaders/streams-data-loader/mapper.d.ts +0 -3
- package/dist/data-loaders/streams-data-loader/mapper.js +0 -11
- package/dist/data-loaders/streams-data-loader/types.d.ts +0 -4
- package/dist/data-loaders/types.d.ts +0 -3
- package/dist/external-analytics.graphql.js +0 -3
- package/dist/internal-analytics.graphql.js +0 -3
- package/dist/postsquery.graphql.js +0 -3
- package/dist/services/embed-content-api-client.d.ts +0 -8
- package/dist/services/embed-content-api-client.js +0 -48
- package/dist/services/embed-content-client.service.d.ts +0 -2
- package/dist/services/embed-content-client.service.js +0 -5
- package/dist/services/index.d.ts +0 -2
- package/dist/services/index.js +0 -2
- package/dist/services/operations/posts-query.graphql.js +0 -3
- package/dist/services/operations/streams-query.graphql.js +0 -3
- package/dist/services/types.d.ts +0 -303
- package/dist/streams-api-client-model.d.ts +0 -5
- package/dist/streams-content-api-client.d.ts +0 -14
- package/dist/streams-content-api-client.js +0 -89
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AppearanceEventsTracker } from './appearance-events-tracker';
|
|
2
|
+
import { MeasurementsBatcher } from './measurements-batcher';
|
|
3
|
+
import { type AnalyticsMetadata, type AnalyticsSchema, type GqlDataSenderOptions, EventsReporter, MeasurementsReporter } from './reporting';
|
|
4
|
+
export type AnalyticsCollectorInitOptions = {
|
|
5
|
+
gqlDataSenderOptions: GqlDataSenderOptions;
|
|
6
|
+
schema: AnalyticsSchema;
|
|
7
|
+
metadata?: AnalyticsMetadata | null;
|
|
8
|
+
};
|
|
9
|
+
declare class AnalyticsCollectorContainer {
|
|
10
|
+
private _eventsReporter?;
|
|
11
|
+
private _measurementsReporter?;
|
|
12
|
+
private _appearanceEventsTracker?;
|
|
13
|
+
private _measurementsBatcher?;
|
|
14
|
+
private _isInitialized;
|
|
15
|
+
initialize(options: AnalyticsCollectorInitOptions): void;
|
|
16
|
+
get eventsReporter(): EventsReporter;
|
|
17
|
+
get measurementsReporter(): MeasurementsReporter;
|
|
18
|
+
get appearanceEventsTracker(): AppearanceEventsTracker;
|
|
19
|
+
get measurementsBatcher(): MeasurementsBatcher;
|
|
20
|
+
get isInitialized(): boolean;
|
|
21
|
+
private assertInitialized;
|
|
22
|
+
}
|
|
23
|
+
export declare const AnalyticsCollector: AnalyticsCollectorContainer;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { AppearanceEventsTracker } from './appearance-events-tracker.js';
|
|
2
|
+
import { MeasurementsBatcher } from './measurements-batcher.js';
|
|
3
|
+
import { EventsReporter } from './reporting/events-reporter.js';
|
|
4
|
+
import { GqlDataSender } from './reporting/gql-data-sender.js';
|
|
5
|
+
import { MeasurementsReporter } from './reporting/measurements-reporter.js';
|
|
6
|
+
import './reporting/types.js';
|
|
7
|
+
import { ViewportVisibilityTracker } from './viewport-visibility-tracker.js';
|
|
8
|
+
|
|
9
|
+
class AnalyticsCollectorContainer {
|
|
10
|
+
_eventsReporter;
|
|
11
|
+
_measurementsReporter;
|
|
12
|
+
_appearanceEventsTracker;
|
|
13
|
+
_measurementsBatcher;
|
|
14
|
+
_isInitialized = false;
|
|
15
|
+
initialize(options) {
|
|
16
|
+
const gqlDataSender = new GqlDataSender(options.gqlDataSenderOptions);
|
|
17
|
+
const viewportVisibilityTracker = new ViewportVisibilityTracker();
|
|
18
|
+
this._eventsReporter = new EventsReporter(gqlDataSender, options.schema, options.metadata);
|
|
19
|
+
this._measurementsReporter = new MeasurementsReporter(gqlDataSender, options.schema, options.metadata);
|
|
20
|
+
this._appearanceEventsTracker = new AppearanceEventsTracker(viewportVisibilityTracker, this._eventsReporter);
|
|
21
|
+
this._measurementsBatcher = new MeasurementsBatcher(this._measurementsReporter);
|
|
22
|
+
this._isInitialized = true;
|
|
23
|
+
}
|
|
24
|
+
get eventsReporter() {
|
|
25
|
+
this.assertInitialized();
|
|
26
|
+
return this._eventsReporter;
|
|
27
|
+
}
|
|
28
|
+
get measurementsReporter() {
|
|
29
|
+
this.assertInitialized();
|
|
30
|
+
return this._measurementsReporter;
|
|
31
|
+
}
|
|
32
|
+
get appearanceEventsTracker() {
|
|
33
|
+
this.assertInitialized();
|
|
34
|
+
return this._appearanceEventsTracker;
|
|
35
|
+
}
|
|
36
|
+
get measurementsBatcher() {
|
|
37
|
+
this.assertInitialized();
|
|
38
|
+
return this._measurementsBatcher;
|
|
39
|
+
}
|
|
40
|
+
get isInitialized() {
|
|
41
|
+
return this._isInitialized;
|
|
42
|
+
}
|
|
43
|
+
assertInitialized() {
|
|
44
|
+
if (!this._isInitialized) {
|
|
45
|
+
throw new Error('AnalyticsCollector is not initialized. Call AnalyticsCollector.initialize() first.');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const AnalyticsCollector = new AnalyticsCollectorContainer();
|
|
50
|
+
|
|
51
|
+
export { AnalyticsCollector };
|
|
@@ -241,3 +241,40 @@ export declare class AppEventsTracker {
|
|
|
241
241
|
private static saveAppEvent;
|
|
242
242
|
private static queryGql;
|
|
243
243
|
}
|
|
244
|
+
export declare enum AppEventType {
|
|
245
|
+
AdClick = "AD_CLICK",
|
|
246
|
+
AdImpression = "AD_IMPRESSION",
|
|
247
|
+
CommunityMessageView = "COMMUNITY_MESSAGE_VIEW",
|
|
248
|
+
ContributionCreated = "CONTRIBUTION_CREATED",
|
|
249
|
+
PostView = "POST_VIEW",
|
|
250
|
+
ShortVideoImpression = "SHORT_VIDEO_IMPRESSION",
|
|
251
|
+
ShortVideoProductAddToCart = "SHORT_VIDEO_PRODUCT_ADD_TO_CART",
|
|
252
|
+
ShortVideoProductCheckout = "SHORT_VIDEO_PRODUCT_CHECKOUT",
|
|
253
|
+
ShortVideoProductClick = "SHORT_VIDEO_PRODUCT_CLICK",
|
|
254
|
+
ShortVideoProductImpression = "SHORT_VIDEO_PRODUCT_IMPRESSION",
|
|
255
|
+
ShortVideoView = "SHORT_VIDEO_VIEW",
|
|
256
|
+
StreamEngagementTime = "STREAM_ENGAGEMENT_TIME",
|
|
257
|
+
StreamPageView = "STREAM_PAGE_VIEW",
|
|
258
|
+
StreamProductAddToCart = "STREAM_PRODUCT_ADD_TO_CART",
|
|
259
|
+
StreamProductCheckout = "STREAM_PRODUCT_CHECKOUT",
|
|
260
|
+
StreamProductClick = "STREAM_PRODUCT_CLICK",
|
|
261
|
+
StreamProductImpression = "STREAM_PRODUCT_IMPRESSION",
|
|
262
|
+
StreamScrollDepth = "STREAM_SCROLL_DEPTH",
|
|
263
|
+
StreamTileClick = "STREAM_TILE_CLICK",
|
|
264
|
+
StreamTileImpression = "STREAM_TILE_IMPRESSION",
|
|
265
|
+
StreamView = "STREAM_VIEW"
|
|
266
|
+
}
|
|
267
|
+
export declare enum CommunityMessageStatus {
|
|
268
|
+
Sent = "SENT",
|
|
269
|
+
Delivered = "DELIVERED",
|
|
270
|
+
Read = "READ",
|
|
271
|
+
Failed = "FAILED"
|
|
272
|
+
}
|
|
273
|
+
export type TrackAppEventInput = {
|
|
274
|
+
eventType: AppEventType;
|
|
275
|
+
targetId: string;
|
|
276
|
+
ownerId?: string;
|
|
277
|
+
value?: number;
|
|
278
|
+
organizationId?: string;
|
|
279
|
+
profileId?: string;
|
|
280
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type EventsReporter, type Entity, type EntityRelation } from './reporting';
|
|
2
|
+
import type { ViewportVisibilityTracker } from './viewport-visibility-tracker';
|
|
3
|
+
export type TrackingEntityElement = {
|
|
4
|
+
element: HTMLElement;
|
|
5
|
+
entity: Entity;
|
|
6
|
+
relatedEntities?: EntityRelation[] | null;
|
|
7
|
+
};
|
|
8
|
+
export declare class AppearanceEventsTracker {
|
|
9
|
+
private viewportVisibilityTracker;
|
|
10
|
+
private eventsReporter;
|
|
11
|
+
constructor(viewportVisibilityTracker: ViewportVisibilityTracker, eventsReporter: EventsReporter);
|
|
12
|
+
trackElementAppearance({ entity, element, relatedEntities }: TrackingEntityElement): () => void;
|
|
13
|
+
untrackElementAppearance(el: HTMLElement): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EventType } from './reporting/types.js';
|
|
2
|
+
|
|
3
|
+
class AppearanceEventsTracker {
|
|
4
|
+
viewportVisibilityTracker;
|
|
5
|
+
eventsReporter;
|
|
6
|
+
constructor(viewportVisibilityTracker, eventsReporter) {
|
|
7
|
+
this.viewportVisibilityTracker = viewportVisibilityTracker;
|
|
8
|
+
this.eventsReporter = eventsReporter;
|
|
9
|
+
}
|
|
10
|
+
trackElementAppearance({ entity, element, relatedEntities }) {
|
|
11
|
+
this.viewportVisibilityTracker.registerElement(element, getTrackingId(entity), () => this.eventsReporter.reportEvent({
|
|
12
|
+
entity,
|
|
13
|
+
eventType: EventType.Appeared,
|
|
14
|
+
relatedEntities
|
|
15
|
+
}));
|
|
16
|
+
return () => this.viewportVisibilityTracker.unregisterElement(element);
|
|
17
|
+
}
|
|
18
|
+
untrackElementAppearance(el) {
|
|
19
|
+
this.viewportVisibilityTracker.unregisterElement(el);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function getTrackingId(entity) {
|
|
23
|
+
return `${entity.type}::${entity.id}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { AppearanceEventsTracker };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Entity, type MeasurementsReporter, type MeasurementType } from './reporting';
|
|
2
|
+
export type TrackingMeasurement = {
|
|
3
|
+
entity: Entity;
|
|
4
|
+
measurementType: MeasurementType;
|
|
5
|
+
value: number;
|
|
6
|
+
};
|
|
7
|
+
export declare class ContainedEntityMeasurementsTracker {
|
|
8
|
+
private measurementsReporter;
|
|
9
|
+
private containerEntities;
|
|
10
|
+
constructor(measurementsReporter: MeasurementsReporter);
|
|
11
|
+
collectEntityMeasurement(containers: Entity[], measurement: TrackingMeasurement): void;
|
|
12
|
+
reportGroupedMeasurements(containers: Entity[], onReported?: (measurement: TrackingMeasurement) => void): Promise<void>;
|
|
13
|
+
clearContainerEntities(containers: Entity[]): void;
|
|
14
|
+
reset(): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { EntityRelationType } from './reporting/types.js';
|
|
2
|
+
|
|
3
|
+
class ContainedEntityMeasurementsTracker {
|
|
4
|
+
measurementsReporter;
|
|
5
|
+
containerEntities = new Map();
|
|
6
|
+
constructor(measurementsReporter) {
|
|
7
|
+
this.measurementsReporter = measurementsReporter;
|
|
8
|
+
}
|
|
9
|
+
collectEntityMeasurement(containers, measurement) {
|
|
10
|
+
if (containers.length === 0) {
|
|
11
|
+
throw new Error('At least one container entity is required.');
|
|
12
|
+
}
|
|
13
|
+
const groupKey = getContainerGroupKey(containers);
|
|
14
|
+
let entitiesInGroup = this.containerEntities.get(groupKey);
|
|
15
|
+
if (!entitiesInGroup) {
|
|
16
|
+
entitiesInGroup = new Map();
|
|
17
|
+
this.containerEntities.set(groupKey, entitiesInGroup);
|
|
18
|
+
}
|
|
19
|
+
entitiesInGroup.set(getMeasurementKey(measurement), measurement);
|
|
20
|
+
}
|
|
21
|
+
async reportGroupedMeasurements(containers, onReported) {
|
|
22
|
+
if (containers.length === 0) {
|
|
23
|
+
throw new Error('At least one container entity is required.');
|
|
24
|
+
}
|
|
25
|
+
const groupKey = getContainerGroupKey(containers);
|
|
26
|
+
const entitiesInGroup = this.containerEntities.get(groupKey);
|
|
27
|
+
if (!entitiesInGroup || entitiesInGroup.size === 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const containerRelations = getContainerRelations(containers);
|
|
31
|
+
try {
|
|
32
|
+
await Promise.all(Array.from(entitiesInGroup.values()).map(async (measurement) => {
|
|
33
|
+
await this.measurementsReporter.reportMeasurement({
|
|
34
|
+
entity: measurement.entity,
|
|
35
|
+
measurementType: measurement.measurementType,
|
|
36
|
+
value: measurement.value,
|
|
37
|
+
relatedEntities: containerRelations,
|
|
38
|
+
});
|
|
39
|
+
onReported?.(measurement);
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
this.containerEntities.delete(groupKey);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
clearContainerEntities(containers) {
|
|
47
|
+
const groupKey = getContainerGroupKey(containers);
|
|
48
|
+
this.containerEntities.delete(groupKey);
|
|
49
|
+
}
|
|
50
|
+
reset() {
|
|
51
|
+
this.containerEntities.clear();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function getEntityKey(entity) {
|
|
55
|
+
return `${entity.type}::${entity.id}`;
|
|
56
|
+
}
|
|
57
|
+
function getMeasurementKey(container) {
|
|
58
|
+
return `${getEntityKey(container.entity)}::${container.measurementType}`;
|
|
59
|
+
}
|
|
60
|
+
function normalizeContainers(containers) {
|
|
61
|
+
const uniq = new Map();
|
|
62
|
+
for (const c of containers) {
|
|
63
|
+
uniq.set(getEntityKey(c), c);
|
|
64
|
+
}
|
|
65
|
+
return Array.from(uniq.values()).sort((a, b) => getEntityKey(a).localeCompare(getEntityKey(b)));
|
|
66
|
+
}
|
|
67
|
+
function getContainerGroupKey(containers) {
|
|
68
|
+
const keys = normalizeContainers(containers).map(getEntityKey);
|
|
69
|
+
return keys.join('||');
|
|
70
|
+
}
|
|
71
|
+
function getContainerRelations(containers) {
|
|
72
|
+
return normalizeContainers(containers).map((c) => ({
|
|
73
|
+
relationType: EntityRelationType.PlacedIn,
|
|
74
|
+
entity: c,
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { ContainedEntityMeasurementsTracker };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AnalyticsMetadata, type EntityType, type EventType, type EntityRelation } from './types';
|
|
2
|
+
import type { GqlDataSender } from './gql-data-sender';
|
|
3
|
+
export type ReportedEvent = {
|
|
4
|
+
entityType: EntityType;
|
|
5
|
+
entityId: string;
|
|
6
|
+
eventType: EventType;
|
|
7
|
+
relatedEntities?: EntityRelation[] | null;
|
|
8
|
+
};
|
|
9
|
+
export declare class EventsReporter {
|
|
10
|
+
private gqlDataSender;
|
|
11
|
+
private analyticsMetadata?;
|
|
12
|
+
constructor(gqlDataSender: GqlDataSender, analyticsMetadata?: AnalyticsMetadata | null);
|
|
13
|
+
reportEvent({ entityType, entityId, eventType, relatedEntities }: ReportedEvent): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ApiMode } from './types.js';
|
|
2
|
+
import ReportEvent from './report-event.graphql.js';
|
|
3
|
+
import ReportExternalEvent from './report-external-event.graphql.js';
|
|
4
|
+
|
|
5
|
+
class EventsReporter {
|
|
6
|
+
gqlDataSender;
|
|
7
|
+
analyticsMetadata;
|
|
8
|
+
constructor(gqlDataSender, analyticsMetadata) {
|
|
9
|
+
this.gqlDataSender = gqlDataSender;
|
|
10
|
+
this.analyticsMetadata = analyticsMetadata;
|
|
11
|
+
}
|
|
12
|
+
async reportEvent({ entityType, entityId, eventType, relatedEntities }) {
|
|
13
|
+
const input = {
|
|
14
|
+
entityType,
|
|
15
|
+
entityId,
|
|
16
|
+
eventType,
|
|
17
|
+
relatedEntities,
|
|
18
|
+
installation: this.analyticsMetadata?.installationId
|
|
19
|
+
? {
|
|
20
|
+
id: this.analyticsMetadata.installationId,
|
|
21
|
+
} : null
|
|
22
|
+
};
|
|
23
|
+
await this.gqlDataSender.send((apiMode) => apiMode === ApiMode.Internal ? ReportEvent : ReportExternalEvent, { input });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { EventsReporter };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Client } from '@urql/core';
|
|
2
|
+
import type { ApiMode } from './types';
|
|
3
|
+
export type GqlDataSenderOptions = {
|
|
4
|
+
client: Client;
|
|
5
|
+
mode: ApiMode;
|
|
6
|
+
} | {
|
|
7
|
+
endpoint: string;
|
|
8
|
+
mode: ApiMode;
|
|
9
|
+
};
|
|
10
|
+
export declare class GqlDataSender {
|
|
11
|
+
private gqlEndpoint;
|
|
12
|
+
private client;
|
|
13
|
+
private apiMode;
|
|
14
|
+
constructor(options: GqlDataSenderOptions);
|
|
15
|
+
send(querySelector: (apiMode: ApiMode) => string, variables?: object): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class GqlDataSender {
|
|
2
|
+
gqlEndpoint = null;
|
|
3
|
+
client = null;
|
|
4
|
+
apiMode;
|
|
5
|
+
constructor(options) {
|
|
6
|
+
if ('client' in options) {
|
|
7
|
+
this.client = options.client;
|
|
8
|
+
this.gqlEndpoint = null;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
this.gqlEndpoint = options.endpoint;
|
|
12
|
+
this.client = null;
|
|
13
|
+
}
|
|
14
|
+
this.apiMode = options.mode;
|
|
15
|
+
}
|
|
16
|
+
async send(querySelector, variables) {
|
|
17
|
+
const query = querySelector(this.apiMode);
|
|
18
|
+
if (this.gqlEndpoint) {
|
|
19
|
+
await sendGqlBeacon(this.gqlEndpoint, query, variables);
|
|
20
|
+
}
|
|
21
|
+
else if (this.client) {
|
|
22
|
+
await this.client.mutation(query, variables).toPromise();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.error('EventsReporter not properly initialized.');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function sendGqlBeacon(endpoint, query, variables) {
|
|
30
|
+
const body = JSON.stringify({ query, variables });
|
|
31
|
+
const blob = new Blob([body], { type: 'application/json' });
|
|
32
|
+
const accepted = navigator.sendBeacon(endpoint, blob);
|
|
33
|
+
if (!accepted) {
|
|
34
|
+
throw new Error('Failed to queue analytics beacon.');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { GqlDataSender };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
export
|
|
2
|
-
export {
|
|
1
|
+
export { EntityRelationType, EntityType, EventType, MeasurementType, type AnalyticsMetadata, type AnalyticsSchema, type Entity, type EntityRelation, } from './reporting/types';
|
|
2
|
+
export { type AnalyticsCollectorInitOptions, AnalyticsCollector } from './analytics-collector';
|
|
3
|
+
export { type TrackingEntityElement, AppearanceEventsTracker } from './appearance-events-tracker';
|
|
4
|
+
export { ViewportVisibilityTracker } from './viewport-visibility-tracker';
|
|
5
|
+
export { type BatchedMeasurement, type MeasurementsBatchReportResult, type FailedBatchedMeasurement, MeasurementsBatcher, } from './measurements-batcher';
|
|
6
|
+
export { Schemas } from './schemas';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export { EntityRelationType, EntityType, EventType, MeasurementType } from './reporting/types.js';
|
|
2
|
+
export { AnalyticsCollector } from './analytics-collector.js';
|
|
3
|
+
export { AppearanceEventsTracker } from './appearance-events-tracker.js';
|
|
4
|
+
export { ViewportVisibilityTracker } from './viewport-visibility-tracker.js';
|
|
5
|
+
export { MeasurementsBatcher } from './measurements-batcher.js';
|
|
6
|
+
export { Schemas } from './schemas.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Entity, type MeasurementsReporter, type MeasurementType } from './reporting';
|
|
2
|
+
export type BatchedMeasurement = {
|
|
3
|
+
entity: Entity;
|
|
4
|
+
measurementType: MeasurementType;
|
|
5
|
+
value: number;
|
|
6
|
+
};
|
|
7
|
+
export type FailedBatchedMeasurement = {
|
|
8
|
+
measurement: BatchedMeasurement;
|
|
9
|
+
error: unknown;
|
|
10
|
+
};
|
|
11
|
+
export type MeasurementsBatchReportResult = {
|
|
12
|
+
succeeded: BatchedMeasurement[];
|
|
13
|
+
failed: FailedBatchedMeasurement[];
|
|
14
|
+
};
|
|
15
|
+
export declare class MeasurementsBatcher {
|
|
16
|
+
private measurementsReporter;
|
|
17
|
+
private containerEntities;
|
|
18
|
+
constructor(measurementsReporter: MeasurementsReporter);
|
|
19
|
+
collect(containers: Entity[], measurement: BatchedMeasurement): void;
|
|
20
|
+
reportBatch(containers: Entity[]): Promise<MeasurementsBatchReportResult>;
|
|
21
|
+
clearBatch(containers: Entity[]): void;
|
|
22
|
+
reset(): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { EntityRelationType } from './reporting/types.js';
|
|
2
|
+
|
|
3
|
+
class MeasurementsBatcher {
|
|
4
|
+
measurementsReporter;
|
|
5
|
+
containerEntities = new Map();
|
|
6
|
+
constructor(measurementsReporter) {
|
|
7
|
+
this.measurementsReporter = measurementsReporter;
|
|
8
|
+
}
|
|
9
|
+
collect(containers, measurement) {
|
|
10
|
+
if (containers.length === 0) {
|
|
11
|
+
throw new Error('At least one container entity is required.');
|
|
12
|
+
}
|
|
13
|
+
const groupKey = getContainerGroupKey(containers);
|
|
14
|
+
let entitiesInGroup = this.containerEntities.get(groupKey);
|
|
15
|
+
if (!entitiesInGroup) {
|
|
16
|
+
entitiesInGroup = new Map();
|
|
17
|
+
this.containerEntities.set(groupKey, entitiesInGroup);
|
|
18
|
+
}
|
|
19
|
+
entitiesInGroup.set(getMeasurementKey(measurement), measurement);
|
|
20
|
+
}
|
|
21
|
+
async reportBatch(containers) {
|
|
22
|
+
if (containers.length === 0) {
|
|
23
|
+
throw new Error('At least one container entity is required.');
|
|
24
|
+
}
|
|
25
|
+
const groupKey = getContainerGroupKey(containers);
|
|
26
|
+
const entitiesInGroup = this.containerEntities.get(groupKey);
|
|
27
|
+
if (!entitiesInGroup || entitiesInGroup.size === 0) {
|
|
28
|
+
return { succeeded: [], failed: [] };
|
|
29
|
+
}
|
|
30
|
+
const containerRelations = getContainerRelations(containers);
|
|
31
|
+
const entries = Array.from(entitiesInGroup.entries());
|
|
32
|
+
const succeeded = [];
|
|
33
|
+
const failed = [];
|
|
34
|
+
await Promise.all(entries.map(async ([key, measurement]) => {
|
|
35
|
+
try {
|
|
36
|
+
await this.measurementsReporter.reportMeasurement({
|
|
37
|
+
entity: measurement.entity,
|
|
38
|
+
measurementType: measurement.measurementType,
|
|
39
|
+
value: measurement.value,
|
|
40
|
+
relatedEntities: containerRelations,
|
|
41
|
+
});
|
|
42
|
+
succeeded.push(measurement);
|
|
43
|
+
entitiesInGroup.delete(key);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
failed.push({ measurement, error });
|
|
47
|
+
}
|
|
48
|
+
}));
|
|
49
|
+
if (entitiesInGroup.size === 0) {
|
|
50
|
+
this.containerEntities.delete(groupKey);
|
|
51
|
+
}
|
|
52
|
+
return { succeeded, failed };
|
|
53
|
+
}
|
|
54
|
+
clearBatch(containers) {
|
|
55
|
+
const groupKey = getContainerGroupKey(containers);
|
|
56
|
+
this.containerEntities.delete(groupKey);
|
|
57
|
+
}
|
|
58
|
+
reset() {
|
|
59
|
+
this.containerEntities.clear();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function getEntityKey(entity) {
|
|
63
|
+
return `${entity.type}::${entity.id}`;
|
|
64
|
+
}
|
|
65
|
+
function getMeasurementKey(container) {
|
|
66
|
+
return `${getEntityKey(container.entity)}::${container.measurementType}`;
|
|
67
|
+
}
|
|
68
|
+
function normalizeContainers(containers) {
|
|
69
|
+
const uniq = new Map();
|
|
70
|
+
for (const c of containers) {
|
|
71
|
+
uniq.set(getEntityKey(c), c);
|
|
72
|
+
}
|
|
73
|
+
return Array.from(uniq.values()).sort((a, b) => {
|
|
74
|
+
const ka = getEntityKey(a);
|
|
75
|
+
const kb = getEntityKey(b);
|
|
76
|
+
return ka < kb ? -1 : ka > kb ? 1 : 0;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function getContainerGroupKey(containers) {
|
|
80
|
+
const keys = normalizeContainers(containers).map(getEntityKey);
|
|
81
|
+
return keys.join('||');
|
|
82
|
+
}
|
|
83
|
+
function getContainerRelations(containers) {
|
|
84
|
+
return normalizeContainers(containers).map((c) => ({
|
|
85
|
+
relationType: EntityRelationType.PlacedIn,
|
|
86
|
+
entity: c,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { MeasurementsBatcher };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AnalyticsMetadata, type EntityType, type MeasurementType, type EntityRelation } from './types';
|
|
2
|
+
import type { GqlDataSender } from './gql-data-sender';
|
|
3
|
+
export type ReportedMeasurement = {
|
|
4
|
+
entityType: EntityType;
|
|
5
|
+
entityId: string;
|
|
6
|
+
measurementType: MeasurementType;
|
|
7
|
+
value: number;
|
|
8
|
+
relatedEntities?: EntityRelation[] | null;
|
|
9
|
+
};
|
|
10
|
+
export declare class MeasurementsReporter {
|
|
11
|
+
private gqlDataSender;
|
|
12
|
+
private analyticsMetadata?;
|
|
13
|
+
constructor(gqlDataSender: GqlDataSender, analyticsMetadata?: AnalyticsMetadata | null);
|
|
14
|
+
reportMeasurement({ entityType, entityId, measurementType, value, relatedEntities }: ReportedMeasurement): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ApiMode } from './types.js';
|
|
2
|
+
import ReportMeasurement from './report-measurement.graphql.js';
|
|
3
|
+
import ReportExternalMeasurement from './report-external-measurement.graphql.js';
|
|
4
|
+
|
|
5
|
+
class MeasurementsReporter {
|
|
6
|
+
gqlDataSender;
|
|
7
|
+
analyticsMetadata;
|
|
8
|
+
constructor(gqlDataSender, analyticsMetadata) {
|
|
9
|
+
this.gqlDataSender = gqlDataSender;
|
|
10
|
+
this.analyticsMetadata = analyticsMetadata;
|
|
11
|
+
}
|
|
12
|
+
async reportMeasurement({ entityType, entityId, measurementType, value, relatedEntities }) {
|
|
13
|
+
const input = {
|
|
14
|
+
entityType,
|
|
15
|
+
entityId,
|
|
16
|
+
measurementType,
|
|
17
|
+
value,
|
|
18
|
+
relatedEntities,
|
|
19
|
+
installation: this.analyticsMetadata?.installationId
|
|
20
|
+
? {
|
|
21
|
+
id: this.analyticsMetadata.installationId,
|
|
22
|
+
} : null,
|
|
23
|
+
};
|
|
24
|
+
await this.gqlDataSender.send((apiMode) => apiMode === ApiMode.Internal ? ReportMeasurement : ReportExternalMeasurement, { input });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { MeasurementsReporter };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AnalyticsSchema, AnalyticsMetadata, EventType, EntityRelation, Entity } from './types';
|
|
2
|
+
import type { GqlDataSender } from './gql-data-sender';
|
|
3
|
+
export type ReportedEvent = {
|
|
4
|
+
entity: Entity;
|
|
5
|
+
eventType: EventType;
|
|
6
|
+
relatedEntities?: EntityRelation[] | null;
|
|
7
|
+
};
|
|
8
|
+
export declare class EventsReporter {
|
|
9
|
+
private gqlDataSender;
|
|
10
|
+
private analyticsSchema;
|
|
11
|
+
private analyticsMetadata?;
|
|
12
|
+
constructor(gqlDataSender: GqlDataSender, analyticsSchema: AnalyticsSchema, analyticsMetadata?: AnalyticsMetadata | null);
|
|
13
|
+
reportEvent({ entity, eventType, relatedEntities }: ReportedEvent): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class EventsReporter {
|
|
2
|
+
gqlDataSender;
|
|
3
|
+
analyticsSchema;
|
|
4
|
+
analyticsMetadata;
|
|
5
|
+
constructor(gqlDataSender, analyticsSchema, analyticsMetadata) {
|
|
6
|
+
this.gqlDataSender = gqlDataSender;
|
|
7
|
+
this.analyticsSchema = analyticsSchema;
|
|
8
|
+
this.analyticsMetadata = analyticsMetadata;
|
|
9
|
+
}
|
|
10
|
+
async reportEvent({ entity, eventType, relatedEntities }) {
|
|
11
|
+
const input = {
|
|
12
|
+
entityType: entity.type,
|
|
13
|
+
entityId: entity.id,
|
|
14
|
+
eventType,
|
|
15
|
+
relatedEntities: relatedEntities
|
|
16
|
+
?.map(({ relationType, entity }) => ({
|
|
17
|
+
relationType,
|
|
18
|
+
entityType: entity.type,
|
|
19
|
+
entityId: entity.id,
|
|
20
|
+
})) ?? null,
|
|
21
|
+
installation: this.analyticsMetadata?.installationId
|
|
22
|
+
? {
|
|
23
|
+
id: this.analyticsMetadata.installationId,
|
|
24
|
+
} : null,
|
|
25
|
+
};
|
|
26
|
+
await this.gqlDataSender.send(this.analyticsSchema.reportEvent, { input });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { EventsReporter };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Client } from '@urql/core';
|
|
2
|
+
export type GqlDataSenderOptions = {
|
|
3
|
+
client: Client;
|
|
4
|
+
} | {
|
|
5
|
+
endpoint: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class GqlDataSender {
|
|
8
|
+
private gqlEndpoint;
|
|
9
|
+
private client;
|
|
10
|
+
constructor(options: GqlDataSenderOptions);
|
|
11
|
+
send(query: string, variables?: object): Promise<void>;
|
|
12
|
+
}
|