This is an automated email from the ASF dual-hosted git repository.

unclegedd pushed a commit to branch test
in repository https://gitbox.apache.org/repos/asf/flagon-useralejs.git

commit 1cbfd0f882b07586a7ce52fb9114ec4a61eff8c1
Author: Jason Young <[email protected]>
AuthorDate: Thu Mar 23 15:52:33 2023 -0700

    Changed map/filter to addCallbacks
    
    Co-authored-by: Nicholas Alexander Sagun <[email protected]>
---
 build/UserALEWebExtension/background.js | 206 ++++++-------
 build/UserALEWebExtension/content.js    | 523 +++++++++++++++++---------------
 build/UserALEWebExtension/options.js    |  30 +-
 build/userale-2.3.0.js                  | 115 ++++---
 build/userale-2.3.0.min.js              |   2 +-
 example/index.js                        |  30 +-
 src/UserALEWebExtension/content.js      |   7 +-
 src/main.js                             |   3 +-
 src/packageLogs.js                      |  81 +++--
 test/packageLogs_spec.js                | 113 +++----
 10 files changed, 578 insertions(+), 532 deletions(-)

diff --git a/build/UserALEWebExtension/background.js 
b/build/UserALEWebExtension/background.js
index ad860f7..abd9d13 100644
--- a/build/UserALEWebExtension/background.js
+++ b/build/UserALEWebExtension/background.js
@@ -26,57 +26,57 @@ var toolVersion = '2.3.0';
 
 /* eslint-enable */
 
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-    * this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-    * the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+    * this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+    * the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
 */
 
 var prefix = 'USERALE_';
 var CONFIG_CHANGE = prefix + 'CONFIG_CHANGE';
 var ADD_LOG = prefix + 'ADD_LOG';
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the 'License'); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an 'AS IS' BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
-/**
- * Creates a function to normalize the timestamp of the provided event.
- * @param  {Object} e An event containing a timeStamp property.
- * @return {timeStampScale~tsScaler}   The timestamp normalizing function.
+/**
+ * Creates a function to normalize the timestamp of the provided event.
+ * @param  {Object} e An event containing a timeStamp property.
+ * @return {timeStampScale~tsScaler}   The timestamp normalizing function.
  */
 function timeStampScale(e) {
   var tsScaler;
   if (e.timeStamp && e.timeStamp > 0) {
     var delta = Date.now() - e.timeStamp;
-    /**
-     * Returns a timestamp depending on various browser quirks.
-     * @param  {?Number} ts A timestamp to use for normalization.
-     * @return {Number} A normalized timestamp.
+    /**
+     * Returns a timestamp depending on various browser quirks.
+     * @param  {?Number} ts A timestamp to use for normalization.
+     * @return {Number} A normalized timestamp.
      */
 
     if (delta < 0) {
@@ -307,29 +307,13 @@ function createVersionParts(count) {
     return output;
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 detect();
 
-/**
- * Extract the millisecond and microsecond portions of a timestamp.
- * @param  {Number} timeStamp The timestamp to split into millisecond and 
microsecond fields.
- * @return {Object}           An object containing the millisecond
- *                            and microsecond portions of the timestamp.
+/**
+ * Extract the millisecond and microsecond portions of a timestamp.
+ * @param  {Number} timeStamp The timestamp to split into millisecond and 
microsecond fields.
+ * @return {Object}           An object containing the millisecond
+ *                            and microsecond portions of the timestamp.
  */
 function extractTimeFields(timeStamp) {
   return {
@@ -338,29 +322,29 @@ function extractTimeFields(timeStamp) {
   };
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 var sendIntervalId = null;
 
-/**
- * Initializes the log queue processors.
- * @param  {Array} logs   Array of logs to append to.
- * @param  {Object} config Configuration object to use when logging.
+/**
+ * Initializes the log queue processors.
+ * @param  {Array} logs   Array of logs to append to.
+ * @param  {Object} config Configuration object to use when logging.
  */
 function initSender(logs, config) {
   if (sendIntervalId !== null) {
@@ -370,12 +354,12 @@ function initSender(logs, config) {
   sendOnClose(logs, config);
 }
 
-/**
- * Checks the provided log array on an interval, flushing the logs
- * if the queue has reached the threshold specified by the provided config.
- * @param  {Array} logs   Array of logs to read from.
- * @param  {Object} config Configuration object to be read from.
- * @return {Number}        The newly created interval id.
+/**
+ * Checks the provided log array on an interval, flushing the logs
+ * if the queue has reached the threshold specified by the provided config.
+ * @param  {Array} logs   Array of logs to read from.
+ * @param  {Object} config Configuration object to be read from.
+ * @return {Number}        The newly created interval id.
  */
 function sendOnInterval(logs, config) {
   return setInterval(function () {
@@ -389,10 +373,10 @@ function sendOnInterval(logs, config) {
   }, config.transmitInterval);
 }
 
-/**
- * Attempts to flush the remaining logs when the window is closed.
- * @param  {Array} logs   Array of logs to be flushed.
- * @param  {Object} config Configuration object to be read from.
+/**
+ * Attempts to flush the remaining logs when the window is closed.
+ * @param  {Array} logs   Array of logs to be flushed.
+ * @param  {Object} config Configuration object to be read from.
  */
 function sendOnClose(logs, config) {
   window.addEventListener('pagehide', function () {
@@ -403,12 +387,12 @@ function sendOnClose(logs, config) {
   });
 }
 
-/**
- * Sends the provided array of logs to the specified url,
- * retrying the request up to the specified number of retries.
- * @param  {Array} logs    Array of logs to send.
- * @param  {string} config     configuration parameters (e.g., to extract URL 
from & send the POST request to).
- * @param  {Number} retries Maximum number of attempts to send the logs.
+/**
+ * Sends the provided array of logs to the specified url,
+ * retrying the request up to the specified number of retries.
+ * @param  {Array} logs    Array of logs to send.
+ * @param  {string} config     configuration parameters (e.g., to extract URL 
from & send the POST request to).
+ * @param  {Number} retries Maximum number of attempts to send the logs.
  */
 
 // @todo expose config object to sendLogs replate url with config.url
@@ -432,21 +416,21 @@ function sendLogs(logs, config, retries) {
   req.send(data);
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 // inherent dependency on globals.js, loaded by the webext
@@ -602,6 +586,6 @@ browser.tabs.onZoomChange.addListener(function (e) {
   });
 });
 
-/*
- eslint-enable
+/*
+ eslint-enable
  */
diff --git a/build/UserALEWebExtension/content.js 
b/build/UserALEWebExtension/content.js
index 5720e9a..d0689d1 100644
--- a/build/UserALEWebExtension/content.js
+++ b/build/UserALEWebExtension/content.js
@@ -26,21 +26,21 @@ var toolVersion = '2.3.0';
 
 /* eslint-enable */
 
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-    * this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-    * the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+    * this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+    * the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
 */
 
 var prefix = 'USERALE_';
@@ -49,29 +49,29 @@ var ADD_LOG = prefix + 'ADD_LOG';
 
 var version = "2.3.0";
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the 'License'); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an 'AS IS' BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 var sessionId = null;
 
-/**
- * Extracts the initial configuration settings from the
- * currently executing script tag.
- * @return {Object} The extracted configuration object
+/**
+ * Extracts the initial configuration settings from the
+ * currently executing script tag.
+ * @return {Object} The extracted configuration object
  */
 function getInitialSettings() {
   var settings = {};
@@ -102,11 +102,11 @@ function getInitialSettings() {
   return settings;
 }
 
-/**
- * defines sessionId, stores it in sessionStorage, checks to see if there is a 
sessionId in
- * storage when script is started. This prevents events like 'submit', which 
refresh page data
- * from refreshing the current user session
- *
+/**
+ * defines sessionId, stores it in sessionStorage, checks to see if there is a 
sessionId in
+ * storage when script is started. This prevents events like 'submit', which 
refresh page data
+ * from refreshing the current user session
+ *
  */
 function getSessionId(sessionKey, value) {
   if (window.sessionStorage.getItem(sessionKey) === null) {
@@ -116,19 +116,19 @@ function getSessionId(sessionKey, value) {
   return JSON.parse(window.sessionStorage.getItem(sessionKey));
 }
 
-/**
- * Creates a function to normalize the timestamp of the provided event.
- * @param  {Object} e An event containing a timeStamp property.
- * @return {timeStampScale~tsScaler}   The timestamp normalizing function.
+/**
+ * Creates a function to normalize the timestamp of the provided event.
+ * @param  {Object} e An event containing a timeStamp property.
+ * @return {timeStampScale~tsScaler}   The timestamp normalizing function.
  */
 function timeStampScale(e) {
   var tsScaler;
   if (e.timeStamp && e.timeStamp > 0) {
     var delta = Date.now() - e.timeStamp;
-    /**
-     * Returns a timestamp depending on various browser quirks.
-     * @param  {?Number} ts A timestamp to use for normalization.
-     * @return {Number} A normalized timestamp.
+    /**
+     * Returns a timestamp depending on various browser quirks.
+     * @param  {?Number} ts A timestamp to use for normalization.
+     * @return {Number} A normalized timestamp.
      */
 
     if (delta < 0) {
@@ -153,28 +153,28 @@ function timeStampScale(e) {
   return tsScaler;
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
-/**
- * Shallow merges the first argument with the second.
- * Retrieves/updates the userid if userFromParams is provided.
- * @param  {Object} config    Current configuration object to be merged into.
- * @param  {Object} newConfig Configuration object to merge into the current 
config.
+/**
+ * Shallow merges the first argument with the second.
+ * Retrieves/updates the userid if userFromParams is provided.
+ * @param  {Object} config    Current configuration object to be merged into.
+ * @param  {Object} newConfig Configuration object to merge into the current 
config.
  */
 function configure(config, newConfig) {
   var configAutostart = config['autostart'];
@@ -193,10 +193,10 @@ function configure(config, newConfig) {
   }
 }
 
-/**
- * Attempts to extract the userid from the query parameters of the URL.
- * @param  {string} param The name of the query parameter containing the 
userid.
- * @return {string|null}       The extracted/decoded userid, or null if none 
is found.
+/**
+ * Attempts to extract the userid from the query parameters of the URL.
+ * @param  {string} param The name of the query parameter containing the 
userid.
+ * @return {string|null}       The extracted/decoded userid, or null if none 
is found.
  */
 function getUserIdFromParams(param) {
   var userField = param;
@@ -415,22 +415,9 @@ function createVersionParts(count) {
     return output;
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof 
Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if 
(Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && 
o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = 
function F() {}; return { s: F, n: function n() { if (i >= o.length) return { 
done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { 
throw _e; }, f: F }; } throw new T [...]
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o 
=== "string") return _arrayLikeToArray(o, minLen); var n = 
Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && 
o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return 
Array.from(o); if (n === "Arguments" || 
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, 
minLen); }
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) 
len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] 
= arr[i]; return arr2; }
 var browser$1 = detect();
 var logs$1;
 var config$1;
@@ -442,27 +429,41 @@ var intervalPath;
 var intervalTimer;
 var intervalCounter;
 var intervalLog;
-var filterHandler = null;
-var mapHandler = null;
+var cbHandlers = {};
 
-/**
- * Assigns a handler to filter logs out of the queue.
- * @param  {Function} callback The handler to invoke when logging.
+/**
+ * Adds named callbacks to be executed when logging.
+ * @param  {Object } newCallbacks An object containing named callback 
functions.
  */
-function setLogFilter(callback) {
-  filterHandler = callback;
+function addCallbacks() {
+  for (var _len = arguments.length, newCallbacks = new Array(_len), _key = 0; 
_key < _len; _key++) {
+    newCallbacks[_key] = arguments[_key];
+  }
+  newCallbacks.forEach(function (source) {
+    var descriptors = Object.keys(source).reduce(function (descriptors, key) {
+      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
+      return descriptors;
+    }, {});
+    Object.getOwnPropertySymbols(source).forEach(function (sym) {
+      var descriptor = Object.getOwnPropertyDescriptor(source, sym);
+      if (descriptor.enumerable) {
+        descriptors[sym] = descriptor;
+      }
+    });
+    Object.defineProperties(cbHandlers, descriptors);
+  });
+  return cbHandlers;
 }
 
-/**
- * Assigns the config and log container to be used by the logging functions.
- * @param  {Array} newLogs   Log container.
- * @param  {Object} newConfig Configuration to use while logging.
+/**
+ * Assigns the config and log container to be used by the logging functions.
+ * @param  {Array} newLogs   Log container.
+ * @param  {Object} newConfig Configuration to use while logging.
  */
 function initPackager(newLogs, newConfig) {
   logs$1 = newLogs;
   config$1 = newConfig;
-  filterHandler = null;
-  mapHandler = null;
+  cbHandlers = [];
   intervalID = null;
   intervalType = null;
   intervalPath = null;
@@ -471,11 +472,11 @@ function initPackager(newLogs, newConfig) {
   intervalLog = null;
 }
 
-/**
- * Transforms the provided HTML event into a log and appends it to the log 
queue.
- * @param  {Object} e         The event to be logged.
- * @param  {Function} detailFcn The function to extract additional log 
parameters from the event.
- * @return {boolean}           Whether the event was logged.
+/**
+ * Transforms the provided HTML event into a log and appends it to the log 
queue.
+ * @param  {Object} e         The event to be logged.
+ * @param  {Function} detailFcn The function to extract additional log 
parameters from the event.
+ * @return {boolean}           Whether the event was logged.
  */
 function packageLog(e, detailFcn) {
   if (!config$1.on) {
@@ -507,22 +508,25 @@ function packageLog(e, detailFcn) {
     'useraleVersion': config$1.useraleVersion,
     'sessionID': config$1.sessionID
   };
-  if (typeof filterHandler === 'function' && !filterHandler(log)) {
-    return false;
-  }
-  if (typeof mapHandler === 'function') {
-    log = mapHandler(log, e);
+  for (var _i = 0, _Object$values = Object.values(cbHandlers); _i < 
_Object$values.length; _i++) {
+    var func = _Object$values[_i];
+    if (typeof func === 'function') {
+      log = func(log, e);
+      if (!log) {
+        return false;
+      }
+    }
   }
   logs$1.push(log);
   return true;
 }
 
-/**
- * Packages the provided customLog to include standard meta data and appends 
it to the log queue.
- * @param  {Object} customLog        The behavior to be logged.
- * @param  {Function} detailFcn     The function to extract additional log 
parameters from the event.
- * @param  {boolean} userAction     Indicates user behavior (true) or system 
behavior (false)
- * @return {boolean}           Whether the event was logged.
+/**
+ * Packages the provided customLog to include standard meta data and appends 
it to the log queue.
+ * @param  {Object} customLog        The behavior to be logged.
+ * @param  {Function} detailFcn     The function to extract additional log 
parameters from the event.
+ * @param  {boolean} userAction     Indicates user behavior (true) or system 
behavior (false)
+ * @return {boolean}           Whether the event was logged.
  */
 function packageCustomLog(customLog, detailFcn, userAction) {
   if (!config$1.on) {
@@ -549,21 +553,32 @@ function packageCustomLog(customLog, detailFcn, 
userAction) {
     'sessionID': config$1.sessionID
   };
   var log = Object.assign(metaData, customLog);
-  if (typeof filterHandler === 'function' && !filterHandler(log)) {
-    return false;
-  }
-  if (typeof mapHandler === 'function') {
-    log = mapHandler(log);
+  var _iterator = _createForOfIteratorHelper(cbHandlers.values()),
+    _step;
+  try {
+    for (_iterator.s(); !(_step = _iterator.n()).done;) {
+      var func = _step.value;
+      if (typeof func === 'function') {
+        log = func(log, null);
+        if (!log) {
+          return false;
+        }
+      }
+    }
+  } catch (err) {
+    _iterator.e(err);
+  } finally {
+    _iterator.f();
   }
   logs$1.push(log);
   return true;
 }
 
-/**
- * Extract the millisecond and microsecond portions of a timestamp.
- * @param  {Number} timeStamp The timestamp to split into millisecond and 
microsecond fields.
- * @return {Object}           An object containing the millisecond
- *                            and microsecond portions of the timestamp.
+/**
+ * Extract the millisecond and microsecond portions of a timestamp.
+ * @param  {Number} timeStamp The timestamp to split into millisecond and 
microsecond fields.
+ * @return {Object}           An object containing the millisecond
+ *                            and microsecond portions of the timestamp.
  */
 function extractTimeFields(timeStamp) {
   return {
@@ -572,10 +587,10 @@ function extractTimeFields(timeStamp) {
   };
 }
 
-/**
- * Track intervals and gather details about it.
- * @param {Object} e
- * @return boolean
+/**
+ * Track intervals and gather details about it.
+ * @param {Object} e
+ * @return boolean
  */
 function packageIntervalLog(e) {
   var target = getSelector(e.target);
@@ -618,11 +633,22 @@ function packageIntervalLog(e) {
       'useraleVersion': config$1.useraleVersion,
       'sessionID': config$1.sessionID
     };
-    if (typeof filterHandler === 'function' && !filterHandler(intervalLog)) {
-      return false;
-    }
-    if (typeof mapHandler === 'function') {
-      intervalLog = mapHandler(intervalLog, e);
+    var _iterator2 = _createForOfIteratorHelper(cbHandlers.values()),
+      _step2;
+    try {
+      for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+        var func = _step2.value;
+        if (typeof func === 'function') {
+          intervalLog = func(intervalLog, null);
+          if (!intervalLog) {
+            return false;
+          }
+        }
+      }
+    } catch (err) {
+      _iterator2.e(err);
+    } finally {
+      _iterator2.f();
     }
     logs$1.push(intervalLog);
 
@@ -641,11 +667,11 @@ function packageIntervalLog(e) {
   return true;
 }
 
-/**
- * Extracts coordinate information from the event
- * depending on a few browser quirks.
- * @param  {Object} e The event to extract coordinate information from.
- * @return {Object}   An object containing nullable x and y coordinates for 
the event.
+/**
+ * Extracts coordinate information from the event
+ * depending on a few browser quirks.
+ * @param  {Object} e The event to extract coordinate information from.
+ * @return {Object}   An object containing nullable x and y coordinates for 
the event.
  */
 function getLocation(e) {
   if (e.pageX != null) {
@@ -666,9 +692,9 @@ function getLocation(e) {
   }
 }
 
-/**
- * Extracts innerWidth and innerHeight to provide estimates of screen 
resolution
- * @return {Object} An object containing the innerWidth and InnerHeight
+/**
+ * Extracts innerWidth and innerHeight to provide estimates of screen 
resolution
+ * @return {Object} An object containing the innerWidth and InnerHeight
  */
 function getSreenRes() {
   return {
@@ -677,10 +703,10 @@ function getSreenRes() {
   };
 }
 
-/**
- * Builds a string CSS selector from the provided element
- * @param  {HTMLElement} ele The element from which the selector is built.
- * @return {string}     The CSS selector for the element, or Unknown if it 
can't be determined.
+/**
+ * Builds a string CSS selector from the provided element
+ * @param  {HTMLElement} ele The element from which the selector is built.
+ * @return {string}     The CSS selector for the element, or Unknown if it 
can't be determined.
  */
 function getSelector(ele) {
   if (ele.localName) {
@@ -694,10 +720,10 @@ function getSelector(ele) {
   }
 }
 
-/**
- * Builds an array of elements from the provided event target, to the root 
element.
- * @param  {Object} e Event from which the path should be built.
- * @return {HTMLElement[]}   Array of elements, starting at the event target, 
ending at the root element.
+/**
+ * Builds an array of elements from the provided event target, to the root 
element.
+ * @param  {Object} e Event from which the path should be built.
+ * @return {HTMLElement[]}   Array of elements, starting at the event target, 
ending at the root element.
  */
 function buildPath(e) {
   if (e instanceof window.Event) {
@@ -706,10 +732,10 @@ function buildPath(e) {
   }
 }
 
-/**
- * Builds a CSS selector path from the provided list of elements.
- * @param  {HTMLElement[]} path Array of HTMLElements from which the path 
should be built.
- * @return {string[]}      Array of string CSS selectors.
+/**
+ * Builds a CSS selector path from the provided list of elements.
+ * @param  {HTMLElement[]} path Array of HTMLElements from which the path 
should be built.
+ * @return {string[]}      Array of string CSS selectors.
  */
 function selectorizePath(path) {
   var i = 0;
@@ -728,21 +754,21 @@ function detectBrowser() {
   };
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 var events;
 var bufferBools;
@@ -752,9 +778,9 @@ var intervalEvents = ['click', 'focus', 'blur', 'input', 
'change', 'mouseover',
 var refreshEvents;
 var windowEvents = ['load', 'blur', 'focus'];
 
-/**
- * Maps an event to an object containing useful information.
- * @param  {Object} e Event to extract data from
+/**
+ * Maps an event to an object containing useful information.
+ * @param  {Object} e Event to extract data from
  */
 function extractMouseEvent(e) {
   return {
@@ -767,10 +793,10 @@ function extractMouseEvent(e) {
   };
 }
 
-/**
- * Defines the way information is extracted from various events.
- * Also defines which events we will listen to.
- * @param  {Object} config Configuration object to read from.
+/**
+ * Defines the way information is extracted from various events.
+ * Also defines which events we will listen to.
+ * @param  {Object} config Configuration object to read from.
  */
 function defineDetails(config) {
   // Events list
@@ -835,10 +861,10 @@ function defineDetails(config) {
   };
 }
 
-/**
- * Hooks the event handlers for each event type of interest.
- * @param  {Object} config Configuration object to use.
- * @return {boolean}        Whether the operation succeeded
+/**
+ * Hooks the event handlers for each event type of interest.
+ * @param  {Object} config Configuration object to use.
+ * @return {boolean}        Whether the operation succeeded
  */
 function attachHandlers(config) {
   defineDetails(config);
@@ -881,29 +907,29 @@ function attachHandlers(config) {
   return true;
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 var sendIntervalId = null;
 
-/**
- * Initializes the log queue processors.
- * @param  {Array} logs   Array of logs to append to.
- * @param  {Object} config Configuration object to use when logging.
+/**
+ * Initializes the log queue processors.
+ * @param  {Array} logs   Array of logs to append to.
+ * @param  {Object} config Configuration object to use when logging.
  */
 function initSender(logs, config) {
   if (sendIntervalId !== null) {
@@ -913,12 +939,12 @@ function initSender(logs, config) {
   sendOnClose(logs, config);
 }
 
-/**
- * Checks the provided log array on an interval, flushing the logs
- * if the queue has reached the threshold specified by the provided config.
- * @param  {Array} logs   Array of logs to read from.
- * @param  {Object} config Configuration object to be read from.
- * @return {Number}        The newly created interval id.
+/**
+ * Checks the provided log array on an interval, flushing the logs
+ * if the queue has reached the threshold specified by the provided config.
+ * @param  {Array} logs   Array of logs to read from.
+ * @param  {Object} config Configuration object to be read from.
+ * @return {Number}        The newly created interval id.
  */
 function sendOnInterval(logs, config) {
   return setInterval(function () {
@@ -932,10 +958,10 @@ function sendOnInterval(logs, config) {
   }, config.transmitInterval);
 }
 
-/**
- * Attempts to flush the remaining logs when the window is closed.
- * @param  {Array} logs   Array of logs to be flushed.
- * @param  {Object} config Configuration object to be read from.
+/**
+ * Attempts to flush the remaining logs when the window is closed.
+ * @param  {Array} logs   Array of logs to be flushed.
+ * @param  {Object} config Configuration object to be read from.
  */
 function sendOnClose(logs, config) {
   window.addEventListener('pagehide', function () {
@@ -946,12 +972,12 @@ function sendOnClose(logs, config) {
   });
 }
 
-/**
- * Sends the provided array of logs to the specified url,
- * retrying the request up to the specified number of retries.
- * @param  {Array} logs    Array of logs to send.
- * @param  {string} config     configuration parameters (e.g., to extract URL 
from & send the POST request to).
- * @param  {Number} retries Maximum number of attempts to send the logs.
+/**
+ * Sends the provided array of logs to the specified url,
+ * retrying the request up to the specified number of retries.
+ * @param  {Array} logs    Array of logs to send.
+ * @param  {string} config     configuration parameters (e.g., to extract URL 
from & send the POST request to).
+ * @param  {Number} retries Maximum number of attempts to send the logs.
  */
 
 // @todo expose config object to sendLogs replate url with config.url
@@ -993,10 +1019,10 @@ if (config.autostart) {
   setup(config);
 }
 
-/**
- * Hooks the global event listener, and starts up the
- * logging interval.
- * @param  {Object} config Configuration settings for the logger
+/**
+ * Hooks the global event listener, and starts up the
+ * logging interval.
+ * @param  {Object} config Configuration settings for the logger
  */
 function setup(config) {
   if (!started) {
@@ -1020,11 +1046,11 @@ function setup(config) {
   }
 }
 
-/**
- * Updates the current configuration
- * object with the provided values.
- * @param  {Object} newConfig The configuration options to use.
- * @return {Object}           Returns the updated configuration.
+/**
+ * Updates the current configuration
+ * object with the provided values.
+ * @param  {Object} newConfig The configuration options to use.
+ * @return {Object}           Returns the updated configuration.
  */
 function options(newConfig) {
   if (newConfig !== undefined) {
@@ -1033,21 +1059,21 @@ function options(newConfig) {
   return config;
 }
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 // browser is defined in firefox, but not in chrome. In chrome, they use
@@ -1084,11 +1110,14 @@ function queueLog(log) {
 function injectScript(config) {
   options(config);
   //  start();  not necessary given that autostart in place, and option is 
masked from WebExt users
-  setLogFilter(function (log) {
-    queueLog(Object.assign({}, log, {
-      pageUrl: document.location.href
-    }));
-    return false;
+  addCallbacks({
+    "function": function _function(log) {
+      queueLog(Object.assign({}, log, {
+        pageUrl: document.location.href
+      }));
+      console.log(log);
+      return false;
+    }
   });
 }
 browser.runtime.onMessage.addListener(function (message) {
@@ -1102,6 +1131,6 @@ browser.runtime.onMessage.addListener(function (message) {
   }
 });
 
-/*
- eslint-enable
+/*
+ eslint-enable
  */
diff --git a/build/UserALEWebExtension/options.js 
b/build/UserALEWebExtension/options.js
index d935e14..eed800f 100644
--- a/build/UserALEWebExtension/options.js
+++ b/build/UserALEWebExtension/options.js
@@ -26,21 +26,21 @@ var toolVersion = '2.3.0';
 
 /* eslint-enable */
 
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-    * this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-    * the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+    * this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+    * the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
 */
 
 var prefix = 'USERALE_';
diff --git a/build/userale-2.3.0.js b/build/userale-2.3.0.js
index 795ff29..fd8a994 100644
--- a/build/userale-2.3.0.js
+++ b/build/userale-2.3.0.js
@@ -400,22 +400,9 @@
       return output;
   }
 
-  /*
-   * Licensed to the Apache Software Foundation (ASF) under one or more
-   * contributor license agreements.  See the NOTICE file distributed with
-   * this work for additional information regarding copyright ownership.
-   * The ASF licenses this file to You under the Apache License, Version 2.0
-   * (the "License"); you may not use this file except in compliance with
-   * the License.  You may obtain a copy of the License at
-   * 
-   *   http://www.apache.org/licenses/LICENSE-2.0
-   * 
-   * Unless required by applicable law or agreed to in writing, software
-   * distributed under the License is distributed on an "AS IS" BASIS,
-   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   * See the License for the specific language governing permissions and
-   * limitations under the License.
-   */
+  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof 
Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if 
(Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && 
o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = 
function F() {}; return { s: F, n: function n() { if (i >= o.length) return { 
done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { 
throw _e; }, f: F }; } throw new [...]
+  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof 
o === "string") return _arrayLikeToArray(o, minLen); var n = 
Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && 
o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return 
Array.from(o); if (n === "Arguments" || 
/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, 
minLen); }
+  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) 
len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] 
= arr[i]; return arr2; }
   var browser = detect();
   var logs$1;
   var config$1;
@@ -427,23 +414,30 @@
   var intervalTimer;
   var intervalCounter;
   var intervalLog;
-  var filterHandler = null;
-  var mapHandler = null;
-
-  /**
-   * Assigns a handler to filter logs out of the queue.
-   * @param  {Function} callback The handler to invoke when logging.
-   */
-  function setLogFilter(callback) {
-    filterHandler = callback;
-  }
+  var cbHandlers = {};
 
   /**
-   * Assigns a handler to transform logs from their default structure.
-   * @param  {Function} callback The handler to invoke when logging.
+   * Adds named callbacks to be executed when logging.
+   * @param  {Object } newCallbacks An object containing named callback 
functions.
    */
-  function setLogMapper(callback) {
-    mapHandler = callback;
+  function addCallbacks() {
+    for (var _len = arguments.length, newCallbacks = new Array(_len), _key = 
0; _key < _len; _key++) {
+      newCallbacks[_key] = arguments[_key];
+    }
+    newCallbacks.forEach(function (source) {
+      var descriptors = Object.keys(source).reduce(function (descriptors, key) 
{
+        descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
+        return descriptors;
+      }, {});
+      Object.getOwnPropertySymbols(source).forEach(function (sym) {
+        var descriptor = Object.getOwnPropertyDescriptor(source, sym);
+        if (descriptor.enumerable) {
+          descriptors[sym] = descriptor;
+        }
+      });
+      Object.defineProperties(cbHandlers, descriptors);
+    });
+    return cbHandlers;
   }
 
   /**
@@ -454,8 +448,7 @@
   function initPackager(newLogs, newConfig) {
     logs$1 = newLogs;
     config$1 = newConfig;
-    filterHandler = null;
-    mapHandler = null;
+    cbHandlers = [];
     intervalID = null;
     intervalType = null;
     intervalPath = null;
@@ -500,11 +493,14 @@
       'useraleVersion': config$1.useraleVersion,
       'sessionID': config$1.sessionID
     };
-    if (typeof filterHandler === 'function' && !filterHandler(log)) {
-      return false;
-    }
-    if (typeof mapHandler === 'function') {
-      log = mapHandler(log, e);
+    for (var _i = 0, _Object$values = Object.values(cbHandlers); _i < 
_Object$values.length; _i++) {
+      var func = _Object$values[_i];
+      if (typeof func === 'function') {
+        log = func(log, e);
+        if (!log) {
+          return false;
+        }
+      }
     }
     logs$1.push(log);
     return true;
@@ -542,11 +538,22 @@
       'sessionID': config$1.sessionID
     };
     var log = Object.assign(metaData, customLog);
-    if (typeof filterHandler === 'function' && !filterHandler(log)) {
-      return false;
-    }
-    if (typeof mapHandler === 'function') {
-      log = mapHandler(log);
+    var _iterator = _createForOfIteratorHelper(cbHandlers.values()),
+      _step;
+    try {
+      for (_iterator.s(); !(_step = _iterator.n()).done;) {
+        var func = _step.value;
+        if (typeof func === 'function') {
+          log = func(log, null);
+          if (!log) {
+            return false;
+          }
+        }
+      }
+    } catch (err) {
+      _iterator.e(err);
+    } finally {
+      _iterator.f();
     }
     logs$1.push(log);
     return true;
@@ -611,11 +618,22 @@
         'useraleVersion': config$1.useraleVersion,
         'sessionID': config$1.sessionID
       };
-      if (typeof filterHandler === 'function' && !filterHandler(intervalLog)) {
-        return false;
-      }
-      if (typeof mapHandler === 'function') {
-        intervalLog = mapHandler(intervalLog, e);
+      var _iterator2 = _createForOfIteratorHelper(cbHandlers.values()),
+        _step2;
+      try {
+        for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
+          var func = _step2.value;
+          if (typeof func === 'function') {
+            intervalLog = func(intervalLog, null);
+            if (!intervalLog) {
+              return false;
+            }
+          }
+        }
+      } catch (err) {
+        _iterator2.e(err);
+      } finally {
+        _iterator2.f();
       }
       logs$1.push(intervalLog);
 
@@ -1127,12 +1145,11 @@
     }
   }
 
+  exports.addCallbacks = addCallbacks;
   exports.buildPath = buildPath;
   exports.details = defineCustomDetails;
-  exports.filter = setLogFilter;
   exports.getSelector = getSelector;
   exports.log = log;
-  exports.map = setLogMapper;
   exports.options = options;
   exports.packageCustomLog = packageCustomLog;
   exports.packageLog = packageLog;
diff --git a/build/userale-2.3.0.min.js b/build/userale-2.3.0.min.js
index 0f1d734..82396de 100644
--- a/build/userale-2.3.0.min.js
+++ b/build/userale-2.3.0.min.js
@@ -16,4 +16,4 @@
  * @preserved
  */
 
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof 
module?t(exports):"function"==typeof 
define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof 
globalThis?globalThis:e||self).userale={})}(this,(function(e){"use 
strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof 
Symbol.iterator?function(e){return typeof e}:function(e){return 
e&&"function"==typeof 
Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof 
e},t(e)}var n="2.3.0",o=null;fu [...]
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof 
module?t(exports):"function"==typeof 
define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof 
globalThis?globalThis:e||self).userale={})}(this,(function(e){"use 
strict";function t(e){return t="function"==typeof Symbol&&"symbol"==typeof 
Symbol.iterator?function(e){return typeof e}:function(e){return 
e&&"function"==typeof 
Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof 
e},t(e)}var n="2.3.0",o=null;fu [...]
diff --git a/example/index.js b/example/index.js
index 21d5113..11af64a 100644
--- a/example/index.js
+++ b/example/index.js
@@ -34,10 +34,12 @@ window.userale.options({
  * Note that for surgical filters, you may need to clear or reset back to a 
global filter callback
  * the same is true for the 'map' API. See examples below:
  */
-window.userale.filter(function (log) {
-    var type_array = ['mouseup', 'mouseover', 'mousedown', 'keydown', 
'dblclick', 'blur', 'focus', 'input', 'wheel'];
-    var logType_array = ['interval'];
-    return !type_array.includes(log.type) && 
!logType_array.includes(log.logType);
+window.userale.addCallbacks({
+    filter(log) {
+        var type_array = ['mouseup', 'mouseover', 'mousedown', 'keydown', 
'dblclick', 'blur', 'focus', 'input', 'wheel'];
+        var logType_array = ['interval'];
+        return !type_array.includes(log.type) && 
!logType_array.includes(log.logType);
+    }
 });
 
 /**Log Mapping API
@@ -45,17 +47,13 @@ window.userale.filter(function (log) {
  * the 'map' API allows you to add or modify new fields to your logs
  * this example works with the "Click Me!" button at the top of index.html
  */
-document.addEventListener('click', function(e){
-    if (e.target.innerHTML === 'Click Me!') {
-        window.userale.map(function (log) {
+window.userale.addCallbacks({
+    map(log, e) {
+        if(e && e.type === 'click' && e.target.innerHTML === 'Click Me!') {
             return Object.assign({}, log, { logType: 'custom', customLabel: 
'map & packageLog Example' });
-        });
-        window.userale.packageLog(e, 
window.userale.details(window.userale.options(),e.type));
-        /**you'll want to reset the map callback function, or set a 
conditional (e.g., return log), else
-         * the callback may be applied to other events of the same class 
(e.g., click) */
-        window.userale.map();
-    } else {
-        return false
+        }
+
+        return log;
     }
 });
 
@@ -108,14 +106,14 @@ document.addEventListener('change', function(e) {
 document.addEventListener('change', function(e){
     if (e.target.value === 'packageLog') {
         /**You can then use the 'Mapping' API function to modify custom logs 
created with the packageLog function*/
-        window.userale.map(function (log) {
+        window.userale.addCallbacks({changeMap(log) {
             var targetsForLabels = ['change'];
             if (targetsForLabels.includes(log.type)) {
                 return Object.assign({}, log, { logType: 'custom', 
customLabel: 'packageLog Example' });
             } else {
                 return log;
             }
-        });
+        }});
         /**You can also use the details function to package additional log 
meta data, or add custom details*/
         window.userale.packageLog(e, 
window.userale.details(window.userale.options(),e.type));
     } else {
diff --git a/src/UserALEWebExtension/content.js 
b/src/UserALEWebExtension/content.js
index be80806..7ede7a6 100644
--- a/src/UserALEWebExtension/content.js
+++ b/src/UserALEWebExtension/content.js
@@ -19,7 +19,7 @@
 
 import * as globals from './globals';
 import * as MessageTypes from './messageTypes.js';
-import { filter, options, start } from '../main.js';
+import { addCallbacks, options, start } from '../main.js';
 
 // browser is defined in firefox, but not in chrome. In chrome, they use
 // the 'chrome' global instead. Let's map it to browser so we don't have
@@ -55,12 +55,13 @@ function queueLog(log) {
 function injectScript(config) {
   options(config);
 //  start();  not necessary given that autostart in place, and option is 
masked from WebExt users
-  filter(function (log) {
+  addCallbacks({function (log) {
     queueLog(Object.assign({}, log, {
       pageUrl: document.location.href,
     }));
+    console.log(log);
     return false;
-  });
+  }});
 }
 
 browser.runtime.onMessage.addListener(function (message) {
diff --git a/src/main.js b/src/main.js
index aa5e52a..f9b9fee 100644
--- a/src/main.js
+++ b/src/main.js
@@ -33,8 +33,7 @@ window.onload = function () {
 export let started = false;
 export {defineCustomDetails as details} from './attachHandlers.js';
 export {
-    setLogMapper as map,
-    setLogFilter as filter,
+    addCallbacks as addCallbacks,
     packageLog as packageLog,
     packageCustomLog as packageCustomLog,
     getSelector as getSelector,
diff --git a/src/packageLogs.js b/src/packageLogs.js
index d2e4cee..7c4629a 100644
--- a/src/packageLogs.js
+++ b/src/packageLogs.js
@@ -29,26 +29,42 @@ let intervalTimer;
 let intervalCounter;
 let intervalLog;
 
-export let filterHandler = null;
-export let mapHandler = null;
+export let cbHandlers = {};
 
 /**
- * Assigns a handler to filter logs out of the queue.
- * @param  {Function} callback The handler to invoke when logging.
+ * Adds named callbacks to be executed when logging.
+ * @param  {Object } newCallbacks An object containing named callback 
functions.
  */
-export function setLogFilter(callback) {
-  filterHandler = callback;
+export function addCallbacks(...newCallbacks) {
+  newCallbacks.forEach((source) => {
+    const descriptors = Object.keys(source).reduce((descriptors, key) => {
+      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
+      return descriptors;
+    }, {});
+
+    Object.getOwnPropertySymbols(source).forEach((sym) => {
+      const descriptor = Object.getOwnPropertyDescriptor(source, sym);
+      if (descriptor.enumerable) {
+        descriptors[sym] = descriptor;
+      }
+    });
+    Object.defineProperties(cbHandlers, descriptors);
+  });
+  return cbHandlers;
 }
 
 /**
- * Assigns a handler to transform logs from their default structure.
- * @param  {Function} callback The handler to invoke when logging.
+ * Removes callbacks by name.
+ * @param  {String[]} targetKeys A list of names of functions to remove.
  */
-export function setLogMapper(callback) {
-  mapHandler = callback;
+export function removeCallbacks(targetKeys) {
+  targetKeys.forEach(key => {
+    if(Object.hasOwn(cbHandlers, key)) {
+      delete cbHandlers[key];
+    }
+  });
 }
 
-
 /**
  * Assigns the config and log container to be used by the logging functions.
  * @param  {Array} newLogs   Log container.
@@ -57,8 +73,7 @@ export function setLogMapper(callback) {
 export function initPackager(newLogs, newConfig) {
   logs = newLogs;
   config = newConfig;
-  filterHandler = null;
-  mapHandler = null;
+  cbHandlers = [];
   intervalID = null;
   intervalType = null;
   intervalPath = null;
@@ -109,16 +124,16 @@ export function packageLog(e, detailFcn) {
     'sessionID': config.sessionID,
   };
 
-  if ((typeof filterHandler === 'function') && !filterHandler(log)) {
-    return false;
-  }
-
-  if (typeof mapHandler === 'function') {
-    log = mapHandler(log, e);
+  for (const func of Object.values(cbHandlers)) {
+    if (typeof func === 'function') {
+      log = func(log, e);
+      if(!log) {
+        return false;
+      }
+    }
   }
 
   logs.push(log);
-
   return true;
 }
 
@@ -158,12 +173,13 @@ export function packageCustomLog(customLog, detailFcn, 
userAction) {
 
     let log = Object.assign(metaData, customLog);
 
-    if ((typeof filterHandler === 'function') && !filterHandler(log)) {
-        return false;
-    }
-
-    if (typeof mapHandler === 'function') {
-        log = mapHandler(log);
+    for (const func of cbHandlers.values()) {
+      if (typeof func === 'function') {
+        log = func(log, null);
+        if(!log) {
+          return false;
+        }
+      }
     }
 
     logs.push(log);
@@ -231,12 +247,13 @@ export function packageIntervalLog(e) {
             'sessionID': config.sessionID
         };
 
-        if (typeof filterHandler === 'function' && 
!filterHandler(intervalLog)) {
-          return false;
-        }
-
-        if (typeof mapHandler === 'function') {
-          intervalLog = mapHandler(intervalLog, e);
+        for (const func of cbHandlers.values()) {
+          if (typeof func === 'function') {
+            intervalLog = func(intervalLog, null);
+            if(!intervalLog) {
+              return false;
+            }
+          }
         }
 
         logs.push(intervalLog);
diff --git a/test/packageLogs_spec.js b/test/packageLogs_spec.js
index 51aae05..def256b 100644
--- a/test/packageLogs_spec.js
+++ b/test/packageLogs_spec.js
@@ -18,44 +18,59 @@ import {expect} from 'chai';
 import {JSDOM} from 'jsdom';
 import 'global-jsdom/register'
 import {
+    addCallbacks,
     buildPath,
+    cbHandlers,
     extractTimeFields,
-    filterHandler,
     getLocation,
     getSelector,
     initPackager,
     logs,
-    mapHandler,
     packageLog,
+    removeCallbacks,
     selectorizePath,
-    setLogFilter,
-    setLogMapper,
 } from '../src/packageLogs';
 
 describe('packageLogs', () => {
-    describe('setLogFilter', () => {
-        it('assigns the handler to the provided value', () => {
-            const func = x => true;
-            setLogFilter(func);
-            expect(filterHandler).to.equal(func);
+    describe('addCallbacks', () => {
+        it('adds a single callback', () => {
+            initPackager([], {on: false});
+            const fn = {
+                func1() {return true}
+            };
+            addCallbacks(fn);
+            expect(Object.keys(cbHandlers)).to.deep.equal(Object.keys(fn));
         });
-        it('allows the handler to be nulled', () => {
-            setLogFilter(x => true);
-            setLogFilter(null);
-            expect(filterHandler).to.equal(null);
+        it('adds a list of callbacks', () => {
+            initPackager([], {on: false});
+
+            const fns = {
+                func1() {return true},
+                func2() {return false}
+            };
+
+            addCallbacks(fns);
+            expect(Object.keys(cbHandlers)).to.deep.equal(Object.keys(fns));
         });
     });
-
-    describe('setLogMapper', () => {
-        it('assigns the handler to the provided value', () => {
-            const func = x => true;
-            setLogMapper(func);
-            expect(mapHandler).to.equal(func);
+    
+    describe('removeCallbacks', () => {
+        it('removes a single callback', () => {
+            initPackager([], {on: false});
+            const fn = {func() {return true}}; 
+            addCallbacks(fn);
+            removeCallbacks(Object.keys(fn));
+            expect(cbHandlers).to.be.empty;
         });
-        it('allows the handler to be nulled', () => {
-            setLogMapper(x => true);
-            setLogMapper(null);
-            expect(mapHandler).to.equal(null);
+        it('removes a list of callbacks', () => {
+            initPackager([], {on: false});
+            const fns = {
+                func1() {return true},
+                func2() {return false}
+            };
+            addCallbacks(fns);
+            removeCallbacks(Object.keys(fns));
+            expect(cbHandlers).to.be.empty;
         });
     });
 
@@ -90,9 +105,11 @@ describe('packageLogs', () => {
 
         it('filters logs when a handler is assigned and returns false', () => {
             let filterCalled = false;
-            const filter = (log) => {
-                filterCalled = true;
-                return false;
+            const filter = {
+                filterAll() {
+                    filterCalled = true;
+                    return false;
+                }
             };
 
             const evt = {
@@ -105,19 +122,22 @@ describe('packageLogs', () => {
 
             expect(logs.length).to.equal(1);
 
-            setLogFilter(filter);
+            addCallbacks(filter);
             packageLog(evt);
 
+            expect(filterCalled).to.equal(true);
             expect(logs.length).to.equal(1);
         });
 
-        it('assigns logs to the mapper\'s return value if a handler is 
assigned', () => {
+        it('assigns logs to the callback\'s return value if a handler is 
assigned', () => {
             let mapperCalled = false;
 
             const mappedLog = {type: 'foo'};
-            const mapper = (log) => {
-                mapperCalled = true;
-                return mappedLog;
+            const mapper = {
+                mapper() {
+                    mapperCalled = true;
+                    return mappedLog;
+                }
             };
 
             const evt = {
@@ -127,14 +147,14 @@ describe('packageLogs', () => {
 
             initPackager([], {on: true});
 
-            setLogMapper(mapper);
+            addCallbacks(mapper);
             packageLog(evt);
 
             expect(mapperCalled).to.equal(true);
             expect(logs.indexOf(mappedLog)).to.equal(0);
         });
 
-        it('does not call the map handler if the log is filtered out', () => {
+        it('does not call a subsequent handler if the log is filtered out', () 
=> {
             let mapperCalled = false;
             const filter = () => false;
             const mapper = (log) => {
@@ -148,8 +168,8 @@ describe('packageLogs', () => {
             };
 
             initPackager([], {on: true});
-            setLogFilter(filter);
-            setLogMapper(mapper);
+            addCallbacks(filter);
+            addCallbacks(mapper);
 
             packageLog(evt);
 
@@ -157,35 +177,16 @@ describe('packageLogs', () => {
         });
 
         it('does not attempt to call a non-function filter/mapper', () => {
-            let filterCalled = false;
-            let mapperCalled = false;
-            const filter = () => {
-                filterCalled = true;
-                return true;
-            };
-            const mapper = (log) => {
-                mapperCalled = true;
-                return log;
-            };
-
             const evt = {
                 target: {},
                 type: 'test',
             };
 
             initPackager([], {on: true});
-            setLogFilter(filter);
-            setLogMapper(mapper);
-
             packageLog(evt);
-
-            expect(filterCalled).to.equal(true);
-            expect(mapperCalled).to.equal(true);
-
-            setLogFilter('foo');
-            setLogMapper('bar');
-
+            addCallbacks('foo');
             packageLog(evt);
+
             expect(logs.length).to.equal(2);
         });
     });

Reply via email to