@vouchfor/embeds 0.0.0-experiment.607fdcd → 0.0.0-experiment.6242786
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 +363 -278
- package/dist/es/embeds.js.map +1 -1
- package/dist/es/{components → src/components}/Embed/controllers/tracking.d.ts +4 -0
- package/dist/es/{components → src/components}/Embed/index.d.ts +2 -1
- package/dist/iife/embeds.iife.js +297 -186
- package/dist/iife/embeds.iife.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Embed/Embed.stories.ts +1 -0
- package/src/components/Embed/controllers/fetcher.ts +1 -1
- package/src/components/Embed/controllers/tracking.ts +71 -48
- package/src/components/Embed/index.ts +5 -1
- /package/dist/es/{components → src/components}/Embed/controllers/fetcher.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.6242786",
|
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.6242786",
|
40
40
|
"uuid": "^9.0.1"
|
41
41
|
},
|
42
42
|
"peerDependencies": {
|
@@ -45,7 +45,7 @@ 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
|
@@ -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,7 +46,10 @@ 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
54
|
return this.host.vouch.id;
|
51
55
|
}
|
@@ -128,7 +132,7 @@ class TrackingController implements ReactiveController {
|
|
128
132
|
};
|
129
133
|
|
130
134
|
private _sendTrackingEvent = (event: TrackingEvent, payload?: TrackingPayload) => {
|
131
|
-
const vouchId = this._findVouchId();
|
135
|
+
const vouchId = this._findVouchId(payload);
|
132
136
|
|
133
137
|
if (!vouchId || this.host.disableTracking) {
|
134
138
|
return;
|
@@ -138,24 +142,45 @@ class TrackingController implements ReactiveController {
|
|
138
142
|
const { client, tab, request, visitor } = this._getUids();
|
139
143
|
|
140
144
|
navigator.sendBeacon(
|
141
|
-
`${publicApiUrl}/api/events`,
|
145
|
+
`${publicApiUrl}/api/v2/events`,
|
142
146
|
JSON.stringify({
|
143
147
|
event,
|
144
148
|
payload: {
|
145
|
-
|
146
|
-
|
149
|
+
...payload,
|
150
|
+
vouchId
|
147
151
|
},
|
148
152
|
context: {
|
149
153
|
'x-uid-client': client,
|
150
154
|
'x-uid-tab': tab,
|
151
155
|
'x-uid-request': request,
|
152
156
|
'x-uid-visitor': visitor,
|
153
|
-
'x-reporting-metadata': this._getReportingMetadata()
|
157
|
+
'x-reporting-metadata': this._getReportingMetadata(),
|
158
|
+
'x-embeds-version': packageJson.version
|
154
159
|
}
|
155
160
|
})
|
156
161
|
);
|
157
162
|
};
|
158
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
|
+
|
178
|
+
// Make sure these events are only sent once by deleting the start and latest times
|
179
|
+
delete this._streamStartTime[key];
|
180
|
+
delete this._streamLatestTime[key];
|
181
|
+
}
|
182
|
+
};
|
183
|
+
|
159
184
|
private _handleVouchLoaded = ({ detail: vouchId }: CustomEvent<string>) => {
|
160
185
|
if (!vouchId) {
|
161
186
|
return;
|
@@ -163,7 +188,7 @@ class TrackingController implements ReactiveController {
|
|
163
188
|
|
164
189
|
// Only send loaded event once per session
|
165
190
|
if (!this._hasLoaded[vouchId]) {
|
166
|
-
this._sendTrackingEvent('VOUCH_LOADED');
|
191
|
+
this._sendTrackingEvent('VOUCH_LOADED', { vouchId });
|
167
192
|
this._hasLoaded[vouchId] = true;
|
168
193
|
}
|
169
194
|
};
|
@@ -187,54 +212,60 @@ class TrackingController implements ReactiveController {
|
|
187
212
|
this._answersViewed[key] = true;
|
188
213
|
}
|
189
214
|
|
190
|
-
this._streamStartTime[key]
|
191
|
-
|
192
|
-
};
|
193
|
-
|
194
|
-
private _handleVideoTimeUpdate = ({ detail: { id, key, node } }: CustomEvent<VideoEventDetail>) => {
|
195
|
-
// We only want to count any time that the video is actually playing
|
196
|
-
if (!this.host.paused) {
|
197
|
-
this._currentlyPlayingVideo = { id, key, node };
|
215
|
+
if (!this._streamStartTime[key]) {
|
216
|
+
this._streamStartTime[key] = node.currentTime;
|
198
217
|
this._streamLatestTime[key] = node.currentTime;
|
199
218
|
}
|
219
|
+
};
|
200
220
|
|
221
|
+
private _handleVideoTimeUpdate = ({ detail: { id, key, node } }: CustomEvent<VideoEventDetail>) => {
|
201
222
|
if (
|
202
|
-
|
223
|
+
// We only want to count any time that the video is actually playing
|
203
224
|
!this.host.paused &&
|
204
|
-
// Only
|
205
|
-
id === this.host.scene?.video?.id
|
206
|
-
// Throttle the frequency that we send streamed events while playing
|
207
|
-
this._streamLatestTime[key] - this._streamStartTime[key] > STREAMED_THROTTLE
|
225
|
+
// Only update the latest time if this event fires for the currently active video
|
226
|
+
id === this.host.scene?.video?.id
|
208
227
|
) {
|
209
|
-
this.
|
210
|
-
|
211
|
-
streamStart: this._streamStartTime[key],
|
212
|
-
streamEnd: this._streamLatestTime[key]
|
213
|
-
});
|
214
|
-
|
215
|
-
this._streamStartTime[key] = node.currentTime;
|
228
|
+
this._currentlyPlayingVideo = { id, key, node };
|
229
|
+
this._streamLatestTime[key] = node.currentTime;
|
216
230
|
}
|
217
231
|
};
|
218
232
|
|
219
233
|
private _handleVideoPause = ({ detail: { id, key } }: CustomEvent<VideoEventDetail>) => {
|
220
|
-
|
221
|
-
if (this._streamLatestTime[key] > this._streamStartTime[key]) {
|
222
|
-
// Send a video streamed event any time the video pauses then reset the streamed state
|
223
|
-
// We do this to capture the last bit of time that the video was played between the previous
|
224
|
-
// stream event and the video being paused manually or stopping because it ended
|
234
|
+
if (this._streamLatestTime[key] > this._streamStartTime[key] + MINIMUM_SEND_THRESHOLD) {
|
225
235
|
this._sendTrackingEvent('VIDEO_STREAMED', {
|
226
236
|
answerId: id,
|
227
237
|
streamStart: this._streamStartTime[key],
|
228
238
|
streamEnd: this._streamLatestTime[key]
|
229
239
|
});
|
230
240
|
}
|
231
|
-
this._currentlyPlayingVideo = null;
|
232
241
|
delete this._streamStartTime[key];
|
233
242
|
delete this._streamLatestTime[key];
|
234
243
|
};
|
235
244
|
|
245
|
+
private _pageUnloading = () => {
|
246
|
+
this._streamEnded();
|
247
|
+
// This will try to send the same stream event again so we delete the start and latest
|
248
|
+
// time in stream ended so that there is no times to send and the pause event does nothing
|
249
|
+
this.host.pause();
|
250
|
+
};
|
251
|
+
|
252
|
+
private _handleVisibilityChange = () => {
|
253
|
+
if (document.visibilityState === 'hidden') {
|
254
|
+
this._pageUnloading();
|
255
|
+
}
|
256
|
+
};
|
257
|
+
|
258
|
+
private _handlePageHide = () => {
|
259
|
+
this._pageUnloading();
|
260
|
+
};
|
261
|
+
|
236
262
|
hostConnected() {
|
237
263
|
requestAnimationFrame(() => {
|
264
|
+
if ('onvisibilitychange' in document) {
|
265
|
+
document.addEventListener('visibilitychange', this._handleVisibilityChange);
|
266
|
+
} else {
|
267
|
+
window.addEventListener('pagehide', this._handlePageHide);
|
268
|
+
}
|
238
269
|
this.host.addEventListener('vouch:loaded', this._handleVouchLoaded);
|
239
270
|
this.host.mediaPlayer?.addEventListener('play', this._handlePlay);
|
240
271
|
this.host.mediaPlayer?.addEventListener('video:play', this._handleVideoPlay);
|
@@ -244,20 +275,12 @@ class TrackingController implements ReactiveController {
|
|
244
275
|
}
|
245
276
|
|
246
277
|
hostDisconnected() {
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
// stream event and the video being paused manually or stopping because it ended
|
253
|
-
this._sendTrackingEvent('VIDEO_STREAMED', {
|
254
|
-
answerId: id,
|
255
|
-
streamStart: this._streamStartTime[key],
|
256
|
-
streamEnd: this._streamLatestTime[key]
|
257
|
-
});
|
258
|
-
}
|
278
|
+
this._streamEnded();
|
279
|
+
if ('onvisibilitychange' in document) {
|
280
|
+
document.removeEventListener('visibilitychange', this._handleVisibilityChange);
|
281
|
+
} else {
|
282
|
+
window.removeEventListener('pagehide', this._handlePageHide);
|
259
283
|
}
|
260
|
-
|
261
284
|
this.host.removeEventListener('vouch:loaded', this._handleVouchLoaded);
|
262
285
|
this.host.mediaPlayer?.removeEventListener('play', this._handlePlay);
|
263
286
|
this.host.mediaPlayer?.removeEventListener('video:play', this._handleVideoPlay);
|
@@ -3,7 +3,7 @@ import { customElement, property, state } from 'lit/decorators.js';
|
|
3
3
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
4
4
|
import { createRef, ref } from 'lit/directives/ref.js';
|
5
5
|
|
6
|
-
import type { Scene, TemplateInstance } from '@vouchfor/canvas-video';
|
6
|
+
import type { Scene, Scenes, TemplateInstance } from '@vouchfor/canvas-video';
|
7
7
|
import type { MediaPlayer, MediaPlayerProps } from '@vouchfor/media-player';
|
8
8
|
import type { Ref } from 'lit/directives/ref.js';
|
9
9
|
import type { Environment } from '~/utils/env';
|
@@ -149,6 +149,10 @@ class Embed extends LitElement {
|
|
149
149
|
return this._mediaPlayerRef.value?.scenes ?? [];
|
150
150
|
}
|
151
151
|
|
152
|
+
get sceneConfig(): Scenes | null {
|
153
|
+
return this._mediaPlayerRef.value?.sceneConfig ?? null;
|
154
|
+
}
|
155
|
+
|
152
156
|
get videoState() {
|
153
157
|
return this._mediaPlayerRef.value?.videoState;
|
154
158
|
}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|