@ketch-sdk/ketch-data-layer
Version:
Ketch Data Layer interface
242 lines • 18.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const events_1 = require("events");
const ketch_types_1 = require("@ketch-sdk/ketch-types");
const cookie_1 = require("../cookie");
const dataLayer_1 = require("../dataLayer");
const window_1 = require("../window");
const localStorage_1 = require("../localStorage");
const sessionStorage_1 = require("../sessionStorage");
const queryString_1 = require("../queryString");
const managed_1 = require("../managed");
const string_1 = require("../string");
const json_1 = require("../json");
const jwt_1 = require("../jwt");
const queryString_2 = require("../queryString");
const semicolon_1 = require("../semicolon");
const base64_1 = require("../base64");
const noop_1 = require("../noop");
const nano_equal_1 = tslib_1.__importDefault(require("nano-equal"));
const ketch_logging_1 = require("@ketch-sdk/ketch-logging");
const log = (0, ketch_logging_1.getLogger)('trait');
/**
* Watcher provides a mechanism for watching for traits.
*/
class Watcher {
/**
* Create a new Watcher.
*
* @param w The window interface
* @param options The listener options
*/
constructor(w, options = {}) {
this._emitter = new events_1.EventEmitter();
this._w = w;
this._listenerOptions = options;
this._fetchers = new Map();
this._attributes = {};
}
/**
* Add a trait with the given name and definition.
*
* @param name The name of the trait.
* @param attribute The definition of the trait.
*/
add(name, attribute) {
let structure;
let encoding;
if (typeof attribute === 'function') {
this._fetchers.set(name, () => attribute());
return;
}
switch (attribute.format) {
case ketch_types_1.TraitFormat.TRAIT_FORMAT_JSON:
structure = json_1.structure;
break;
case ketch_types_1.TraitFormat.TRAIT_FORMAT_JWT:
structure = jwt_1.structure;
break;
case ketch_types_1.TraitFormat.TRAIT_FORMAT_QUERY:
structure = queryString_2.structure;
break;
case ketch_types_1.TraitFormat.TRAIT_FORMAT_SEMICOLON:
structure = semicolon_1.structure;
break;
default: // string or undefined
structure = string_1.structure;
}
const key = attribute.key || 'value';
switch (attribute.encoding) {
case ketch_types_1.TraitEncoding.TRAIT_ENCODING_BASE64:
encoding = base64_1.encoding;
break;
default: // none or undefined
encoding = noop_1.encoding;
}
// Get a value from an object (JSON) by key dot notation
const getDotValue = (obj, key) => {
const keys = key.split('.');
return keys.reduce((v, k) => {
if (v && typeof v === 'object' && k in v) {
return v[k];
}
else {
return undefined;
}
}, obj);
};
switch (attribute.type) {
case ketch_types_1.TraitType.TRAIT_TYPE_COOKIE:
this._fetchers.set(name, (w) => (0, cookie_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
case ketch_types_1.TraitType.TRAIT_TYPE_DATA_LAYER:
this._fetchers.set(name, (w) => (0, dataLayer_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
case ketch_types_1.TraitType.TRAIT_TYPE_WINDOW:
this._fetchers.set(name, (w) => (0, window_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
case ketch_types_1.TraitType.TRAIT_TYPE_LOCAL_STORAGE:
this._fetchers.set(name, (w) => (0, localStorage_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
case ketch_types_1.TraitType.TRAIT_TYPE_SESSION_STORAGE:
this._fetchers.set(name, (w) => (0, sessionStorage_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
case ketch_types_1.TraitType.TRAIT_TYPE_QUERY_STRING:
this._fetchers.set(name, (w) => (0, queryString_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
case ketch_types_1.TraitType.TRAIT_TYPE_MANAGED:
this._fetchers.set(name, (w) => (0, managed_1.fetcher)(w, attribute.variable).then(values => encoding(values)
.map(structure)
.map(values => String(getDotValue(values, key)))));
break;
default:
throw new Error(`unsupported trait type ${attribute.type} for ${name}`);
}
}
/**
* Starts watching for traits.
*/
start(type, returnEarly) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (this._intervalId) {
return;
}
if (this._listenerOptions.interval) {
this._intervalId = this._w.setInterval(this.notify.bind(this), this._listenerOptions.interval);
if (this._listenerOptions.timeout) {
this._w.setTimeout(this.stop.bind(this), this._listenerOptions.timeout);
}
}
return this.notify(type, returnEarly);
});
}
/**
* Stops watching for traits.
*/
stop() {
if (!this._intervalId) {
return;
}
this._w.clearInterval(this._intervalId);
this._intervalId = undefined;
}
/**
* Fetches and notifies about traits.
*/
notify(type, returnEarly) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const attributes = {};
for (const [key, fetcher] of this._fetchers.entries()) {
try {
const values = yield fetcher(this._w);
for (const value of values) {
attributes[key] = value;
}
}
catch (e) {
log.warn(`failed to fetch trait for ${key}: ${e}`);
}
}
// If there are new attributes or no attributes at all, emit the event
// This is to ensure that absent attributes do not hold up the event loop
// (if it is waiting for attributes object to be fulfilled)
if (!(0, nano_equal_1.default)(attributes, this._attributes) || (returnEarly && Object.keys(this._attributes).length === 0)) {
const message = type || ketch_types_1.TraitName.IDENTITY;
this._emitter.emit(message, attributes);
this._attributes = attributes;
}
});
}
/**
* Alias for `emitter.on(eventName, listener)`.
*/
addListener(eventName, listener) {
return this.on(eventName, listener);
}
/**
* Adds the `listener` function to the end of the listeners array for the
* event named `eventName`. No checks are made to see if the `listener` has
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in
* the `listener` being added, and called, multiple
* times.
*
* @param eventName The name of the event.
* @param listener The callback function
*/
on(eventName, listener) {
this._emitter.on(eventName, listener);
return this;
}
/**
* Adds a **one-time**`listener` function for the event named `eventName`. The
* next time `eventName` is triggered, this listener is removed and then invoked.
*
* @param eventName The name of the event.
* @param listener The callback function
*/
once(eventName, listener) {
this._emitter.once(eventName, listener);
return this;
}
/**
* Removes the specified `listener` from the listener array for the event named`eventName`.
*/
removeListener(eventName, listener) {
return this.off(eventName, listener);
}
/**
* Alias for `emitter.removeListener()`.
*/
off(eventName, listener) {
this._emitter.off(eventName, listener);
return this;
}
/**
* Removes all listeners, or those of the specified `eventName`.
*
* It is bad practice to remove listeners added elsewhere in the code,
* particularly when the `EventEmitter` instance was created by some other
* component or module (e.g. sockets or file streams).
*
* Returns a reference to the `EventEmitter`, so that calls can be chained.
*/
removeAllListeners(event) {
this._emitter.removeAllListeners(event);
return this;
}
}
exports.default = Watcher;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd2F0Y2hlci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtQ0FBcUM7QUFDckMsd0RBQWtIO0FBQ2xILHNDQUFvRDtBQUNwRCw0Q0FBMEQ7QUFDMUQsc0NBQW9EO0FBQ3BELGtEQUFnRTtBQUNoRSxzREFBb0U7QUFDcEUsZ0RBQThEO0FBQzlELHdDQUFzRDtBQUN0RCxzQ0FBd0Q7QUFDeEQsa0NBQW9EO0FBQ3BELGdDQUFrRDtBQUNsRCxnREFBNEQ7QUFDNUQsNENBQThEO0FBQzlELHNDQUFzRDtBQUN0RCxrQ0FBa0Q7QUFJbEQsb0VBQWtDO0FBQ2xDLDREQUFvRDtBQUVwRCxNQUFNLEdBQUcsR0FBRyxJQUFBLHlCQUFTLEVBQUMsT0FBTyxDQUFDLENBQUE7QUFFOUI7O0dBRUc7QUFDSCxNQUFxQixPQUFPO0lBUTFCOzs7OztPQUtHO0lBQ0gsWUFBWSxDQUFTLEVBQUUsVUFBMkIsRUFBRTtRQUNsRCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUkscUJBQVksRUFBRSxDQUFBO1FBQ2xDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFBO1FBQ1gsSUFBSSxDQUFDLGdCQUFnQixHQUFHLE9BQU8sQ0FBQTtRQUMvQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksR0FBRyxFQUE0QyxDQUFBO1FBQ3BFLElBQUksQ0FBQyxXQUFXLEdBQUcsRUFBRSxDQUFBO0lBQ3ZCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEdBQUcsQ0FBQyxJQUFZLEVBQUUsU0FBdUQ7UUFDdkUsSUFBSSxTQUFvQixDQUFBO1FBQ3hCLElBQUksUUFBa0IsQ0FBQTtRQUV0QixJQUFJLE9BQU8sU0FBUyxLQUFLLFVBQVUsRUFBRTtZQUNuQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQTtZQUMzQyxP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