vastlint-react 0.4.20
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/README.md +14 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +431 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.js +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# vastlint-react
|
|
2
|
+
|
|
3
|
+
Headless React bindings for `vastlint-client`.
|
|
4
|
+
|
|
5
|
+
Current status:
|
|
6
|
+
|
|
7
|
+
- `useVastSession` is implemented as a thin hook over `vastlint-client` session instances.
|
|
8
|
+
- The hook subscribes to session snapshots, supports auto-load and auto-validate, and exposes tracking-aware session state.
|
|
9
|
+
- `useVastAnnotations` is implemented as a derived annotation model over `ValidationResult`, grouped by line and issue ID.
|
|
10
|
+
- `useVastPlayback` is implemented as a thin hook over `createVastPlaybackController()`, with subscribed playback snapshots, optional auto-initialize behavior, and bound playback lifecycle methods.
|
|
11
|
+
- `useVastPlaybackQueue` is implemented as a thin hook over `createVastPlaybackQueueController()`, with subscribed queue snapshots, optional auto-initialize behavior, and bound queue lifecycle methods.
|
|
12
|
+
- Build-first Node smoke tests now cover `useVastSession`, `useVastAnnotations`, `useVastTracker`, `useVastPlayback`, and `useVastPlaybackQueue` against built package output via a `jsdom` plus `react-dom/client` harness.
|
|
13
|
+
- `useVastTracker` is implemented as a thin hook over session tracking state and dispatch methods, including pod-aware `trackAd()` plus companion helpers for `getAdCompanions()`, `getCompanionTargets()`, and `trackCompanion()`.
|
|
14
|
+
- The package will stay renderer-agnostic and return data models rather than opinionated UI.
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { UseVastAnnotationsOptions, UseVastPlaybackOptions, UseVastPlaybackQueueOptions, UseVastSessionOptions, UseVastTrackerOptions, VastAnnotationModel, VastPlaybackHookResult, VastPlaybackQueueHookResult, VastSessionHookResult, VastTrackerHookResult } from "./types.js";
|
|
2
|
+
export declare function useVastSession(options: UseVastSessionOptions): VastSessionHookResult;
|
|
3
|
+
export declare function useVastAnnotations(_options: UseVastAnnotationsOptions): VastAnnotationModel;
|
|
4
|
+
export declare function useVastPlayback(options: UseVastPlaybackOptions): VastPlaybackHookResult;
|
|
5
|
+
export declare function useVastPlaybackQueue(options: UseVastPlaybackQueueOptions): VastPlaybackQueueHookResult;
|
|
6
|
+
export declare function useVastTracker(options: UseVastTrackerOptions): VastTrackerHookResult;
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { startTransition, useDeferredValue, useEffect, useMemo, useReducer, useRef } from "react";
|
|
2
|
+
import { createVastPlaybackController, createVastPlaybackQueueController, createVastSession, selectTrackingTargets } from "vastlint-client";
|
|
3
|
+
function useSubscribedSnapshot(store) {
|
|
4
|
+
const [, forceRender] = useReducer((value) => value + 1, 0);
|
|
5
|
+
const storeRef = useRef(store);
|
|
6
|
+
const snapshotRef = useRef(store.getSnapshot());
|
|
7
|
+
if (!Object.is(storeRef.current, store)) {
|
|
8
|
+
storeRef.current = store;
|
|
9
|
+
snapshotRef.current = store.getSnapshot();
|
|
10
|
+
}
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
snapshotRef.current = store.getSnapshot();
|
|
13
|
+
let isSynchronousSubscription = true;
|
|
14
|
+
const unsubscribe = store.subscribe((nextSnapshot) => {
|
|
15
|
+
if (isSynchronousSubscription) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
snapshotRef.current = nextSnapshot;
|
|
19
|
+
forceRender();
|
|
20
|
+
});
|
|
21
|
+
isSynchronousSubscription = false;
|
|
22
|
+
return unsubscribe;
|
|
23
|
+
}, [store]);
|
|
24
|
+
return snapshotRef.current;
|
|
25
|
+
}
|
|
26
|
+
function createEmptyAnnotationModel() {
|
|
27
|
+
return {
|
|
28
|
+
annotations: [],
|
|
29
|
+
byLine: new Map(),
|
|
30
|
+
byIssueId: new Map(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function countXmlLines(xml) {
|
|
34
|
+
if (!xml) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
return xml.split(/\r\n?|\n/).length;
|
|
38
|
+
}
|
|
39
|
+
function buildVastAnnotationModel(xml, validation) {
|
|
40
|
+
if (!validation || validation.issues.length === 0) {
|
|
41
|
+
return createEmptyAnnotationModel();
|
|
42
|
+
}
|
|
43
|
+
const maxLine = countXmlLines(xml);
|
|
44
|
+
const annotations = validation.issues.map((issue, index) => {
|
|
45
|
+
const line = issue.line !== null && issue.line >= 1 && issue.line <= maxLine ? issue.line : null;
|
|
46
|
+
const col = line === null ? null : issue.col;
|
|
47
|
+
return {
|
|
48
|
+
id: `${issue.id}:${issue.path ?? "document"}:${line ?? 0}:${col ?? 0}:${index}`,
|
|
49
|
+
issueId: issue.id,
|
|
50
|
+
severity: issue.severity,
|
|
51
|
+
message: issue.message,
|
|
52
|
+
path: issue.path,
|
|
53
|
+
line,
|
|
54
|
+
col,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
const byLine = new Map();
|
|
58
|
+
const byIssueId = new Map();
|
|
59
|
+
for (const annotation of annotations) {
|
|
60
|
+
if (annotation.line !== null) {
|
|
61
|
+
const lineAnnotations = byLine.get(annotation.line) ?? [];
|
|
62
|
+
lineAnnotations.push(annotation);
|
|
63
|
+
byLine.set(annotation.line, lineAnnotations);
|
|
64
|
+
}
|
|
65
|
+
const issueAnnotations = byIssueId.get(annotation.issueId) ?? [];
|
|
66
|
+
issueAnnotations.push(annotation);
|
|
67
|
+
byIssueId.set(annotation.issueId, issueAnnotations);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
annotations,
|
|
71
|
+
byLine,
|
|
72
|
+
byIssueId,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function serializeValidateOptions(validateOptions) {
|
|
76
|
+
if (!validateOptions) {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
const sortedRuleOverrides = validateOptions.rule_overrides
|
|
80
|
+
? Object.fromEntries(Object.entries(validateOptions.rule_overrides).sort(([left], [right]) => left.localeCompare(right)))
|
|
81
|
+
: undefined;
|
|
82
|
+
return JSON.stringify({
|
|
83
|
+
wrapper_depth: validateOptions.wrapper_depth ?? null,
|
|
84
|
+
max_wrapper_depth: validateOptions.max_wrapper_depth ?? null,
|
|
85
|
+
rule_overrides: sortedRuleOverrides ?? null,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function serializeMediaSelectionOptions(mediaSelection) {
|
|
89
|
+
if (!mediaSelection) {
|
|
90
|
+
return "";
|
|
91
|
+
}
|
|
92
|
+
return JSON.stringify({
|
|
93
|
+
supportedMimeTypes: mediaSelection.supportedMimeTypes ?? null,
|
|
94
|
+
preferredMimeTypes: mediaSelection.preferredMimeTypes ?? null,
|
|
95
|
+
preferredDelivery: mediaSelection.preferredDelivery ?? null,
|
|
96
|
+
targetBitrate: mediaSelection.targetBitrate ?? null,
|
|
97
|
+
maxBitrate: mediaSelection.maxBitrate ?? null,
|
|
98
|
+
targetWidth: mediaSelection.targetWidth ?? null,
|
|
99
|
+
targetHeight: mediaSelection.targetHeight ?? null,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function createSessionConfig(options) {
|
|
103
|
+
return {
|
|
104
|
+
sourceKind: options.source.kind,
|
|
105
|
+
sourceValue: options.source.kind === "xml" ? options.source.xml : options.source.url,
|
|
106
|
+
label: options.source.label ?? null,
|
|
107
|
+
requestRef: options.source.kind === "url" ? (options.source.request ?? null) : null,
|
|
108
|
+
fetchRef: options.fetch ?? null,
|
|
109
|
+
timeoutMs: options.timeoutMs ?? null,
|
|
110
|
+
maxWrapperDepth: options.maxWrapperDepth ?? null,
|
|
111
|
+
validateOptionsKey: serializeValidateOptions(options.validateOptions),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function createPlaybackConfig(options) {
|
|
115
|
+
return {
|
|
116
|
+
sessionRef: options.session,
|
|
117
|
+
autoResolve: options.autoResolve !== false,
|
|
118
|
+
mediaSelectionKey: serializeMediaSelectionOptions(options.mediaSelection),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function createPlaybackQueueConfig(options) {
|
|
122
|
+
return {
|
|
123
|
+
sessionRef: options.session,
|
|
124
|
+
fetchRef: options.fetch ?? null,
|
|
125
|
+
autoResolve: options.autoResolve !== false,
|
|
126
|
+
mediaSelectionKey: serializeMediaSelectionOptions(options.mediaSelection),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function hasSessionConfigChanged(previous, next) {
|
|
130
|
+
return (previous.sourceKind !== next.sourceKind
|
|
131
|
+
|| previous.sourceValue !== next.sourceValue
|
|
132
|
+
|| previous.label !== next.label
|
|
133
|
+
|| !Object.is(previous.requestRef, next.requestRef)
|
|
134
|
+
|| !Object.is(previous.fetchRef, next.fetchRef)
|
|
135
|
+
|| previous.timeoutMs !== next.timeoutMs
|
|
136
|
+
|| previous.maxWrapperDepth !== next.maxWrapperDepth
|
|
137
|
+
|| previous.validateOptionsKey !== next.validateOptionsKey);
|
|
138
|
+
}
|
|
139
|
+
function hasPlaybackConfigChanged(previous, next) {
|
|
140
|
+
return (!Object.is(previous.sessionRef, next.sessionRef)
|
|
141
|
+
|| previous.autoResolve !== next.autoResolve
|
|
142
|
+
|| previous.mediaSelectionKey !== next.mediaSelectionKey);
|
|
143
|
+
}
|
|
144
|
+
function hasPlaybackQueueConfigChanged(previous, next) {
|
|
145
|
+
return (!Object.is(previous.sessionRef, next.sessionRef)
|
|
146
|
+
|| !Object.is(previous.fetchRef, next.fetchRef)
|
|
147
|
+
|| previous.autoResolve !== next.autoResolve
|
|
148
|
+
|| previous.mediaSelectionKey !== next.mediaSelectionKey);
|
|
149
|
+
}
|
|
150
|
+
async function runAutoAction(session, autoLoad, autoValidate) {
|
|
151
|
+
if (autoValidate) {
|
|
152
|
+
await session.validate();
|
|
153
|
+
return session.getSnapshot();
|
|
154
|
+
}
|
|
155
|
+
if (autoLoad) {
|
|
156
|
+
return session.load();
|
|
157
|
+
}
|
|
158
|
+
return session.getSnapshot();
|
|
159
|
+
}
|
|
160
|
+
export function useVastSession(options) {
|
|
161
|
+
const { autoLoad = true, autoValidate = false, ...sessionOptions } = options;
|
|
162
|
+
const [, forceRender] = useReducer((value) => value + 1, 0);
|
|
163
|
+
const trackedSessionRef = useRef(null);
|
|
164
|
+
const autoStartedSessionsRef = useRef(new WeakSet());
|
|
165
|
+
const sessionConfig = createSessionConfig(sessionOptions);
|
|
166
|
+
if (!trackedSessionRef.current
|
|
167
|
+
|| hasSessionConfigChanged(trackedSessionRef.current.config, sessionConfig)) {
|
|
168
|
+
trackedSessionRef.current = {
|
|
169
|
+
config: sessionConfig,
|
|
170
|
+
session: createVastSession(sessionOptions),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const getCurrentSession = () => trackedSessionRef.current.session;
|
|
174
|
+
const replaceSession = () => {
|
|
175
|
+
const nextSession = createVastSession(sessionOptions);
|
|
176
|
+
trackedSessionRef.current = {
|
|
177
|
+
config: sessionConfig,
|
|
178
|
+
session: nextSession,
|
|
179
|
+
};
|
|
180
|
+
startTransition(() => {
|
|
181
|
+
forceRender();
|
|
182
|
+
});
|
|
183
|
+
return nextSession;
|
|
184
|
+
};
|
|
185
|
+
const session = getCurrentSession();
|
|
186
|
+
const snapshot = useSubscribedSnapshot(session);
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if ((!autoLoad && !autoValidate) || autoStartedSessionsRef.current.has(session)) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
autoStartedSessionsRef.current.add(session);
|
|
192
|
+
void runAutoAction(session, autoLoad, autoValidate).catch(() => {
|
|
193
|
+
// Session state already captures errors for consumers.
|
|
194
|
+
});
|
|
195
|
+
}, [session, autoLoad, autoValidate]);
|
|
196
|
+
return {
|
|
197
|
+
session,
|
|
198
|
+
snapshot,
|
|
199
|
+
load() {
|
|
200
|
+
return getCurrentSession().load();
|
|
201
|
+
},
|
|
202
|
+
reload() {
|
|
203
|
+
const nextSession = replaceSession();
|
|
204
|
+
autoStartedSessionsRef.current.add(nextSession);
|
|
205
|
+
return runAutoAction(nextSession, true, autoValidate);
|
|
206
|
+
},
|
|
207
|
+
validate() {
|
|
208
|
+
return getCurrentSession().validate();
|
|
209
|
+
},
|
|
210
|
+
fix() {
|
|
211
|
+
return getCurrentSession().fix();
|
|
212
|
+
},
|
|
213
|
+
resolve() {
|
|
214
|
+
return getCurrentSession().resolve();
|
|
215
|
+
},
|
|
216
|
+
track(event, trackOptions) {
|
|
217
|
+
return getCurrentSession().track(event, trackOptions);
|
|
218
|
+
},
|
|
219
|
+
trackAd(adSelector, event, trackOptions) {
|
|
220
|
+
return getCurrentSession().trackAd(adSelector, event, trackOptions);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
export function useVastAnnotations(_options) {
|
|
225
|
+
const deferredXml = useDeferredValue(_options.xml);
|
|
226
|
+
const deferredValidation = useDeferredValue(_options.validation);
|
|
227
|
+
return useMemo(() => buildVastAnnotationModel(deferredXml, deferredValidation), [deferredXml, deferredValidation]);
|
|
228
|
+
}
|
|
229
|
+
export function useVastPlayback(options) {
|
|
230
|
+
const { autoInitialize = true, ...controllerOptions } = options;
|
|
231
|
+
const trackedPlaybackRef = useRef(null);
|
|
232
|
+
const autoInitializedControllersRef = useRef(new WeakSet());
|
|
233
|
+
const playbackConfig = createPlaybackConfig(controllerOptions);
|
|
234
|
+
if (!trackedPlaybackRef.current
|
|
235
|
+
|| hasPlaybackConfigChanged(trackedPlaybackRef.current.config, playbackConfig)) {
|
|
236
|
+
trackedPlaybackRef.current = {
|
|
237
|
+
config: playbackConfig,
|
|
238
|
+
controller: createVastPlaybackController(controllerOptions),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const getCurrentController = () => trackedPlaybackRef.current.controller;
|
|
242
|
+
const controller = getCurrentController();
|
|
243
|
+
const snapshot = useSubscribedSnapshot(controller);
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
return () => {
|
|
246
|
+
controller.dispose();
|
|
247
|
+
};
|
|
248
|
+
}, [controller]);
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
if (!autoInitialize || autoInitializedControllersRef.current.has(controller)) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
autoInitializedControllersRef.current.add(controller);
|
|
254
|
+
void controller.initialize().catch(() => {
|
|
255
|
+
// Controller state already captures errors for consumers.
|
|
256
|
+
});
|
|
257
|
+
}, [controller, autoInitialize]);
|
|
258
|
+
return {
|
|
259
|
+
controller,
|
|
260
|
+
snapshot,
|
|
261
|
+
initialize() {
|
|
262
|
+
return getCurrentController().initialize();
|
|
263
|
+
},
|
|
264
|
+
start() {
|
|
265
|
+
return getCurrentController().start();
|
|
266
|
+
},
|
|
267
|
+
pause() {
|
|
268
|
+
return getCurrentController().pause();
|
|
269
|
+
},
|
|
270
|
+
resume() {
|
|
271
|
+
return getCurrentController().resume();
|
|
272
|
+
},
|
|
273
|
+
updateProgress(currentTimeSec, durationSec) {
|
|
274
|
+
return getCurrentController().updateProgress(currentTimeSec, durationSec);
|
|
275
|
+
},
|
|
276
|
+
complete() {
|
|
277
|
+
return getCurrentController().complete();
|
|
278
|
+
},
|
|
279
|
+
setMuted(muted) {
|
|
280
|
+
return getCurrentController().setMuted(muted);
|
|
281
|
+
},
|
|
282
|
+
setFullscreen(fullscreen) {
|
|
283
|
+
return getCurrentController().setFullscreen(fullscreen);
|
|
284
|
+
},
|
|
285
|
+
setViewability(viewability) {
|
|
286
|
+
return getCurrentController().setViewability(viewability);
|
|
287
|
+
},
|
|
288
|
+
click(trackOptions) {
|
|
289
|
+
return getCurrentController().click(trackOptions);
|
|
290
|
+
},
|
|
291
|
+
skip() {
|
|
292
|
+
return getCurrentController().skip();
|
|
293
|
+
},
|
|
294
|
+
signalError(trackOptions) {
|
|
295
|
+
return getCurrentController().signalError(trackOptions);
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
export function useVastPlaybackQueue(options) {
|
|
300
|
+
const { autoInitialize = true, ...controllerOptions } = options;
|
|
301
|
+
const trackedPlaybackQueueRef = useRef(null);
|
|
302
|
+
const autoInitializedControllersRef = useRef(new WeakSet());
|
|
303
|
+
const playbackQueueConfig = createPlaybackQueueConfig(controllerOptions);
|
|
304
|
+
if (!trackedPlaybackQueueRef.current
|
|
305
|
+
|| hasPlaybackQueueConfigChanged(trackedPlaybackQueueRef.current.config, playbackQueueConfig)) {
|
|
306
|
+
trackedPlaybackQueueRef.current = {
|
|
307
|
+
config: playbackQueueConfig,
|
|
308
|
+
controller: createVastPlaybackQueueController(controllerOptions),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const getCurrentController = () => trackedPlaybackQueueRef.current.controller;
|
|
312
|
+
const controller = getCurrentController();
|
|
313
|
+
const snapshot = useSubscribedSnapshot(controller);
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
return () => {
|
|
316
|
+
controller.dispose();
|
|
317
|
+
};
|
|
318
|
+
}, [controller]);
|
|
319
|
+
useEffect(() => {
|
|
320
|
+
if (!autoInitialize || autoInitializedControllersRef.current.has(controller)) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
autoInitializedControllersRef.current.add(controller);
|
|
324
|
+
void controller.initialize().catch(() => {
|
|
325
|
+
// Controller state already captures errors for consumers.
|
|
326
|
+
});
|
|
327
|
+
}, [controller, autoInitialize]);
|
|
328
|
+
return {
|
|
329
|
+
controller,
|
|
330
|
+
snapshot,
|
|
331
|
+
initialize() {
|
|
332
|
+
return getCurrentController().initialize();
|
|
333
|
+
},
|
|
334
|
+
start() {
|
|
335
|
+
return getCurrentController().start();
|
|
336
|
+
},
|
|
337
|
+
pause() {
|
|
338
|
+
return getCurrentController().pause();
|
|
339
|
+
},
|
|
340
|
+
resume() {
|
|
341
|
+
return getCurrentController().resume();
|
|
342
|
+
},
|
|
343
|
+
updateProgress(currentTimeSec, durationSec) {
|
|
344
|
+
return getCurrentController().updateProgress(currentTimeSec, durationSec);
|
|
345
|
+
},
|
|
346
|
+
completeCurrent() {
|
|
347
|
+
return getCurrentController().completeCurrent();
|
|
348
|
+
},
|
|
349
|
+
next() {
|
|
350
|
+
return getCurrentController().next();
|
|
351
|
+
},
|
|
352
|
+
setMuted(muted) {
|
|
353
|
+
return getCurrentController().setMuted(muted);
|
|
354
|
+
},
|
|
355
|
+
setFullscreen(fullscreen) {
|
|
356
|
+
return getCurrentController().setFullscreen(fullscreen);
|
|
357
|
+
},
|
|
358
|
+
setViewability(viewability) {
|
|
359
|
+
return getCurrentController().setViewability(viewability);
|
|
360
|
+
},
|
|
361
|
+
click(trackOptions) {
|
|
362
|
+
return getCurrentController().click(trackOptions);
|
|
363
|
+
},
|
|
364
|
+
skip() {
|
|
365
|
+
return getCurrentController().skip();
|
|
366
|
+
},
|
|
367
|
+
signalError(trackOptions) {
|
|
368
|
+
return getCurrentController().signalError(trackOptions);
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
export function useVastTracker(options) {
|
|
373
|
+
const { session } = options;
|
|
374
|
+
const snapshot = useSubscribedSnapshot(session);
|
|
375
|
+
const availableEvents = useMemo(() => {
|
|
376
|
+
const events = new Set();
|
|
377
|
+
if (snapshot.tracking.plan.impressions.length > 0) {
|
|
378
|
+
events.add("impression");
|
|
379
|
+
}
|
|
380
|
+
if (snapshot.tracking.plan.errors.length > 0) {
|
|
381
|
+
events.add("error");
|
|
382
|
+
}
|
|
383
|
+
if (snapshot.tracking.plan.clickTrackings.length > 0) {
|
|
384
|
+
events.add("clickTracking");
|
|
385
|
+
}
|
|
386
|
+
for (const target of snapshot.tracking.plan.events) {
|
|
387
|
+
events.add(target.event);
|
|
388
|
+
}
|
|
389
|
+
return [...events].sort((left, right) => left.localeCompare(right));
|
|
390
|
+
}, [snapshot.tracking]);
|
|
391
|
+
return {
|
|
392
|
+
session,
|
|
393
|
+
tracking: snapshot.tracking,
|
|
394
|
+
resolvedAd: snapshot.resolvedAd,
|
|
395
|
+
resolvedAds: snapshot.resolvedAds,
|
|
396
|
+
companions: snapshot.resolvedAd?.companions ?? [],
|
|
397
|
+
availableEvents,
|
|
398
|
+
clickThroughUrl: snapshot.resolvedAd?.clickThroughUrl ?? null,
|
|
399
|
+
clickThroughUrls: snapshot.resolvedAd?.clickThroughUrls ?? [],
|
|
400
|
+
getAdCompanions(adSelector) {
|
|
401
|
+
return session.getAdCompanions(adSelector);
|
|
402
|
+
},
|
|
403
|
+
track(event, trackOptions) {
|
|
404
|
+
return session.track(event, trackOptions);
|
|
405
|
+
},
|
|
406
|
+
trackAd(adSelector, event, trackOptions) {
|
|
407
|
+
return session.trackAd(adSelector, event, trackOptions);
|
|
408
|
+
},
|
|
409
|
+
trackCompanion(adSelector, companionSelector, event, trackOptions) {
|
|
410
|
+
return session.trackCompanion(adSelector, companionSelector, event, trackOptions);
|
|
411
|
+
},
|
|
412
|
+
getTargets(event, trackOptions) {
|
|
413
|
+
return selectTrackingTargets(snapshot.tracking.plan, event, trackOptions?.offset);
|
|
414
|
+
},
|
|
415
|
+
getAdTargets(adSelector, event, trackOptions) {
|
|
416
|
+
return session.getAdTrackingTargets(adSelector, event, trackOptions);
|
|
417
|
+
},
|
|
418
|
+
getCompanionTargets(adSelector, companionSelector, event) {
|
|
419
|
+
return session.getCompanionTrackingTargets(adSelector, companionSelector, event);
|
|
420
|
+
},
|
|
421
|
+
hasTargets(event, trackOptions) {
|
|
422
|
+
return selectTrackingTargets(snapshot.tracking.plan, event, trackOptions?.offset).length > 0;
|
|
423
|
+
},
|
|
424
|
+
hasAdTargets(adSelector, event, trackOptions) {
|
|
425
|
+
return session.getAdTrackingTargets(adSelector, event, trackOptions).length > 0;
|
|
426
|
+
},
|
|
427
|
+
hasCompanionTargets(adSelector, companionSelector, event) {
|
|
428
|
+
return session.getCompanionTrackingTargets(adSelector, companionSelector, event).length > 0;
|
|
429
|
+
},
|
|
430
|
+
};
|
|
431
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { useVastAnnotations, useVastPlayback, useVastPlaybackQueue, useVastSession, useVastTracker } from "./hooks.js";
|
|
2
|
+
export type { UseVastAnnotationsOptions, UseVastPlaybackOptions, UseVastPlaybackQueueOptions, UseVastSessionOptions, UseVastTrackerOptions, VastAnnotation, VastAnnotationModel, VastPlaybackHookResult, VastPlaybackQueueHookResult, VastSessionHookResult, VastTrackerHookResult, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useVastAnnotations, useVastPlayback, useVastPlaybackQueue, useVastSession, useVastTracker } from "./hooks.js";
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { VastPlaybackController, VastPlaybackControllerOptions, VastPlaybackSnapshot, VastPlaybackQueueController, VastPlaybackQueueControllerOptions, VastPlaybackQueueSnapshot, VastCompanionAd, VastCompanionSelector, VastAdSelector, VastResolvedAd, VastSession, VastSessionOptions, VastSessionSnapshot, VastTrackOptions, VastTrackableEvent, VastTrackingDispatchResult, VastTrackingState, VastTrackingTarget } from "vastlint-client";
|
|
2
|
+
import type { FixResult, ValidationResult } from "vastlint";
|
|
3
|
+
export interface UseVastSessionOptions extends VastSessionOptions {
|
|
4
|
+
autoLoad?: boolean;
|
|
5
|
+
autoValidate?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface VastAnnotation {
|
|
8
|
+
id: string;
|
|
9
|
+
issueId: string;
|
|
10
|
+
severity: "error" | "warning" | "info";
|
|
11
|
+
message: string;
|
|
12
|
+
path: string | null;
|
|
13
|
+
line: number | null;
|
|
14
|
+
col: number | null;
|
|
15
|
+
}
|
|
16
|
+
export interface VastAnnotationModel {
|
|
17
|
+
annotations: VastAnnotation[];
|
|
18
|
+
byLine: Map<number, VastAnnotation[]>;
|
|
19
|
+
byIssueId: Map<string, VastAnnotation[]>;
|
|
20
|
+
}
|
|
21
|
+
export interface UseVastAnnotationsOptions {
|
|
22
|
+
xml: string;
|
|
23
|
+
validation: ValidationResult | null;
|
|
24
|
+
}
|
|
25
|
+
export interface UseVastTrackerOptions {
|
|
26
|
+
session: VastSession;
|
|
27
|
+
}
|
|
28
|
+
export interface UseVastPlaybackOptions extends VastPlaybackControllerOptions {
|
|
29
|
+
autoInitialize?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface UseVastPlaybackQueueOptions extends VastPlaybackQueueControllerOptions {
|
|
32
|
+
autoInitialize?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface VastTrackerHookResult {
|
|
35
|
+
session: VastSession;
|
|
36
|
+
tracking: VastTrackingState;
|
|
37
|
+
resolvedAd: VastResolvedAd | null;
|
|
38
|
+
resolvedAds: VastResolvedAd[];
|
|
39
|
+
companions: VastCompanionAd[];
|
|
40
|
+
availableEvents: VastTrackableEvent[];
|
|
41
|
+
clickThroughUrl: string | null;
|
|
42
|
+
clickThroughUrls: string[];
|
|
43
|
+
getAdCompanions(adSelector: VastAdSelector): VastCompanionAd[];
|
|
44
|
+
track(event: VastTrackableEvent, options?: VastTrackOptions): Promise<VastTrackingDispatchResult[]>;
|
|
45
|
+
trackAd(adSelector: VastAdSelector, event: VastTrackableEvent, options?: VastTrackOptions): Promise<VastTrackingDispatchResult[]>;
|
|
46
|
+
trackCompanion(adSelector: VastAdSelector, companionSelector: VastCompanionSelector, event: VastTrackableEvent, options?: VastTrackOptions): Promise<VastTrackingDispatchResult[]>;
|
|
47
|
+
getTargets(event: VastTrackableEvent, options?: Pick<VastTrackOptions, "offset">): VastTrackingTarget[];
|
|
48
|
+
getAdTargets(adSelector: VastAdSelector, event: VastTrackableEvent, options?: Pick<VastTrackOptions, "offset">): VastTrackingTarget[];
|
|
49
|
+
getCompanionTargets(adSelector: VastAdSelector, companionSelector: VastCompanionSelector, event: VastTrackableEvent): VastTrackingTarget[];
|
|
50
|
+
hasTargets(event: VastTrackableEvent, options?: Pick<VastTrackOptions, "offset">): boolean;
|
|
51
|
+
hasAdTargets(adSelector: VastAdSelector, event: VastTrackableEvent, options?: Pick<VastTrackOptions, "offset">): boolean;
|
|
52
|
+
hasCompanionTargets(adSelector: VastAdSelector, companionSelector: VastCompanionSelector, event: VastTrackableEvent): boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface VastSessionHookResult {
|
|
55
|
+
session: VastSession;
|
|
56
|
+
snapshot: VastSessionSnapshot;
|
|
57
|
+
load(): Promise<VastSessionSnapshot>;
|
|
58
|
+
reload(): Promise<VastSessionSnapshot>;
|
|
59
|
+
validate(): Promise<ValidationResult>;
|
|
60
|
+
fix(): Promise<FixResult>;
|
|
61
|
+
resolve(): Promise<VastSessionSnapshot>;
|
|
62
|
+
track(event: VastTrackableEvent, options?: VastTrackOptions): Promise<VastTrackingDispatchResult[]>;
|
|
63
|
+
trackAd(adSelector: VastAdSelector, event: VastTrackableEvent, options?: VastTrackOptions): Promise<VastTrackingDispatchResult[]>;
|
|
64
|
+
}
|
|
65
|
+
export interface VastPlaybackHookResult extends Pick<VastPlaybackController, "initialize" | "start" | "pause" | "resume" | "updateProgress" | "complete" | "setMuted" | "setFullscreen" | "setViewability" | "click" | "skip" | "signalError"> {
|
|
66
|
+
controller: VastPlaybackController;
|
|
67
|
+
snapshot: VastPlaybackSnapshot;
|
|
68
|
+
}
|
|
69
|
+
export interface VastPlaybackQueueHookResult extends Pick<VastPlaybackQueueController, "initialize" | "start" | "pause" | "resume" | "updateProgress" | "completeCurrent" | "next" | "setMuted" | "setFullscreen" | "setViewability" | "click" | "skip" | "signalError"> {
|
|
70
|
+
controller: VastPlaybackQueueController;
|
|
71
|
+
snapshot: VastPlaybackQueueSnapshot;
|
|
72
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vastlint-react",
|
|
3
|
+
"version": "0.4.20",
|
|
4
|
+
"description": "Headless React hooks for vastlint-client.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Alex Sekowski <alex@vastlint.org>",
|
|
7
|
+
"homepage": "https://vastlint.org",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/aleksUIX/vastlint.git",
|
|
11
|
+
"directory": "packages/vastlint-react"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/aleksUIX/vastlint/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"vast",
|
|
18
|
+
"vast-client",
|
|
19
|
+
"react",
|
|
20
|
+
"react-hooks",
|
|
21
|
+
"adtech",
|
|
22
|
+
"ctv",
|
|
23
|
+
"video",
|
|
24
|
+
"advertising",
|
|
25
|
+
"programmatic"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
43
|
+
"test": "npm --prefix ../vastlint-client run build && npm run build && node --test test/**/*.test.mjs"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"vastlint-client": "^0.4.20"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"react": ">=18"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/react": "^19.0.0",
|
|
59
|
+
"jsdom": "^26.1.0",
|
|
60
|
+
"react": "^19.0.0",
|
|
61
|
+
"react-dom": "^19.2.6",
|
|
62
|
+
"typescript": "^5.9.3"
|
|
63
|
+
}
|
|
64
|
+
}
|