@miso.ai/client-sdk-core 1.5.1 → 1.6.0-beta.2

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.
Files changed (50) hide show
  1. package/dist/cjs/api/base.js +1 -15
  2. package/dist/cjs/api/helpers.js +2 -31
  3. package/dist/cjs/api/index.js +0 -9
  4. package/dist/cjs/api/interactions.js +7 -24
  5. package/dist/cjs/api/recommendation.js +0 -11
  6. package/dist/cjs/api/search.js +0 -8
  7. package/dist/cjs/classes.js +0 -9
  8. package/dist/cjs/client.js +0 -21
  9. package/dist/cjs/cmd.js +4 -8
  10. package/dist/cjs/context.js +0 -4
  11. package/dist/cjs/index.js +4 -8
  12. package/dist/cjs/plugin/anonymous.js +0 -4
  13. package/dist/cjs/plugin/auto-events.js +0 -28
  14. package/dist/cjs/plugin/index.js +0 -12
  15. package/dist/cjs/plugin/page-info.js +0 -12
  16. package/dist/cjs/plugin/plugin-root.js +7 -55
  17. package/dist/cjs/plugin/user.js +0 -26
  18. package/dist/cjs/root.js +4 -13
  19. package/dist/cjs/utils.js +7 -37
  20. package/dist/cjs/version.js +1 -1
  21. package/dist/es/api/base.js +1 -12
  22. package/dist/es/api/helpers.js +2 -27
  23. package/dist/es/api/index.js +0 -1
  24. package/dist/es/api/interactions.js +7 -20
  25. package/dist/es/api/recommendation.js +0 -7
  26. package/dist/es/api/search.js +0 -4
  27. package/dist/es/client.js +0 -13
  28. package/dist/es/cmd.js +4 -7
  29. package/dist/es/context.js +0 -1
  30. package/dist/es/index.js +4 -4
  31. package/dist/es/plugin/anonymous.js +0 -1
  32. package/dist/es/plugin/auto-events.js +0 -24
  33. package/dist/es/plugin/index.js +1 -2
  34. package/dist/es/plugin/page-info.js +0 -8
  35. package/dist/es/plugin/plugin-root.js +7 -48
  36. package/dist/es/plugin/user.js +0 -22
  37. package/dist/es/root.js +5 -7
  38. package/dist/es/utils.js +1 -34
  39. package/dist/es/version.js +1 -1
  40. package/package.json +2 -2
  41. package/dist/cjs/plugin/units/constants.js +0 -10
  42. package/dist/cjs/plugin/units/index.js +0 -41
  43. package/dist/cjs/plugin/units/tracker.js +0 -365
  44. package/dist/cjs/plugin/units/unit.js +0 -63
  45. package/dist/cjs/plugin/units/units.js +0 -70
  46. package/dist/es/plugin/units/constants.js +0 -2
  47. package/dist/es/plugin/units/index.js +0 -27
  48. package/dist/es/plugin/units/tracker.js +0 -353
  49. package/dist/es/plugin/units/unit.js +0 -50
  50. package/dist/es/plugin/units/units.js +0 -56
@@ -1,353 +0,0 @@
1
- const _excluded = ["impression", "viewable", "click"];
2
-
3
- function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
4
-
5
- import { isElement, trimObj, asArray } from '@miso.ai/commons';
6
- import { ATTR_PRODUCT_ID } from './constants';
7
- import { viewable as whenViewable } from '../../utils';
8
-
9
- function mergeOptions(def, opt) {
10
- // if opt is falsy then return false, merge otherwise
11
- return !!opt && Object.assign({}, def, opt);
12
- }
13
-
14
- const DEFAULT_TRACKING_OPTIONS = {
15
- watchElements: false,
16
- viewable: {
17
- area: 0.5,
18
- duration: 1000
19
- },
20
- click: {
21
- lenient: false
22
- }
23
- };
24
- const STATE = {
25
- INITIAL: 0,
26
- TRACKING: 1,
27
- TRIGGERED: 2
28
- };
29
- export default class Tracker {
30
- constructor(unit) {
31
- this._unit = unit;
32
- this._eventStates = new Map();
33
- this._sentEvents = {
34
- impression: new Set(),
35
- viewable: new Set(),
36
- click: new Set()
37
- };
38
- this._handleClick = this._handleClick.bind(this);
39
- }
40
-
41
- start(options) {
42
- const root = this._unit.element;
43
-
44
- if (!root) {
45
- throw new Error(`The unit has no bound element. Call unit.bind(element) to associated the unit to an element.`);
46
- }
47
-
48
- if (this._options) {
49
- // throw, for the options could be different and this won't be idempotent
50
- throw new Error(`Already tracking events.`);
51
- } // settle tracking options
52
-
53
-
54
- this._options = this._normalizeOptions(options);
55
-
56
- this._watchElements();
57
-
58
- this._trackClicks();
59
-
60
- this.sync();
61
- }
62
-
63
- sync() {
64
- const {
65
- impression,
66
- viewable
67
- } = this._options;
68
-
69
- if (!impression && !viewable) {
70
- return;
71
- } // scan all descendants for product item elements
72
-
73
-
74
- const elements = this._unit.element.querySelectorAll(`[${ATTR_PRODUCT_ID}]`);
75
-
76
- this._trackImpressions(elements);
77
-
78
- this._trackViewables(elements);
79
- }
80
-
81
- interceptEventPayload(callback) {
82
- this._eventPayloadPass = callback;
83
- }
84
-
85
- impression(productIds) {
86
- this._sendEvent('impression', productIds, true);
87
- }
88
-
89
- viewable(productIds) {
90
- this._sendEvent('viewable', productIds, true);
91
- }
92
-
93
- click(productIds) {
94
- this._sendEvent('click', productIds, true);
95
- }
96
-
97
- _normalizeOptions() {
98
- let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
99
-
100
- let {
101
- impression = {},
102
- viewable = {},
103
- click = {}
104
- } = _ref,
105
- options = _objectWithoutPropertiesLoose(_ref, _excluded);
106
-
107
- return trimObj(Object.assign({}, DEFAULT_TRACKING_OPTIONS, options, {
108
- impression: mergeOptions(DEFAULT_TRACKING_OPTIONS.impression, impression),
109
- viewable: mergeOptions(DEFAULT_TRACKING_OPTIONS.viewable, viewable),
110
- click: mergeOptions(DEFAULT_TRACKING_OPTIONS.click, click)
111
- }));
112
- }
113
-
114
- _watchElements() {
115
- const {
116
- watchElements,
117
- impression,
118
- viewable
119
- } = this._options;
120
-
121
- if (!watchElements || !impression && !viewable) {
122
- return;
123
- }
124
-
125
- const observer = this._mutationObserver = new MutationObserver(mutations => {
126
- let hasAddedElements = false;
127
- let removedElements = [];
128
-
129
- for (const {
130
- addedNodes,
131
- removedNodes
132
- } of mutations) {
133
- hasAddedElements = hasAddedElements || addedNodes.length > 0;
134
- addedElements = [...addedElements, ...addedNodes];
135
- removedElements = [...removedElements, ...removedNodes];
136
- }
137
-
138
- if (hasAddedElements) {
139
- this.sync();
140
- }
141
-
142
- this._untrackViewables(removedElements);
143
- });
144
- observer.observe(this._element, {
145
- childList: true,
146
- subtree: true
147
- });
148
- }
149
-
150
- _unwatchElements() {
151
- this._mutationObserver && this._mutationObserver.disconnect();
152
- }
153
-
154
- _trackImpressions(elements) {
155
- const options = this._options.impression;
156
-
157
- if (!options) {
158
- return;
159
- }
160
-
161
- const productIds = [];
162
-
163
- for (const element of elements) {
164
- const productId = element.getAttribute(ATTR_PRODUCT_ID);
165
-
166
- if (!productId) {
167
- continue;
168
- }
169
-
170
- const state = this._getEventState(productId);
171
-
172
- if (state.impression !== STATE.TRIGGERED) {
173
- state.impression = STATE.TRIGGERED;
174
- productIds.push(productId);
175
- }
176
- }
177
-
178
- this._sendEvent('impression', productIds);
179
- }
180
-
181
- _trackViewables(elements) {
182
- const options = this._options.viewable;
183
-
184
- if (!options) {
185
- return;
186
- }
187
-
188
- for (const element of elements) {
189
- this._trackViewableOnElement(element);
190
- }
191
- }
192
-
193
- async _trackViewableOnElement(element) {
194
- if (!isElement(element)) {
195
- return;
196
- }
197
-
198
- const productId = element.getAttribute(ATTR_PRODUCT_ID);
199
-
200
- if (!productId) {
201
- return;
202
- } // TODO: when element is replaced without proper unload...
203
-
204
-
205
- const state = this._getEventState(productId);
206
-
207
- if (state.viewable !== STATE.INITIAL) {
208
- return;
209
- }
210
-
211
- state.viewable = STATE.TRACKING;
212
- const {
213
- area,
214
- duration
215
- } = this._options.viewable;
216
- await whenViewable(element, {
217
- area,
218
- duration
219
- });
220
- state.viewable = STATE.TRIGGERED;
221
-
222
- this._sendEvent('viewable', [productId]);
223
- }
224
-
225
- _untrackAllViewables() {// TODO
226
- }
227
-
228
- _untrackViewables(elements) {// we need to scan through all descendants to scavenge detached product items
229
- // TODO
230
- }
231
-
232
- _trackClicks() {
233
- this._unit.element.addEventListener('click', this._handleClick);
234
- }
235
-
236
- _untrackClicks() {
237
- this._unit.element.removeEventListener('click', this._handleClick);
238
- }
239
-
240
- _destroy() {
241
- this._unwatchElements();
242
-
243
- this._untrackClicks();
244
- }
245
-
246
- _getEventState(productId) {
247
- let state = this._eventStates.get(productId);
248
-
249
- if (!state) {
250
- this._eventStates.set(productId, state = {
251
- impression: STATE.INITIAL,
252
- viewable: STATE.INITIAL,
253
- click: STATE.INITIAL
254
- });
255
- }
256
-
257
- return state;
258
- }
259
-
260
- _handleClick(event) {
261
- const options = this._options && this._options.click;
262
-
263
- if (!options) {
264
- return;
265
- }
266
-
267
- let productId;
268
-
269
- for (let element = event.target; !productId && element && element !== document; element = element.parentElement) {
270
- productId = element.getAttribute(ATTR_PRODUCT_ID);
271
- }
272
-
273
- if (!productId) {
274
- return;
275
- }
276
-
277
- const state = this._getEventState(productId);
278
-
279
- if (state.click === STATE.TRIGGERED) {
280
- return;
281
- }
282
-
283
- if (!options.lenient) {// only left click counts
284
- // event isPreventDefault
285
- // go through a real link
286
- // TODO
287
- }
288
-
289
- state.click = STATE.TRIGGERED;
290
-
291
- this._sendEvent('click', [productId]);
292
- }
293
-
294
- _sendEvent(type, productIds, manual) {
295
- if (type !== 'impression' && type !== 'viewable' && type !== 'click') {
296
- throw new Error(`Unrecognized event type: ${type}`);
297
- }
298
-
299
- productIds = asArray(productIds); // dedupe
300
-
301
- const sentEvents = this._sentEvents[type];
302
- productIds = productIds.filter(id => {
303
- const sent = sentEvents.has(id);
304
-
305
- if (!sent) {
306
- sentEvents.add(id);
307
- }
308
-
309
- return !sent;
310
- });
311
-
312
- if (productIds.length === 0) {
313
- return;
314
- } // TODO: emit
315
- // we want to queue the event for a while so we can merge them and save requests
316
- // TODO
317
-
318
-
319
- const client = this._unit._context._client;
320
-
321
- const payloads = this._buildPayloads(type, productIds, manual);
322
-
323
- if (payloads.length > 0) {
324
- client.api.interactions.upload(payloads);
325
- }
326
- }
327
-
328
- _buildPayloads(type, productIds, manual) {
329
- const {
330
- id,
331
- uuid
332
- } = this._unit;
333
- let payload = {
334
- type: type === 'viewable' ? 'viewable_impression' : type,
335
- product_ids: productIds,
336
- context: {
337
- custom_context: {
338
- unit_id: id,
339
- unit_instance_uuid: uuid,
340
- trigger: manual ? 'manual' : 'auto'
341
- }
342
- }
343
- };
344
-
345
- if (this._eventPayloadPass) {
346
- // TODO: handle error
347
- payload = this._eventPayloadPass(payload);
348
- }
349
-
350
- return asArray(payload);
351
- }
352
-
353
- }
@@ -1,50 +0,0 @@
1
- import { uuidv4 } from '@miso.ai/commons';
2
- import Tracker from './tracker';
3
- export default class Unit {
4
- constructor(context, id) {
5
- this._context = context;
6
- Object.defineProperties(this, {
7
- uuid: {
8
- value: uuidv4()
9
- },
10
- id: {
11
- value: id
12
- }
13
- });
14
-
15
- context._units.set(id, this);
16
- }
17
-
18
- get element() {
19
- return this._element;
20
- }
21
-
22
- get tracker() {
23
- return this._tracker || (this._tracker = new Tracker(this));
24
- }
25
-
26
- bind(element) {
27
- if (this._element === element) {
28
- return;
29
- } else if (this._element) {
30
- throw new Error(`Element has already been set.`);
31
- }
32
-
33
- this._element = element;
34
-
35
- this._context._e2u.set(element, this);
36
-
37
- return this;
38
- }
39
-
40
- destroy() {
41
- this._tracker && this._tracker._destroy();
42
-
43
- this._context._e2u.delete(this._element);
44
-
45
- this._context._units.delete(this.id);
46
-
47
- this._element = undefined;
48
- }
49
-
50
- }
@@ -1,56 +0,0 @@
1
- import { isElement, delegateGetters } from '@miso.ai/commons';
2
- import { ATTR_UNIT_ID } from './constants';
3
- import Unit from './unit';
4
- export default class UnitsContext {
5
- constructor(plugin, client) {
6
- this._plugin = plugin;
7
- this._client = client;
8
- this._units = new Map();
9
- this._e2u = new WeakMap();
10
- this.interface = new Units(this);
11
- }
12
-
13
- list() {
14
- return [...this._units.values()];
15
- }
16
-
17
- create() {
18
- let id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'default';
19
-
20
- if (this._units.has(id)) {
21
- throw new Error(`Unit already exists: ${id}`);
22
- }
23
-
24
- return new Unit(this, id);
25
- }
26
-
27
- has() {
28
- let ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'default';
29
- return typeof ref === 'string' ? this._units.has(ref) : isElement(ref) && this._e2u.has(ref);
30
- }
31
-
32
- get() {
33
- let ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'default';
34
-
35
- if (typeof ref === 'string') {
36
- return this._units.get(ref) || new Unit(this, ref);
37
- } else if (isElement(ref)) {
38
- if (this._e2u.has(ref)) {
39
- return this._e2u.get(ref);
40
- } else {
41
- const id = ref.getAttribute(ATTR_UNIT_ID) || 'default';
42
- return new Unit(this, id).bind(ref);
43
- }
44
- } else {
45
- throw new Error(`Required input to be either a string unit ID or an element: ${ref}`);
46
- }
47
- }
48
-
49
- }
50
-
51
- class Units {
52
- constructor(context) {
53
- delegateGetters(this, context, ['list', 'has', 'create', 'get']);
54
- }
55
-
56
- }