@vouchfor/embeds 0.0.0-experiment.cbb21a3 → 0.0.0-experiment.d892f46
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/es/embeds.js +365 -287
- package/dist/es/embeds.js.map +1 -1
- package/dist/es/{components → src/components}/Embed/controllers/tracking.d.ts +2 -0
- package/dist/iife/embeds.iife.js +69 -69
- package/dist/iife/embeds.iife.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Embed/controllers/fetcher.ts +3 -3
- package/src/components/Embed/controllers/tracking.ts +54 -50
- /package/dist/es/{components → src/components}/Embed/controllers/fetcher.d.ts +0 -0
- /package/dist/es/{components → src/components}/Embed/index.d.ts +0 -0
- /package/dist/es/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/es/{utils → src/utils}/env.d.ts +0 -0
- /package/dist/es/{utils → src/utils}/events.d.ts +0 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vouchfor/embeds",
|
3
|
-
"version": "0.0.0-experiment.
|
3
|
+
"version": "0.0.0-experiment.d892f46",
|
4
4
|
"license": "MIT",
|
5
5
|
"author": "Aaron Williams",
|
6
6
|
"main": "dist/es/embeds.js",
|
@@ -36,7 +36,7 @@
|
|
36
36
|
},
|
37
37
|
"dependencies": {
|
38
38
|
"@lit/task": "^1.0.0",
|
39
|
-
"@vouchfor/media-player": "0.0.0-experiment.
|
39
|
+
"@vouchfor/media-player": "0.0.0-experiment.d892f46",
|
40
40
|
"uuid": "^9.0.1"
|
41
41
|
},
|
42
42
|
"peerDependencies": {
|
@@ -45,13 +45,13 @@ class FetcherController {
|
|
45
45
|
});
|
46
46
|
|
47
47
|
const vouch = await res.json();
|
48
|
-
this.host.dispatchEvent(new CustomEvent('vouch:loaded', { detail:
|
48
|
+
this.host.dispatchEvent(new CustomEvent('vouch:loaded', { detail: vouch?.id }));
|
49
49
|
|
50
50
|
// HACK: we're currently using API Gateway caching on the embed API without any invalidation logic,
|
51
51
|
// so to ensure that the cache stays up to date, whenever we detect a cache hit we trigger another
|
52
52
|
// API call with the `Cache-Control` header which will re-fill the cache
|
53
53
|
const resCacheCheck = res?.headers?.get('X-Cache-Check');
|
54
|
-
if (resCacheCheck
|
54
|
+
if (resCacheCheck !== cacheCheck) {
|
55
55
|
fetch(`${embedApiUrl}/vouches/${vouchId}`, {
|
56
56
|
method: 'GET',
|
57
57
|
headers: [
|
@@ -81,7 +81,7 @@ class FetcherController {
|
|
81
81
|
// so to ensure that the cache stays up to date, whenever we detect a cache hit we trigger another
|
82
82
|
// API call with the `Cache-Control` header which will re-fill the cache
|
83
83
|
const resCacheCheck = res?.headers?.get('X-Cache-Check');
|
84
|
-
if (resCacheCheck
|
84
|
+
if (resCacheCheck !== cacheCheck) {
|
85
85
|
fetch(`${embedApiUrl}/templates/${templateId}`, {
|
86
86
|
method: 'GET',
|
87
87
|
headers: [
|
@@ -4,15 +4,16 @@ import type { Embed } from '..';
|
|
4
4
|
import type { VideoEventDetail } from '@vouchfor/media-player';
|
5
5
|
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
6
6
|
|
7
|
+
import packageJson from '../../../../package.json';
|
7
8
|
import { getEnvUrls } from '~/utils/env';
|
8
9
|
|
9
|
-
|
10
|
-
const STREAMED_THROTTLE = 10;
|
10
|
+
const MINIMUM_SEND_THRESHOLD = 1;
|
11
11
|
|
12
12
|
type EmbedHost = ReactiveControllerHost & Embed;
|
13
13
|
|
14
14
|
type TrackingEvent = 'VOUCH_LOADED' | 'VOUCH_RESPONSE_VIEWED' | 'VIDEO_PLAYED' | 'VIDEO_STREAMED';
|
15
15
|
type TrackingPayload = {
|
16
|
+
vouchId?: string;
|
16
17
|
answerId?: string;
|
17
18
|
streamStart?: number;
|
18
19
|
streamEnd?: number;
|
@@ -45,13 +46,14 @@ class TrackingController implements ReactiveController {
|
|
45
46
|
host.addController(this);
|
46
47
|
}
|
47
48
|
|
48
|
-
private _findVouchId() {
|
49
|
+
private _findVouchId(payload?: TrackingPayload) {
|
50
|
+
if (payload && 'vouchId' in payload) {
|
51
|
+
return payload.vouchId;
|
52
|
+
}
|
49
53
|
if (this.host.vouch) {
|
50
|
-
if ('uuid' in this.host.vouch) {
|
51
|
-
return this.host.vouch.uuid;
|
52
|
-
}
|
53
54
|
return this.host.vouch.id;
|
54
55
|
}
|
56
|
+
return null;
|
55
57
|
}
|
56
58
|
|
57
59
|
private _createVisitor = (visitorId: string) => {
|
@@ -130,7 +132,7 @@ class TrackingController implements ReactiveController {
|
|
130
132
|
};
|
131
133
|
|
132
134
|
private _sendTrackingEvent = (event: TrackingEvent, payload?: TrackingPayload) => {
|
133
|
-
const vouchId = this._findVouchId();
|
135
|
+
const vouchId = this._findVouchId(payload);
|
134
136
|
|
135
137
|
if (!vouchId || this.host.disableTracking) {
|
136
138
|
return;
|
@@ -143,18 +145,40 @@ class TrackingController implements ReactiveController {
|
|
143
145
|
`${publicApiUrl}/api/events`,
|
144
146
|
JSON.stringify({
|
145
147
|
event,
|
146
|
-
payload
|
148
|
+
payload: {
|
149
|
+
...payload,
|
150
|
+
vouchId
|
151
|
+
},
|
147
152
|
context: {
|
148
153
|
'x-uid-client': client,
|
149
154
|
'x-uid-tab': tab,
|
150
155
|
'x-uid-request': request,
|
151
156
|
'x-uid-visitor': visitor,
|
152
|
-
'x-reporting-metadata': this._getReportingMetadata()
|
157
|
+
'x-reporting-metadata': this._getReportingMetadata(),
|
158
|
+
'x-embeds-version': packageJson.version
|
153
159
|
}
|
154
160
|
})
|
155
161
|
);
|
156
162
|
};
|
157
163
|
|
164
|
+
private _streamEnded = () => {
|
165
|
+
if (this._currentlyPlayingVideo) {
|
166
|
+
const { id, key } = this._currentlyPlayingVideo;
|
167
|
+
// Don't send a tracking event when seeking backwards
|
168
|
+
if (this._streamLatestTime[key] > this._streamStartTime[key] + MINIMUM_SEND_THRESHOLD) {
|
169
|
+
// Send a video streamed event any time the stream ends to capture the time between starting
|
170
|
+
// the video and the video stopping for any reason (pausing, deleting the embed node or closing the browser)
|
171
|
+
this._sendTrackingEvent('VIDEO_STREAMED', {
|
172
|
+
answerId: id,
|
173
|
+
streamStart: this._streamStartTime[key],
|
174
|
+
streamEnd: this._streamLatestTime[key]
|
175
|
+
});
|
176
|
+
}
|
177
|
+
delete this._streamStartTime[key];
|
178
|
+
delete this._streamLatestTime[key];
|
179
|
+
}
|
180
|
+
};
|
181
|
+
|
158
182
|
private _handleVouchLoaded = ({ detail: vouchId }: CustomEvent<string>) => {
|
159
183
|
if (!vouchId) {
|
160
184
|
return;
|
@@ -162,7 +186,7 @@ class TrackingController implements ReactiveController {
|
|
162
186
|
|
163
187
|
// Only send loaded event once per session
|
164
188
|
if (!this._hasLoaded[vouchId]) {
|
165
|
-
this._sendTrackingEvent('VOUCH_LOADED');
|
189
|
+
this._sendTrackingEvent('VOUCH_LOADED', { vouchId });
|
166
190
|
this._hasLoaded[vouchId] = true;
|
167
191
|
}
|
168
192
|
};
|
@@ -186,54 +210,46 @@ class TrackingController implements ReactiveController {
|
|
186
210
|
this._answersViewed[key] = true;
|
187
211
|
}
|
188
212
|
|
189
|
-
this._streamStartTime[key]
|
190
|
-
|
191
|
-
};
|
192
|
-
|
193
|
-
private _handleVideoTimeUpdate = ({ detail: { id, key, node } }: CustomEvent<VideoEventDetail>) => {
|
194
|
-
// We only want to count any time that the video is actually playing
|
195
|
-
if (!this.host.paused) {
|
196
|
-
this._currentlyPlayingVideo = { id, key, node };
|
213
|
+
if (!this._streamStartTime[key]) {
|
214
|
+
this._streamStartTime[key] = node.currentTime;
|
197
215
|
this._streamLatestTime[key] = node.currentTime;
|
198
216
|
}
|
217
|
+
};
|
199
218
|
|
219
|
+
private _handleVideoTimeUpdate = ({ detail: { id, key, node } }: CustomEvent<VideoEventDetail>) => {
|
200
220
|
if (
|
201
|
-
|
221
|
+
// We only want to count any time that the video is actually playing
|
202
222
|
!this.host.paused &&
|
203
|
-
// Only
|
204
|
-
id === this.host.scene?.video?.id
|
205
|
-
// Throttle the frequency that we send streamed events while playing
|
206
|
-
this._streamLatestTime[key] - this._streamStartTime[key] > STREAMED_THROTTLE
|
223
|
+
// Only update the latest time if this event fires for the currently active video
|
224
|
+
id === this.host.scene?.video?.id
|
207
225
|
) {
|
208
|
-
this.
|
209
|
-
|
210
|
-
streamStart: this._streamStartTime[key],
|
211
|
-
streamEnd: this._streamLatestTime[key]
|
212
|
-
});
|
213
|
-
|
214
|
-
this._streamStartTime[key] = node.currentTime;
|
226
|
+
this._currentlyPlayingVideo = { id, key, node };
|
227
|
+
this._streamLatestTime[key] = node.currentTime;
|
215
228
|
}
|
216
229
|
};
|
217
230
|
|
218
231
|
private _handleVideoPause = ({ detail: { id, key } }: CustomEvent<VideoEventDetail>) => {
|
219
|
-
|
220
|
-
if (this._streamLatestTime[key] > this._streamStartTime[key]) {
|
221
|
-
// Send a video streamed event any time the video pauses then reset the streamed state
|
222
|
-
// We do this to capture the last bit of time that the video was played between the previous
|
223
|
-
// stream event and the video being paused manually or stopping because it ended
|
232
|
+
if (this._streamLatestTime[key] > this._streamStartTime[key] + MINIMUM_SEND_THRESHOLD) {
|
224
233
|
this._sendTrackingEvent('VIDEO_STREAMED', {
|
225
234
|
answerId: id,
|
226
235
|
streamStart: this._streamStartTime[key],
|
227
236
|
streamEnd: this._streamLatestTime[key]
|
228
237
|
});
|
229
238
|
}
|
230
|
-
this._currentlyPlayingVideo = null;
|
231
239
|
delete this._streamStartTime[key];
|
232
240
|
delete this._streamLatestTime[key];
|
233
241
|
};
|
234
242
|
|
243
|
+
private _handleVisibilityChange = () => {
|
244
|
+
if (document.visibilityState === 'hidden') {
|
245
|
+
this.host.pause();
|
246
|
+
this._streamEnded();
|
247
|
+
}
|
248
|
+
};
|
249
|
+
|
235
250
|
hostConnected() {
|
236
251
|
requestAnimationFrame(() => {
|
252
|
+
document.addEventListener('visibilitychange', this._handleVisibilityChange);
|
237
253
|
this.host.addEventListener('vouch:loaded', this._handleVouchLoaded);
|
238
254
|
this.host.mediaPlayer?.addEventListener('play', this._handlePlay);
|
239
255
|
this.host.mediaPlayer?.addEventListener('video:play', this._handleVideoPlay);
|
@@ -243,20 +259,8 @@ class TrackingController implements ReactiveController {
|
|
243
259
|
}
|
244
260
|
|
245
261
|
hostDisconnected() {
|
246
|
-
|
247
|
-
|
248
|
-
if (this._streamLatestTime[key] > this._streamStartTime[key]) {
|
249
|
-
// Send a video streamed event any time the video pauses then reset the streamed state
|
250
|
-
// We do this to capture the last bit of time that the video was played between the previous
|
251
|
-
// stream event and the video being paused manually or stopping because it ended
|
252
|
-
this._sendTrackingEvent('VIDEO_STREAMED', {
|
253
|
-
answerId: id,
|
254
|
-
streamStart: this._streamStartTime[key],
|
255
|
-
streamEnd: this._streamLatestTime[key]
|
256
|
-
});
|
257
|
-
}
|
258
|
-
}
|
259
|
-
|
262
|
+
this._streamEnded();
|
263
|
+
document.removeEventListener('visibilitychange', this._handleVisibilityChange);
|
260
264
|
this.host.removeEventListener('vouch:loaded', this._handleVouchLoaded);
|
261
265
|
this.host.mediaPlayer?.removeEventListener('play', this._handlePlay);
|
262
266
|
this.host.mediaPlayer?.removeEventListener('video:play', this._handleVideoPlay);
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|