@player-ui/beacon-plugin 0.0.1-next.1

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.
@@ -0,0 +1,171 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tapable = require('tapable');
6
+ var player = require('@player-ui/player');
7
+ var timm = require('timm');
8
+
9
+ const BeaconPluginSymbol = Symbol.for("BeaconPlugin");
10
+
11
+ var __defProp = Object.defineProperty;
12
+ var __defProps = Object.defineProperties;
13
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
14
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
17
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
18
+ var __spreadValues = (a, b) => {
19
+ for (var prop in b || (b = {}))
20
+ if (__hasOwnProp.call(b, prop))
21
+ __defNormalProp(a, prop, b[prop]);
22
+ if (__getOwnPropSymbols)
23
+ for (var prop of __getOwnPropSymbols(b)) {
24
+ if (__propIsEnum.call(b, prop))
25
+ __defNormalProp(a, prop, b[prop]);
26
+ }
27
+ return a;
28
+ };
29
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
30
+ var __async = (__this, __arguments, generator) => {
31
+ return new Promise((resolve, reject) => {
32
+ var fulfilled = (value) => {
33
+ try {
34
+ step(generator.next(value));
35
+ } catch (e) {
36
+ reject(e);
37
+ }
38
+ };
39
+ var rejected = (value) => {
40
+ try {
41
+ step(generator.throw(value));
42
+ } catch (e) {
43
+ reject(e);
44
+ }
45
+ };
46
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
47
+ step((generator = generator.apply(__this, __arguments)).next());
48
+ });
49
+ };
50
+ const _BeaconPlugin = class {
51
+ constructor(options) {
52
+ this.name = "Beacon";
53
+ this.symbol = _BeaconPlugin.Symbol;
54
+ this.beaconContext = {
55
+ view: void 0
56
+ };
57
+ this.hooks = {
58
+ buildBeacon: new tapable.AsyncSeriesWaterfallHook([
59
+ "beacon",
60
+ "beaconArguments"
61
+ ]),
62
+ cancelBeacon: new tapable.SyncBailHook(["args"]),
63
+ publishBeacon: new tapable.SyncHook(["beacon"])
64
+ };
65
+ if (options == null ? void 0 : options.plugins) {
66
+ options.plugins.forEach((plugin) => {
67
+ plugin.apply(this);
68
+ });
69
+ }
70
+ if (options == null ? void 0 : options.callback) {
71
+ this.hooks.publishBeacon.tap("BeaconCallback", (beacon) => {
72
+ if (options.callback)
73
+ options.callback(beacon);
74
+ });
75
+ }
76
+ }
77
+ apply(player) {
78
+ this.player = player;
79
+ this.logger = player.logger;
80
+ player.hooks.dataController.tap(this.name, (dataController) => {
81
+ this.dataController = dataController;
82
+ });
83
+ player.hooks.expressionEvaluator.tap(this.name, (expressionEvaluator) => {
84
+ this.expressionEvaluator = expressionEvaluator;
85
+ });
86
+ player.hooks.viewController.tap(this.name, (vc) => {
87
+ this.beaconContext = {
88
+ view: void 0
89
+ };
90
+ vc.hooks.view.tap(this.name, (view) => {
91
+ let beaconedView = false;
92
+ view.hooks.parser.tap(this.name, (parser) => {
93
+ parser.hooks.onCreateASTNode.tap(this.name, (obj) => {
94
+ var _a, _b, _c, _d;
95
+ if ((obj == null ? void 0 : obj.type) !== "asset" && (obj == null ? void 0 : obj.type) !== "view")
96
+ return void 0;
97
+ const propertiesToSkip = (_c = (_b = (_a = obj.plugins) == null ? void 0 : _a.stringResolver) == null ? void 0 : _b.propertiesToSkip) != null ? _c : [];
98
+ if (propertiesToSkip.includes("beacon"))
99
+ return void 0;
100
+ obj.plugins = timm.setIn((_d = obj.plugins) != null ? _d : {}, ["stringResolver", "propertiesToSkip"], ["beacon", ...propertiesToSkip]);
101
+ return obj;
102
+ });
103
+ });
104
+ view.hooks.onUpdate.tap(this.name, (viewUpdate) => {
105
+ this.beaconContext = {
106
+ view: viewUpdate
107
+ };
108
+ if (!beaconedView) {
109
+ this.beacon({
110
+ action: "viewed",
111
+ element: "view",
112
+ asset: viewUpdate,
113
+ view: viewUpdate
114
+ });
115
+ beaconedView = true;
116
+ }
117
+ });
118
+ });
119
+ });
120
+ player.hooks.expressionEvaluator.tap(this.name, (evaluator) => {
121
+ evaluator.addExpressionFunction("beacon", (_ctx, action, data) => {
122
+ const view = this.beaconContext.view || {};
123
+ this.beacon({
124
+ action,
125
+ data,
126
+ element: "view",
127
+ asset: view,
128
+ view
129
+ });
130
+ });
131
+ });
132
+ }
133
+ beacon(event) {
134
+ const { action, element, asset, view } = event;
135
+ const { view: currentView } = this.beaconContext;
136
+ setTimeout(() => __async(this, null, function* () {
137
+ var _a, _b, _c, _d;
138
+ const data = (event == null ? void 0 : event.data) || ((_b = (_a = event.asset) == null ? void 0 : _a.metaData) == null ? void 0 : _b.beacon);
139
+ const defaultBeacon = {
140
+ action,
141
+ element,
142
+ data,
143
+ assetId: asset == null ? void 0 : asset.id,
144
+ viewId: currentView == null ? void 0 : currentView.id
145
+ };
146
+ const state = (_c = this.player) == null ? void 0 : _c.getState();
147
+ const hookArgs = __spreadProps(__spreadValues({}, event), {
148
+ data,
149
+ state,
150
+ view: view || currentView,
151
+ logger: this.logger
152
+ });
153
+ const beacon = (yield this.hooks.buildBeacon.promise(defaultBeacon, hookArgs)) || defaultBeacon;
154
+ const shouldCancel = this.hooks.cancelBeacon.call(hookArgs) || false;
155
+ if (!shouldCancel) {
156
+ const resolvedBeacon = this.dataController && this.expressionEvaluator ? player.resolveDataRefs(beacon, {
157
+ model: this.dataController,
158
+ evaluate: this.expressionEvaluator.evaluate
159
+ }) : beacon;
160
+ (_d = this.logger) == null ? void 0 : _d.debug("Sending beacon event", resolvedBeacon);
161
+ this.hooks.publishBeacon.call(resolvedBeacon);
162
+ }
163
+ }), 0);
164
+ }
165
+ };
166
+ let BeaconPlugin = _BeaconPlugin;
167
+ BeaconPlugin.Symbol = BeaconPluginSymbol;
168
+
169
+ exports.BeaconPlugin = BeaconPlugin;
170
+ exports.BeaconPluginSymbol = BeaconPluginSymbol;
171
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1,70 @@
1
+ import { AsyncSeriesWaterfallHook, SyncBailHook, SyncHook } from 'tapable';
2
+ import { PlayerFlowState, PlayerPlugin, Player } from '@player-ui/player';
3
+ import { Asset, View } from '@player-ui/types';
4
+ import { Logger } from '@player-ui/logger';
5
+
6
+ declare type BeaconDataType = string | Record<string, any>;
7
+ interface BeaconMetaData {
8
+ /** Additional data to send along with beacons */
9
+ beacon?: BeaconDataType;
10
+ }
11
+ interface AssetBeaconInfo {
12
+ /** Additional data about the asset */
13
+ metaData?: BeaconMetaData;
14
+ }
15
+ declare type AssetBeacon = Asset & AssetBeaconInfo;
16
+ declare type ViewBeacon = View & AssetBeaconInfo;
17
+ interface BeaconPluginPlugin {
18
+ /** Use this to tap into the beacon plugin hooks */
19
+ apply: (beaconPlugin: BeaconPlugin) => void;
20
+ }
21
+ interface BeaconPluginOptions {
22
+ /** Callback when a beacon is published */
23
+ callback?: (beacon: any) => void;
24
+ /** A set of plugins to load */
25
+ plugins?: BeaconPluginPlugin[];
26
+ }
27
+ interface BeaconArgs {
28
+ /** The action being performed */
29
+ action: string;
30
+ /** The specific element that the beacon originated from */
31
+ element: string;
32
+ /** The asset firing the beacon */
33
+ asset: AssetBeacon;
34
+ /** The current view */
35
+ view?: ViewBeacon;
36
+ /** Any additional data to attach to the event */
37
+ data?: any;
38
+ }
39
+ interface HookArgs extends BeaconArgs {
40
+ /** The current player state */
41
+ state?: PlayerFlowState;
42
+ /** The beacon plugin logger */
43
+ logger: Logger;
44
+ }
45
+ /**
46
+ * A player plugin to manage beacon events.
47
+ * It automatically keeps track of the current user's view, and adds additional metaData to each beacon event.
48
+ */
49
+ declare class BeaconPlugin implements PlayerPlugin {
50
+ name: string;
51
+ static Symbol: symbol;
52
+ readonly symbol: symbol;
53
+ private player?;
54
+ private logger?;
55
+ private beaconContext;
56
+ private dataController?;
57
+ private expressionEvaluator?;
58
+ hooks: {
59
+ buildBeacon: AsyncSeriesWaterfallHook<unknown, HookArgs, any>;
60
+ cancelBeacon: SyncBailHook<HookArgs, boolean, any, any>;
61
+ publishBeacon: SyncHook<any, any, any>;
62
+ };
63
+ constructor(options?: BeaconPluginOptions);
64
+ apply(player: Player): void;
65
+ beacon(event: BeaconArgs): void;
66
+ }
67
+
68
+ declare const BeaconPluginSymbol: unique symbol;
69
+
70
+ export { AssetBeacon, AssetBeaconInfo, BeaconArgs, BeaconDataType, BeaconMetaData, BeaconPlugin, BeaconPluginOptions, BeaconPluginPlugin, BeaconPluginSymbol, HookArgs, ViewBeacon };
@@ -0,0 +1,166 @@
1
+ import { AsyncSeriesWaterfallHook, SyncBailHook, SyncHook } from 'tapable';
2
+ import { resolveDataRefs } from '@player-ui/player';
3
+ import { setIn } from 'timm';
4
+
5
+ const BeaconPluginSymbol = Symbol.for("BeaconPlugin");
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __defProps = Object.defineProperties;
9
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
10
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
13
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
+ var __spreadValues = (a, b) => {
15
+ for (var prop in b || (b = {}))
16
+ if (__hasOwnProp.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ if (__getOwnPropSymbols)
19
+ for (var prop of __getOwnPropSymbols(b)) {
20
+ if (__propIsEnum.call(b, prop))
21
+ __defNormalProp(a, prop, b[prop]);
22
+ }
23
+ return a;
24
+ };
25
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
26
+ var __async = (__this, __arguments, generator) => {
27
+ return new Promise((resolve, reject) => {
28
+ var fulfilled = (value) => {
29
+ try {
30
+ step(generator.next(value));
31
+ } catch (e) {
32
+ reject(e);
33
+ }
34
+ };
35
+ var rejected = (value) => {
36
+ try {
37
+ step(generator.throw(value));
38
+ } catch (e) {
39
+ reject(e);
40
+ }
41
+ };
42
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
43
+ step((generator = generator.apply(__this, __arguments)).next());
44
+ });
45
+ };
46
+ const _BeaconPlugin = class {
47
+ constructor(options) {
48
+ this.name = "Beacon";
49
+ this.symbol = _BeaconPlugin.Symbol;
50
+ this.beaconContext = {
51
+ view: void 0
52
+ };
53
+ this.hooks = {
54
+ buildBeacon: new AsyncSeriesWaterfallHook([
55
+ "beacon",
56
+ "beaconArguments"
57
+ ]),
58
+ cancelBeacon: new SyncBailHook(["args"]),
59
+ publishBeacon: new SyncHook(["beacon"])
60
+ };
61
+ if (options == null ? void 0 : options.plugins) {
62
+ options.plugins.forEach((plugin) => {
63
+ plugin.apply(this);
64
+ });
65
+ }
66
+ if (options == null ? void 0 : options.callback) {
67
+ this.hooks.publishBeacon.tap("BeaconCallback", (beacon) => {
68
+ if (options.callback)
69
+ options.callback(beacon);
70
+ });
71
+ }
72
+ }
73
+ apply(player) {
74
+ this.player = player;
75
+ this.logger = player.logger;
76
+ player.hooks.dataController.tap(this.name, (dataController) => {
77
+ this.dataController = dataController;
78
+ });
79
+ player.hooks.expressionEvaluator.tap(this.name, (expressionEvaluator) => {
80
+ this.expressionEvaluator = expressionEvaluator;
81
+ });
82
+ player.hooks.viewController.tap(this.name, (vc) => {
83
+ this.beaconContext = {
84
+ view: void 0
85
+ };
86
+ vc.hooks.view.tap(this.name, (view) => {
87
+ let beaconedView = false;
88
+ view.hooks.parser.tap(this.name, (parser) => {
89
+ parser.hooks.onCreateASTNode.tap(this.name, (obj) => {
90
+ var _a, _b, _c, _d;
91
+ if ((obj == null ? void 0 : obj.type) !== "asset" && (obj == null ? void 0 : obj.type) !== "view")
92
+ return void 0;
93
+ const propertiesToSkip = (_c = (_b = (_a = obj.plugins) == null ? void 0 : _a.stringResolver) == null ? void 0 : _b.propertiesToSkip) != null ? _c : [];
94
+ if (propertiesToSkip.includes("beacon"))
95
+ return void 0;
96
+ obj.plugins = setIn((_d = obj.plugins) != null ? _d : {}, ["stringResolver", "propertiesToSkip"], ["beacon", ...propertiesToSkip]);
97
+ return obj;
98
+ });
99
+ });
100
+ view.hooks.onUpdate.tap(this.name, (viewUpdate) => {
101
+ this.beaconContext = {
102
+ view: viewUpdate
103
+ };
104
+ if (!beaconedView) {
105
+ this.beacon({
106
+ action: "viewed",
107
+ element: "view",
108
+ asset: viewUpdate,
109
+ view: viewUpdate
110
+ });
111
+ beaconedView = true;
112
+ }
113
+ });
114
+ });
115
+ });
116
+ player.hooks.expressionEvaluator.tap(this.name, (evaluator) => {
117
+ evaluator.addExpressionFunction("beacon", (_ctx, action, data) => {
118
+ const view = this.beaconContext.view || {};
119
+ this.beacon({
120
+ action,
121
+ data,
122
+ element: "view",
123
+ asset: view,
124
+ view
125
+ });
126
+ });
127
+ });
128
+ }
129
+ beacon(event) {
130
+ const { action, element, asset, view } = event;
131
+ const { view: currentView } = this.beaconContext;
132
+ setTimeout(() => __async(this, null, function* () {
133
+ var _a, _b, _c, _d;
134
+ const data = (event == null ? void 0 : event.data) || ((_b = (_a = event.asset) == null ? void 0 : _a.metaData) == null ? void 0 : _b.beacon);
135
+ const defaultBeacon = {
136
+ action,
137
+ element,
138
+ data,
139
+ assetId: asset == null ? void 0 : asset.id,
140
+ viewId: currentView == null ? void 0 : currentView.id
141
+ };
142
+ const state = (_c = this.player) == null ? void 0 : _c.getState();
143
+ const hookArgs = __spreadProps(__spreadValues({}, event), {
144
+ data,
145
+ state,
146
+ view: view || currentView,
147
+ logger: this.logger
148
+ });
149
+ const beacon = (yield this.hooks.buildBeacon.promise(defaultBeacon, hookArgs)) || defaultBeacon;
150
+ const shouldCancel = this.hooks.cancelBeacon.call(hookArgs) || false;
151
+ if (!shouldCancel) {
152
+ const resolvedBeacon = this.dataController && this.expressionEvaluator ? resolveDataRefs(beacon, {
153
+ model: this.dataController,
154
+ evaluate: this.expressionEvaluator.evaluate
155
+ }) : beacon;
156
+ (_d = this.logger) == null ? void 0 : _d.debug("Sending beacon event", resolvedBeacon);
157
+ this.hooks.publishBeacon.call(resolvedBeacon);
158
+ }
159
+ }), 0);
160
+ }
161
+ };
162
+ let BeaconPlugin = _BeaconPlugin;
163
+ BeaconPlugin.Symbol = BeaconPluginSymbol;
164
+
165
+ export { BeaconPlugin, BeaconPluginSymbol };
166
+ //# sourceMappingURL=index.esm.js.map
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@player-ui/beacon-plugin",
3
+ "version": "0.0.1-next.1",
4
+ "private": false,
5
+ "publishConfig": {
6
+ "registry": "https://registry.npmjs.org"
7
+ },
8
+ "peerDependencies": {
9
+ "@player-ui/binding-grammar": "0.0.1-next.1",
10
+ "@player-ui/logger": "0.0.1-next.1",
11
+ "@player-ui/types": "0.0.1-next.1"
12
+ },
13
+ "dependencies": {
14
+ "tapable": "1.1.3",
15
+ "timm": "^1.6.2",
16
+ "@types/tapable": "^1.0.5",
17
+ "@babel/runtime": "7.15.4"
18
+ },
19
+ "main": "dist/index.cjs.js",
20
+ "module": "dist/index.esm.js",
21
+ "typings": "dist/index.d.ts"
22
+ }
package/src/beacon.ts ADDED
@@ -0,0 +1,225 @@
1
+ import { SyncBailHook, AsyncSeriesWaterfallHook, SyncHook } from 'tapable';
2
+ import type {
3
+ Player,
4
+ PlayerPlugin,
5
+ PlayerFlowState,
6
+ DataController,
7
+ ExpressionEvaluator,
8
+ } from '@player-ui/player';
9
+ import { resolveDataRefs } from '@player-ui/player';
10
+ import type { Asset, View } from '@player-ui/types';
11
+ import type { Logger } from '@player-ui/logger';
12
+ import { setIn } from 'timm';
13
+ import { BeaconPluginSymbol } from './symbols';
14
+
15
+ export type BeaconDataType = string | Record<string, any>;
16
+
17
+ export interface BeaconMetaData {
18
+ /** Additional data to send along with beacons */
19
+ beacon?: BeaconDataType;
20
+ }
21
+
22
+ export interface AssetBeaconInfo {
23
+ /** Additional data about the asset */
24
+ metaData?: BeaconMetaData;
25
+ }
26
+
27
+ export type AssetBeacon = Asset & AssetBeaconInfo;
28
+ export type ViewBeacon = View & AssetBeaconInfo;
29
+
30
+ export interface BeaconPluginPlugin {
31
+ /** Use this to tap into the beacon plugin hooks */
32
+ apply: (beaconPlugin: BeaconPlugin) => void;
33
+ }
34
+
35
+ export interface BeaconPluginOptions {
36
+ /** Callback when a beacon is published */
37
+ callback?: (beacon: any) => void;
38
+ /** A set of plugins to load */
39
+ plugins?: BeaconPluginPlugin[];
40
+ }
41
+
42
+ interface BeaconContext {
43
+ /** The full current view */
44
+ view?: ViewBeacon;
45
+ }
46
+
47
+ export interface BeaconArgs {
48
+ /** The action being performed */
49
+ action: string;
50
+ /** The specific element that the beacon originated from */
51
+ element: string;
52
+ /** The asset firing the beacon */
53
+ asset: AssetBeacon;
54
+ /** The current view */
55
+ view?: ViewBeacon;
56
+ /** Any additional data to attach to the event */
57
+ data?: any;
58
+ }
59
+
60
+ export interface HookArgs extends BeaconArgs {
61
+ /** The current player state */
62
+ state?: PlayerFlowState;
63
+ /** The beacon plugin logger */
64
+ logger: Logger;
65
+ }
66
+
67
+ /**
68
+ * A player plugin to manage beacon events.
69
+ * It automatically keeps track of the current user's view, and adds additional metaData to each beacon event.
70
+ */
71
+ export class BeaconPlugin implements PlayerPlugin {
72
+ name = 'Beacon';
73
+
74
+ static Symbol = BeaconPluginSymbol;
75
+ public readonly symbol = BeaconPlugin.Symbol;
76
+
77
+ private player?: Player;
78
+ private logger?: Logger;
79
+
80
+ private beaconContext: BeaconContext = {
81
+ view: undefined,
82
+ };
83
+
84
+ private dataController?: DataController;
85
+ private expressionEvaluator?: ExpressionEvaluator;
86
+
87
+ public hooks = {
88
+ buildBeacon: new AsyncSeriesWaterfallHook<unknown, HookArgs>([
89
+ 'beacon',
90
+ 'beaconArguments',
91
+ ]),
92
+ cancelBeacon: new SyncBailHook<HookArgs, boolean>(['args']),
93
+ publishBeacon: new SyncHook(['beacon']),
94
+ };
95
+
96
+ constructor(options?: BeaconPluginOptions) {
97
+ if (options?.plugins) {
98
+ options.plugins.forEach((plugin) => {
99
+ plugin.apply(this);
100
+ });
101
+ }
102
+
103
+ if (options?.callback) {
104
+ this.hooks.publishBeacon.tap('BeaconCallback', (beacon: any) => {
105
+ if (options.callback) options.callback(beacon);
106
+ });
107
+ }
108
+ }
109
+
110
+ apply(player: Player) {
111
+ this.player = player;
112
+ this.logger = player.logger;
113
+
114
+ player.hooks.dataController.tap(this.name, (dataController) => {
115
+ this.dataController = dataController;
116
+ });
117
+
118
+ player.hooks.expressionEvaluator.tap(this.name, (expressionEvaluator) => {
119
+ this.expressionEvaluator = expressionEvaluator;
120
+ });
121
+
122
+ player.hooks.viewController.tap(this.name, (vc) => {
123
+ this.beaconContext = {
124
+ view: undefined,
125
+ };
126
+
127
+ vc.hooks.view.tap(this.name, (view) => {
128
+ let beaconedView = false;
129
+
130
+ view.hooks.parser.tap(this.name, (parser) => {
131
+ /* If there is a 'beacon' property in an asset or view, skip resolving as we
132
+ are doing this manually when beacon is fired. */
133
+ parser.hooks.onCreateASTNode.tap(this.name, (obj) => {
134
+ if (obj?.type !== 'asset' && obj?.type !== 'view') return undefined;
135
+
136
+ const propertiesToSkip =
137
+ obj.plugins?.stringResolver?.propertiesToSkip ?? [];
138
+
139
+ if (propertiesToSkip.includes('beacon')) return undefined;
140
+
141
+ // eslint-disable-next-line no-param-reassign
142
+ obj.plugins = setIn(
143
+ obj.plugins ?? {},
144
+ ['stringResolver', 'propertiesToSkip'],
145
+ ['beacon', ...propertiesToSkip]
146
+ ) as any;
147
+
148
+ return obj;
149
+ });
150
+ });
151
+
152
+ view.hooks.onUpdate.tap(this.name, (viewUpdate: ViewBeacon) => {
153
+ this.beaconContext = {
154
+ view: viewUpdate,
155
+ };
156
+
157
+ if (!beaconedView) {
158
+ this.beacon({
159
+ action: 'viewed',
160
+ element: 'view',
161
+ asset: viewUpdate,
162
+ view: viewUpdate,
163
+ });
164
+
165
+ beaconedView = true;
166
+ }
167
+ });
168
+ });
169
+ });
170
+
171
+ player.hooks.expressionEvaluator.tap(this.name, (evaluator) => {
172
+ evaluator.addExpressionFunction('beacon', (_ctx, action, data) => {
173
+ const view = this.beaconContext.view || ({} as ViewBeacon);
174
+ this.beacon({
175
+ action: action as string,
176
+ data: data as any,
177
+ element: 'view',
178
+ asset: view,
179
+ view,
180
+ });
181
+ });
182
+ });
183
+ }
184
+
185
+ beacon(event: BeaconArgs) {
186
+ const { action, element, asset, view } = event;
187
+ const { view: currentView } = this.beaconContext;
188
+ setTimeout(async () => {
189
+ const data = event?.data || event.asset?.metaData?.beacon;
190
+
191
+ const defaultBeacon = {
192
+ action,
193
+ element,
194
+ data,
195
+ assetId: asset?.id,
196
+ viewId: currentView?.id,
197
+ };
198
+ const state = this.player?.getState();
199
+ const hookArgs = {
200
+ ...event,
201
+ data,
202
+ state,
203
+ view: view || currentView,
204
+ logger: this.logger as Logger,
205
+ };
206
+ const beacon =
207
+ (await this.hooks.buildBeacon.promise(defaultBeacon, hookArgs)) ||
208
+ defaultBeacon;
209
+ const shouldCancel = this.hooks.cancelBeacon.call(hookArgs) || false;
210
+
211
+ if (!shouldCancel) {
212
+ const resolvedBeacon =
213
+ this.dataController && this.expressionEvaluator
214
+ ? resolveDataRefs(beacon, {
215
+ model: this.dataController,
216
+ evaluate: this.expressionEvaluator.evaluate,
217
+ })
218
+ : beacon;
219
+
220
+ this.logger?.debug('Sending beacon event', resolvedBeacon);
221
+ this.hooks.publishBeacon.call(resolvedBeacon);
222
+ }
223
+ }, 0);
224
+ }
225
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './beacon';
2
+ export * from './symbols';
package/src/symbols.ts ADDED
@@ -0,0 +1 @@
1
+ export const BeaconPluginSymbol = Symbol.for('BeaconPlugin');