@vouchfor/embeds 0.0.0-experiment.acfa1ff → 0.0.0-experiment.af36011
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/components/Embed/controllers/fetcher.d.ts +5 -0
- package/dist/es/components/Embed/controllers/tracking.d.ts +2 -0
- package/dist/es/components/Embed/index.d.ts +17 -16
- package/dist/es/embeds.js +976 -657
- package/dist/es/embeds.js.map +1 -1
- package/dist/es/utils/env.d.ts +5 -11
- package/dist/iife/embeds.iife.js +339 -390
- package/dist/iife/embeds.iife.js.map +1 -1
- package/package.json +6 -6
- package/src/components/Embed/Embed.stories.ts +10 -26
- package/src/components/Embed/controllers/fetcher.ts +104 -14
- package/src/components/Embed/controllers/tracking.ts +85 -47
- package/src/components/Embed/index.ts +26 -28
- package/src/utils/env.ts +18 -32
- package/dist/es/components/Embed/controllers/event-forwarder.d.ts +0 -14
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.af36011",
|
4
4
|
"license": "MIT",
|
5
5
|
"author": "Aaron Williams",
|
6
6
|
"main": "dist/es/embeds.js",
|
@@ -26,7 +26,7 @@
|
|
26
26
|
"lint:staged": "lint-staged",
|
27
27
|
"prepublishOnly": "yarn build",
|
28
28
|
"size": "size-limit",
|
29
|
-
"storybook": "yarn prebuild && storybook dev -p
|
29
|
+
"storybook": "yarn prebuild && storybook dev -p 6007",
|
30
30
|
"prebuild": "yarn build:deps && yarn generate:manifest",
|
31
31
|
"test": "true"
|
32
32
|
},
|
@@ -35,12 +35,12 @@
|
|
35
35
|
"**/*.{md,json,yml}": "prettier --write"
|
36
36
|
},
|
37
37
|
"dependencies": {
|
38
|
-
"@lit/task": "1.0.0",
|
39
|
-
"@vouchfor/media-player": "0.0.0-experiment.
|
38
|
+
"@lit/task": "^1.0.0",
|
39
|
+
"@vouchfor/media-player": "0.0.0-experiment.af36011",
|
40
40
|
"uuid": "^9.0.1"
|
41
41
|
},
|
42
42
|
"peerDependencies": {
|
43
|
-
"lit": "^3.0
|
43
|
+
"lit": "^3.1.0"
|
44
44
|
},
|
45
45
|
"devDependencies": {
|
46
46
|
"@esm-bundle/chai": "^4.3.4-fix.0",
|
@@ -62,7 +62,7 @@
|
|
62
62
|
"eslint": "^8.50.0",
|
63
63
|
"eslint-plugin-import": "^2.28.1",
|
64
64
|
"lint-staged": "^14.0.1",
|
65
|
-
"lit": "^
|
65
|
+
"lit": "^3.1.0",
|
66
66
|
"prettier": "^3.0.3",
|
67
67
|
"react": "^18.2.0",
|
68
68
|
"react-dom": "^18.2.0",
|
@@ -10,32 +10,18 @@ type EmbedArgs = EmbedProps & {
|
|
10
10
|
showVouch?: boolean;
|
11
11
|
};
|
12
12
|
|
13
|
-
const _Embed = ({
|
14
|
-
vouchHashId,
|
15
|
-
preload,
|
16
|
-
autoplay,
|
17
|
-
env,
|
18
|
-
apiKey,
|
19
|
-
controls,
|
20
|
-
enableTracking,
|
21
|
-
trackingSource,
|
22
|
-
|
23
|
-
resolution,
|
24
|
-
aspectRatio
|
25
|
-
}: EmbedArgs) => {
|
13
|
+
const _Embed = ({ vouchId, templateId, preload, autoplay, env, apiKey, controls, aspectRatio }: EmbedArgs) => {
|
26
14
|
return html`
|
27
15
|
<div style="height: 100vh">
|
28
16
|
<vouch-embed
|
29
17
|
env=${ifDefined(env)}
|
30
18
|
apiKey=${ifDefined(apiKey)}
|
19
|
+
vouchId=${ifDefined(vouchId)}
|
20
|
+
templateId=${ifDefined(templateId)}
|
21
|
+
.controls=${controls}
|
31
22
|
?autoplay=${autoplay}
|
32
|
-
?enableTracking=${enableTracking}
|
33
|
-
vouchHashId=${ifDefined(vouchHashId)}
|
34
|
-
resolution=${ifDefined(resolution)}
|
35
|
-
aspectRatio=${ifDefined(aspectRatio)}
|
36
23
|
preload=${ifDefined(preload)}
|
37
|
-
|
38
|
-
trackingSource=${ifDefined(trackingSource)}
|
24
|
+
aspectRatio=${ifDefined(aspectRatio)}
|
39
25
|
></vouch-embed>
|
40
26
|
</div>
|
41
27
|
`;
|
@@ -53,20 +39,18 @@ type Story = StoryObj<EmbedArgs>;
|
|
53
39
|
|
54
40
|
const Embed: Story = {
|
55
41
|
args: {
|
56
|
-
env: '
|
42
|
+
env: 'local',
|
57
43
|
apiKey: 'TVik9uTMgE-PD25UTHIS6gyl0hMBWC7AT4dkpdlLBT4VIfDWZJrQiCk6Ak7m1',
|
58
|
-
|
59
|
-
|
44
|
+
vouchId: '6JQEIPeStt',
|
45
|
+
templateId: '357fc118-e179-4171-9446-ff2b8e9d1b29',
|
60
46
|
aspectRatio: 0,
|
61
47
|
preload: 'none',
|
62
|
-
autoplay: false
|
63
|
-
enableTracking: true,
|
64
|
-
trackingSource: 'media_player_storybook'
|
48
|
+
autoplay: false
|
65
49
|
},
|
66
50
|
argTypes: {
|
67
51
|
env: {
|
68
52
|
control: 'radio',
|
69
|
-
options: ['
|
53
|
+
options: ['local', 'dev', 'staging', 'prod']
|
70
54
|
},
|
71
55
|
preload: {
|
72
56
|
control: 'radio',
|
@@ -1,41 +1,131 @@
|
|
1
1
|
import { Task } from '@lit/task';
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
2
3
|
|
3
4
|
import type { Embed, EmbedProps } from '..';
|
4
5
|
import type { ReactiveControllerHost } from 'lit';
|
6
|
+
import type { Environment } from '~/utils/env';
|
5
7
|
|
6
8
|
import { getEnvUrls } from '~/utils/env';
|
7
9
|
|
8
10
|
type EmbedHost = ReactiveControllerHost & Embed;
|
9
11
|
|
10
|
-
type TaskDeps = [
|
12
|
+
type TaskDeps = [
|
13
|
+
EmbedProps['env'],
|
14
|
+
EmbedProps['apiKey'],
|
15
|
+
EmbedProps['data'],
|
16
|
+
EmbedProps['vouchId'],
|
17
|
+
EmbedProps['templateId']
|
18
|
+
];
|
11
19
|
|
12
20
|
class FetcherController {
|
13
21
|
host: EmbedHost;
|
14
22
|
|
23
|
+
private _fetching = false;
|
24
|
+
|
25
|
+
set fetching(value) {
|
26
|
+
if (this._fetching !== value) {
|
27
|
+
this._fetching = value;
|
28
|
+
this.host.requestUpdate();
|
29
|
+
}
|
30
|
+
}
|
31
|
+
get fetching() {
|
32
|
+
return this._fetching;
|
33
|
+
}
|
34
|
+
|
35
|
+
private getVouch = async (env: Environment, apiKey: string, vouchId: string) => {
|
36
|
+
const { embedApiUrl } = getEnvUrls(env);
|
37
|
+
|
38
|
+
const cacheCheck = uuidv4();
|
39
|
+
const res = await fetch(`${embedApiUrl}/vouches/${vouchId}`, {
|
40
|
+
method: 'GET',
|
41
|
+
headers: [
|
42
|
+
['X-Api-Key', apiKey],
|
43
|
+
['X-Cache-Check', cacheCheck]
|
44
|
+
]
|
45
|
+
});
|
46
|
+
|
47
|
+
const vouch = await res.json();
|
48
|
+
this.host.dispatchEvent(new CustomEvent('vouch:loaded', { detail: vouchId }));
|
49
|
+
|
50
|
+
// HACK: we're currently using API Gateway caching on the embed API without any invalidation logic,
|
51
|
+
// so to ensure that the cache stays up to date, whenever we detect a cache hit we trigger another
|
52
|
+
// API call with the `Cache-Control` header which will re-fill the cache
|
53
|
+
const resCacheCheck = res?.headers?.get('X-Cache-Check');
|
54
|
+
if (resCacheCheck && resCacheCheck !== cacheCheck) {
|
55
|
+
fetch(`${embedApiUrl}/vouches/${vouchId}`, {
|
56
|
+
method: 'GET',
|
57
|
+
headers: [
|
58
|
+
['X-Api-Key', apiKey],
|
59
|
+
['Cache-Control', 'max-age=0']
|
60
|
+
]
|
61
|
+
});
|
62
|
+
}
|
63
|
+
|
64
|
+
return vouch;
|
65
|
+
};
|
66
|
+
|
67
|
+
private getTemplate = async (env: Environment, apiKey: string, templateId: string) => {
|
68
|
+
const { embedApiUrl } = getEnvUrls(env);
|
69
|
+
|
70
|
+
const cacheCheck = uuidv4();
|
71
|
+
const res = await fetch(`${embedApiUrl}/templates/${templateId}`, {
|
72
|
+
method: 'GET',
|
73
|
+
headers: [
|
74
|
+
['X-Api-Key', apiKey],
|
75
|
+
['X-Cache-Check', cacheCheck]
|
76
|
+
]
|
77
|
+
});
|
78
|
+
const template = await res.json();
|
79
|
+
|
80
|
+
// HACK: we're currently using API Gateway caching on the embed API without any invalidation logic,
|
81
|
+
// so to ensure that the cache stays up to date, whenever we detect a cache hit we trigger another
|
82
|
+
// API call with the `Cache-Control` header which will re-fill the cache
|
83
|
+
const resCacheCheck = res?.headers?.get('X-Cache-Check');
|
84
|
+
if (resCacheCheck && resCacheCheck !== cacheCheck) {
|
85
|
+
fetch(`${embedApiUrl}/templates/${templateId}`, {
|
86
|
+
method: 'GET',
|
87
|
+
headers: [
|
88
|
+
['X-Api-Key', apiKey],
|
89
|
+
['Cache-Control', 'max-age=0']
|
90
|
+
]
|
91
|
+
});
|
92
|
+
}
|
93
|
+
|
94
|
+
return template;
|
95
|
+
};
|
96
|
+
|
15
97
|
constructor(host: EmbedHost) {
|
16
98
|
this.host = host;
|
17
99
|
new Task<TaskDeps, void>(
|
18
100
|
this.host,
|
19
|
-
async ([env, apiKey,
|
101
|
+
async ([env, apiKey, data, vouchId, templateId]: TaskDeps) => {
|
20
102
|
try {
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
const { embedApiUrl } = getEnvUrls(env);
|
103
|
+
host.vouch = undefined;
|
104
|
+
host.template = undefined;
|
25
105
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
106
|
+
if (data) {
|
107
|
+
let template;
|
108
|
+
if (templateId) {
|
109
|
+
this.fetching = true;
|
110
|
+
template = await this.getTemplate(env, apiKey, templateId);
|
111
|
+
}
|
112
|
+
host.vouch = data;
|
113
|
+
host.template = template ?? data?.settings?.template?.instance;
|
114
|
+
} else if (vouchId) {
|
115
|
+
this.fetching = true;
|
30
116
|
|
31
|
-
|
32
|
-
|
117
|
+
const [vouch, template] = await Promise.all([
|
118
|
+
this.getVouch(env, apiKey, vouchId),
|
119
|
+
templateId ? this.getTemplate(env, apiKey, templateId) : null
|
120
|
+
]);
|
121
|
+
host.vouch = vouch;
|
122
|
+
host.template = template ?? vouch?.settings?.template?.instance;
|
33
123
|
}
|
34
124
|
} finally {
|
35
|
-
|
125
|
+
this.fetching = false;
|
36
126
|
}
|
37
127
|
},
|
38
|
-
() => [host.env, host.apiKey, host.
|
128
|
+
() => [host.env, host.apiKey, host.data, host.vouchId, host.templateId]
|
39
129
|
);
|
40
130
|
}
|
41
131
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/* eslint-disable max-lines */
|
1
2
|
import { v4 as uuidv4 } from 'uuid';
|
2
3
|
|
3
4
|
import type { Embed } from '..';
|
@@ -6,7 +7,7 @@ import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
6
7
|
|
7
8
|
import { getEnvUrls } from '~/utils/env';
|
8
9
|
|
9
|
-
const STREAMED_THROTTLE =
|
10
|
+
const STREAMED_THROTTLE = 10000;
|
10
11
|
|
11
12
|
type EmbedHost = ReactiveControllerHost & Embed;
|
12
13
|
|
@@ -37,6 +38,7 @@ class TrackingController implements ReactiveController {
|
|
37
38
|
private _hasLoaded: BooleanMap = {};
|
38
39
|
private _answersViewed: BooleanMap = {};
|
39
40
|
private _streamedTime: TimeMap = {};
|
41
|
+
private _streamLatestTime: TimeMap = {};
|
40
42
|
private _streamedPrevTimestamp: TimeMap = {};
|
41
43
|
|
42
44
|
constructor(host: EmbedHost) {
|
@@ -45,11 +47,11 @@ class TrackingController implements ReactiveController {
|
|
45
47
|
}
|
46
48
|
|
47
49
|
private _findVouchId() {
|
48
|
-
if (this.host.
|
49
|
-
if ('uuid' in this.host.
|
50
|
-
return this.host.
|
50
|
+
if (this.host.vouch) {
|
51
|
+
if ('uuid' in this.host.vouch) {
|
52
|
+
return this.host.vouch.uuid;
|
51
53
|
}
|
52
|
-
return this.host.
|
54
|
+
return this.host.vouch.id;
|
53
55
|
}
|
54
56
|
}
|
55
57
|
|
@@ -116,7 +118,6 @@ class TrackingController implements ReactiveController {
|
|
116
118
|
});
|
117
119
|
|
118
120
|
return {
|
119
|
-
// Source might be embeds, could be playlink etc.
|
120
121
|
source: this.host.trackingSource,
|
121
122
|
time: new Date(),
|
122
123
|
region,
|
@@ -133,23 +134,24 @@ class TrackingController implements ReactiveController {
|
|
133
134
|
const { publicApiUrl } = getEnvUrls(this.host.env);
|
134
135
|
const { client, tab, request, visitor } = this._getUids();
|
135
136
|
|
136
|
-
|
137
|
-
|
138
|
-
navigator.sendBeacon(
|
139
|
-
`${publicApiUrl}/api/events`,
|
140
|
-
JSON.stringify({
|
141
|
-
event,
|
142
|
-
payload,
|
143
|
-
context: {
|
144
|
-
'x-uid-client': client,
|
145
|
-
'x-uid-tab': tab,
|
146
|
-
'x-uid-request': request,
|
147
|
-
'x-uid-visitor': visitor,
|
148
|
-
'x-reporting-metadata': this._getReportingMetadata()
|
149
|
-
}
|
150
|
-
})
|
151
|
-
);
|
137
|
+
if (this.host.disableTracking) {
|
138
|
+
return;
|
152
139
|
}
|
140
|
+
|
141
|
+
navigator.sendBeacon(
|
142
|
+
`${publicApiUrl}/api/events`,
|
143
|
+
JSON.stringify({
|
144
|
+
event,
|
145
|
+
payload,
|
146
|
+
context: {
|
147
|
+
'x-uid-client': client,
|
148
|
+
'x-uid-tab': tab,
|
149
|
+
'x-uid-request': request,
|
150
|
+
'x-uid-visitor': visitor,
|
151
|
+
'x-reporting-metadata': this._getReportingMetadata()
|
152
|
+
}
|
153
|
+
})
|
154
|
+
);
|
153
155
|
};
|
154
156
|
|
155
157
|
private _handleVouchLoaded = ({ detail: vouchId }: CustomEvent<string>) => {
|
@@ -185,9 +187,11 @@ class TrackingController implements ReactiveController {
|
|
185
187
|
|
186
188
|
private _handleVideoPlay = ({ detail: { id, node } }: CustomEvent<VideoEventDetail>) => {
|
187
189
|
const vouchId = this._findVouchId();
|
190
|
+
|
188
191
|
if (!vouchId) {
|
189
192
|
return;
|
190
193
|
}
|
194
|
+
|
191
195
|
// Only increment play count once per session
|
192
196
|
if (!this._answersViewed[id]) {
|
193
197
|
this._sendTrackingEvent('VOUCH_RESPONSE_VIEWED', {
|
@@ -196,17 +200,44 @@ class TrackingController implements ReactiveController {
|
|
196
200
|
});
|
197
201
|
this._answersViewed[id] = true;
|
198
202
|
}
|
203
|
+
|
199
204
|
this._streamedTime[id] = node.currentTime;
|
205
|
+
this._streamLatestTime[id] = node.currentTime;
|
200
206
|
this._streamedPrevTimestamp[id] = Date.now();
|
201
207
|
};
|
202
208
|
|
209
|
+
private _handleVideoSeeking = ({ detail: { id } }: CustomEvent<VideoEventDetail>) => {
|
210
|
+
const vouchId = this._findVouchId();
|
211
|
+
|
212
|
+
if (!vouchId) {
|
213
|
+
return;
|
214
|
+
}
|
215
|
+
|
216
|
+
if (this._streamLatestTime[id]) {
|
217
|
+
this._sendTrackingEvent('VIDEO_STREAMED', {
|
218
|
+
vouchId,
|
219
|
+
answerId: id,
|
220
|
+
streamStart: this._streamedTime[id],
|
221
|
+
streamEnd: this._streamLatestTime[id]
|
222
|
+
});
|
223
|
+
}
|
224
|
+
|
225
|
+
delete this._streamedTime[id];
|
226
|
+
delete this._streamLatestTime[id];
|
227
|
+
delete this._streamedPrevTimestamp[id];
|
228
|
+
};
|
229
|
+
|
203
230
|
private _handleVideoTimeUpdate = ({ detail: { id, node } }: CustomEvent<VideoEventDetail>) => {
|
204
231
|
const vouchId = this._findVouchId();
|
232
|
+
|
205
233
|
if (!vouchId) {
|
206
234
|
return;
|
207
235
|
}
|
236
|
+
|
208
237
|
const currentTimestamp = Date.now();
|
209
238
|
if (
|
239
|
+
node.currentTime &&
|
240
|
+
!node.paused &&
|
210
241
|
!this.host.paused &&
|
211
242
|
// Only fire the video seeked event when this video is the active one
|
212
243
|
id === this.host.scene?.video?.id &&
|
@@ -222,46 +253,53 @@ class TrackingController implements ReactiveController {
|
|
222
253
|
this._streamedTime[id] = node.currentTime;
|
223
254
|
this._streamedPrevTimestamp[id] = currentTimestamp;
|
224
255
|
}
|
256
|
+
|
257
|
+
this._streamLatestTime[id] = node.currentTime;
|
225
258
|
};
|
226
259
|
|
227
260
|
private _handleVideoPause = ({ detail: { id, node } }: CustomEvent<VideoEventDetail>) => {
|
228
261
|
const vouchId = this._findVouchId();
|
262
|
+
|
229
263
|
if (!vouchId) {
|
230
264
|
return;
|
231
265
|
}
|
232
|
-
|
233
|
-
//
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
266
|
+
|
267
|
+
// Don't send a tracking event if the video pauses when seeking backwards
|
268
|
+
if (node.currentTime > this._streamedTime[id]) {
|
269
|
+
// Send a video streamed event any time the video pauses then reset the streamed state
|
270
|
+
// We do this to capture the last bit of time that the video was played between the previous
|
271
|
+
// stream event and the video being paused manually or stopping because it ended
|
272
|
+
this._sendTrackingEvent('VIDEO_STREAMED', {
|
273
|
+
vouchId,
|
274
|
+
answerId: id,
|
275
|
+
streamStart: this._streamedTime[id],
|
276
|
+
streamEnd: node.currentTime
|
277
|
+
});
|
278
|
+
}
|
279
|
+
|
241
280
|
delete this._streamedTime[id];
|
281
|
+
delete this._streamLatestTime[id];
|
242
282
|
delete this._streamedPrevTimestamp[id];
|
243
283
|
};
|
244
284
|
|
245
285
|
hostConnected() {
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
}
|
286
|
+
requestAnimationFrame(() => {
|
287
|
+
this.host.addEventListener('vouch:loaded', this._handleVouchLoaded);
|
288
|
+
this.host.mediaPlayer?.addEventListener('play', this._handlePlay);
|
289
|
+
this.host.mediaPlayer?.addEventListener('video:play', this._handleVideoPlay);
|
290
|
+
this.host.mediaPlayer?.addEventListener('video:seeking', this._handleVideoSeeking);
|
291
|
+
this.host.mediaPlayer?.addEventListener('video:pause', this._handleVideoPause);
|
292
|
+
this.host.mediaPlayer?.addEventListener('video:timeupdate', this._handleVideoTimeUpdate);
|
293
|
+
});
|
255
294
|
}
|
256
295
|
|
257
296
|
hostDisconnected() {
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
}
|
297
|
+
this.host.removeEventListener('vouch:loaded', this._handleVouchLoaded);
|
298
|
+
this.host.mediaPlayer?.removeEventListener('play', this._handlePlay);
|
299
|
+
this.host.mediaPlayer?.removeEventListener('video:play', this._handleVideoPlay);
|
300
|
+
this.host.mediaPlayer?.removeEventListener('video:seeking', this._handleVideoSeeking);
|
301
|
+
this.host.mediaPlayer?.removeEventListener('video:pause', this._handleVideoPause);
|
302
|
+
this.host.mediaPlayer?.removeEventListener('video:timeupdate', this._handleVideoTimeUpdate);
|
265
303
|
}
|
266
304
|
}
|
267
305
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { html, LitElement } from 'lit';
|
2
|
-
import { customElement,
|
2
|
+
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 } from '@vouchfor/canvas-video';
|
6
|
+
import type { Scene, 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';
|
@@ -14,39 +14,32 @@ import { TrackingController } from './controllers/tracking';
|
|
14
14
|
|
15
15
|
import '@vouchfor/media-player';
|
16
16
|
|
17
|
-
type EmbedProps = Pick<
|
18
|
-
MediaPlayerProps,
|
19
|
-
'data' | 'resolution' | 'aspectRatio' | 'preload' | 'autoplay' | 'controls'
|
20
|
-
> & {
|
17
|
+
type EmbedProps = Pick<MediaPlayerProps, 'data' | 'aspectRatio' | 'preload' | 'autoplay' | 'controls'> & {
|
21
18
|
env: Environment;
|
22
19
|
apiKey: string;
|
23
|
-
|
24
|
-
enableTracking?: boolean;
|
20
|
+
disableTracking?: boolean;
|
25
21
|
trackingSource?: string;
|
22
|
+
vouchId?: string;
|
23
|
+
templateId?: string;
|
26
24
|
};
|
27
25
|
|
28
26
|
@customElement('vouch-embed')
|
29
27
|
class Embed extends LitElement {
|
30
28
|
private _mediaPlayerRef: Ref<MediaPlayer> = createRef();
|
31
29
|
|
32
|
-
@property({ type: Object, attribute: 'data' })
|
33
|
-
@property({ type: String })
|
30
|
+
@property({ type: Object, attribute: 'data' }) data: EmbedProps['data'];
|
31
|
+
@property({ type: String }) vouchId: EmbedProps['vouchId'];
|
32
|
+
@property({ type: String }) templateId: EmbedProps['templateId'];
|
34
33
|
|
35
34
|
@property({ type: String }) env: EmbedProps['env'] = 'prod';
|
36
35
|
@property({ type: String }) apiKey: EmbedProps['apiKey'] = '';
|
36
|
+
@property({ type: Boolean }) disableTracking: EmbedProps['disableTracking'] = false;
|
37
|
+
@property({ type: String }) trackingSource: EmbedProps['trackingSource'] = 'embed';
|
37
38
|
|
39
|
+
@property({ type: Array }) controls: EmbedProps['controls'];
|
38
40
|
@property({ type: String }) preload: EmbedProps['preload'] = 'auto';
|
39
41
|
@property({ type: Boolean }) autoplay: EmbedProps['autoplay'] = false;
|
40
|
-
@property({ type: Boolean }) enableTracking: EmbedProps['enableTracking'] = false;
|
41
|
-
@property({ type: String }) trackingSource: EmbedProps['trackingSource'] = 'media_player';
|
42
|
-
|
43
|
-
@property({ type: Number }) resolution: EmbedProps['resolution'] = 1080;
|
44
42
|
@property({ type: Number }) aspectRatio: EmbedProps['aspectRatio'] = 0;
|
45
|
-
@property({ type: Array }) controls: EmbedProps['controls'];
|
46
|
-
|
47
|
-
@state() data: MediaPlayerProps['data'];
|
48
|
-
@state() instance: MediaPlayerProps['instance'];
|
49
|
-
@state() fetching = false;
|
50
43
|
|
51
44
|
private eventController = new EventForwardController(this, [
|
52
45
|
'durationchange',
|
@@ -66,6 +59,7 @@ class Embed extends LitElement {
|
|
66
59
|
'waiting',
|
67
60
|
|
68
61
|
'video:loadeddata',
|
62
|
+
'video:seeking',
|
69
63
|
'video:seeked',
|
70
64
|
'video:play',
|
71
65
|
'video:playing',
|
@@ -75,12 +69,17 @@ class Embed extends LitElement {
|
|
75
69
|
'video:ended',
|
76
70
|
'video:error'
|
77
71
|
]);
|
72
|
+
private _fetcherController = new FetcherController(this);
|
78
73
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
79
74
|
// @ts-ignore
|
80
|
-
private
|
81
|
-
|
82
|
-
|
83
|
-
|
75
|
+
private _trackingController = new TrackingController(this);
|
76
|
+
|
77
|
+
@state() vouch: EmbedProps['data'];
|
78
|
+
@state() template: TemplateInstance | undefined;
|
79
|
+
|
80
|
+
get fetching() {
|
81
|
+
return this._fetcherController.fetching;
|
82
|
+
}
|
84
83
|
|
85
84
|
get waiting() {
|
86
85
|
return this._mediaPlayerRef.value?.waiting;
|
@@ -172,18 +171,17 @@ class Embed extends LitElement {
|
|
172
171
|
|
173
172
|
render() {
|
174
173
|
return html`
|
175
|
-
<vmp-media-player
|
174
|
+
<vmp-new-media-player
|
176
175
|
${ref(this._mediaPlayerRef)}
|
177
176
|
${this.eventController.register()}
|
178
177
|
?autoplay=${this.autoplay}
|
179
178
|
?loading=${this.fetching}
|
180
|
-
.data=${this.
|
181
|
-
.
|
182
|
-
resolution=${ifDefined(this.resolution)}
|
179
|
+
.data=${this.vouch}
|
180
|
+
.template=${this.template}
|
183
181
|
aspectRatio=${ifDefined(this.aspectRatio)}
|
184
182
|
preload=${ifDefined(this.preload)}
|
185
183
|
.controls=${this.controls}
|
186
|
-
></vmp-media-player>
|
184
|
+
></vmp-new-media-player>
|
187
185
|
`;
|
188
186
|
}
|
189
187
|
}
|
package/src/utils/env.ts
CHANGED
@@ -1,15 +1,11 @@
|
|
1
|
-
type Environment = 'dev' | 'staging' | 'prod';
|
1
|
+
type Environment = 'local' | 'dev' | 'staging' | 'prod';
|
2
2
|
|
3
3
|
type GetEnvUrlsReturn = {
|
4
|
-
marketingUrl: string;
|
5
4
|
videoUrl: string;
|
6
5
|
publicApiUrl: string;
|
7
6
|
embedApiUrl: string;
|
8
|
-
publicRecorderUrl: string;
|
9
7
|
};
|
10
8
|
|
11
|
-
const marketingUrl = 'https://vouchfor.com';
|
12
|
-
|
13
9
|
const devVideoUrl = 'https://d2rxhdlm2q91uk.cloudfront.net';
|
14
10
|
const stagingVideoUrl = 'https://d1ix11aj5kfygl.cloudfront.net';
|
15
11
|
const prodVideoUrl = 'https://d157jlwnudd93d.cloudfront.net';
|
@@ -18,61 +14,51 @@ const devPublicApiUrl = 'https://bshyfw4h5a.execute-api.ap-southeast-2.amazonaws
|
|
18
14
|
const stagingPublicApiUrl = 'https://gyzw7rpbq3.execute-api.ap-southeast-2.amazonaws.com/staging';
|
19
15
|
const prodPublicApiUrl = 'https://vfcjuim1l3.execute-api.ap-southeast-2.amazonaws.com/prod';
|
20
16
|
|
21
|
-
const
|
22
|
-
const
|
23
|
-
const
|
24
|
-
|
25
|
-
const devPublicRecorderUrl = 'https://dev.vouchfor.com';
|
26
|
-
const stagingPublicRecorderUrl = 'https://staging.vouchfor.com';
|
27
|
-
const prodPublicRecorderUrl = 'https://app.vouchfor.com';
|
17
|
+
const localEmbedApiUrl = 'http://localhost:6060/v2';
|
18
|
+
const devEmbedApiUrl = 'https://embed-dev.vouchfor.com/v2';
|
19
|
+
const stagingEmbedApiUrl = 'https://embed-staging.vouchfor.com/v2';
|
20
|
+
const prodEmbedApiUrl = 'https://embed.vouchfor.com/v2';
|
28
21
|
|
29
22
|
// We are handling the case where env is an unknown string so the ts error is a lie
|
30
23
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
31
24
|
// @ts-ignore
|
32
25
|
function getEnvUrls(env: Environment): GetEnvUrlsReturn {
|
33
|
-
if (!['dev', 'staging', 'prod'].includes(env)) {
|
26
|
+
if (!['local', 'dev', 'staging', 'prod'].includes(env)) {
|
34
27
|
throw new Error(`Unknown environment: ${env}`);
|
35
28
|
}
|
36
29
|
|
30
|
+
if (env === 'local') {
|
31
|
+
return {
|
32
|
+
videoUrl: devVideoUrl,
|
33
|
+
publicApiUrl: devPublicApiUrl,
|
34
|
+
embedApiUrl: localEmbedApiUrl
|
35
|
+
};
|
36
|
+
}
|
37
|
+
|
37
38
|
if (env === 'dev') {
|
38
39
|
return {
|
39
|
-
marketingUrl,
|
40
40
|
videoUrl: devVideoUrl,
|
41
41
|
publicApiUrl: devPublicApiUrl,
|
42
|
-
embedApiUrl: devEmbedApiUrl
|
43
|
-
publicRecorderUrl: devPublicRecorderUrl
|
42
|
+
embedApiUrl: devEmbedApiUrl
|
44
43
|
};
|
45
44
|
}
|
46
45
|
|
47
46
|
if (env === 'staging') {
|
48
47
|
return {
|
49
|
-
marketingUrl,
|
50
48
|
videoUrl: stagingVideoUrl,
|
51
49
|
publicApiUrl: stagingPublicApiUrl,
|
52
|
-
embedApiUrl: stagingEmbedApiUrl
|
53
|
-
publicRecorderUrl: stagingPublicRecorderUrl
|
50
|
+
embedApiUrl: stagingEmbedApiUrl
|
54
51
|
};
|
55
52
|
}
|
56
53
|
|
57
54
|
if (env === 'prod') {
|
58
55
|
return {
|
59
|
-
marketingUrl,
|
60
56
|
videoUrl: prodVideoUrl,
|
61
57
|
publicApiUrl: prodPublicApiUrl,
|
62
|
-
embedApiUrl: prodEmbedApiUrl
|
63
|
-
publicRecorderUrl: prodPublicRecorderUrl
|
58
|
+
embedApiUrl: prodEmbedApiUrl
|
64
59
|
};
|
65
60
|
}
|
66
61
|
}
|
67
62
|
|
68
|
-
export {
|
69
|
-
marketingUrl,
|
70
|
-
devEmbedApiUrl,
|
71
|
-
stagingEmbedApiUrl,
|
72
|
-
prodEmbedApiUrl,
|
73
|
-
devPublicRecorderUrl,
|
74
|
-
stagingPublicRecorderUrl,
|
75
|
-
prodPublicRecorderUrl,
|
76
|
-
getEnvUrls
|
77
|
-
};
|
63
|
+
export { devEmbedApiUrl, stagingEmbedApiUrl, prodEmbedApiUrl, getEnvUrls };
|
78
64
|
export type { Environment };
|