UNPKG

@ketch-sdk/ketch-data-layer

Version:
242 lines 18.6 kB
"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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