lightstreamer-client-web
Version:
This package includes the resources needed to write a Lightstreamer client.
1,278 lines (1,191 loc) • 1.28 MB
JavaScript
/**
* @preserve
* LIGHTSTREAMER - www.lightstreamer.com
* Lightstreamer Web Client
* Version 9.2.3+20250225
* Copyright (c) Lightstreamer Srl. All Rights Reserved.
* Contains: LightstreamerClient, Subscription, ConsoleLogLevel,
* ConsoleLoggerProvider, MpnDevice, MpnSubscription, SafariMpnBuilder,
* FirebaseMpnBuilder, Chart, DynaGrid, SimpleChartListener,
* StaticGrid, StatusWidget, Logger, LoggerProvider,
* ClientListener, ClientMessageListener, ItemUpdate, SubscriptionListener,
* MpnDeviceListener, MpnSubscriptionListener, ChartListener, DynaGridListener,
* StaticGridListener
* ESM
*/
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getAugmentedNamespace(n) {
if (n.__esModule) return n;
var f = n.default;
if (typeof f == "function") {
var a = function a () {
if (this instanceof a) {
return Reflect.construct(f, arguments, this.constructor);
}
return f.apply(this, arguments);
};
a.prototype = f.prototype;
} else a = {};
Object.defineProperty(a, '__esModule', {value: true});
Object.keys(n).forEach(function (k) {
var d = Object.getOwnPropertyDescriptor(n, k);
Object.defineProperty(a, k, d.get ? d : {
enumerable: true,
get: function () {
return n[k];
}
});
});
return a;
}
const createCache = (lastNumberWeakMap) => {
return (collection, nextNumber) => {
lastNumberWeakMap.set(collection, nextNumber);
return nextNumber;
};
};
/*
* The value of the constant Number.MAX_SAFE_INTEGER equals (2 ** 53 - 1) but it
* is fairly new.
*/
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER === undefined ? 9007199254740991 : Number.MAX_SAFE_INTEGER;
const TWO_TO_THE_POWER_OF_TWENTY_NINE = 536870912;
const TWO_TO_THE_POWER_OF_THIRTY = TWO_TO_THE_POWER_OF_TWENTY_NINE * 2;
const createGenerateUniqueNumber = (cache, lastNumberWeakMap) => {
return (collection) => {
const lastNumber = lastNumberWeakMap.get(collection);
/*
* Let's try the cheapest algorithm first. It might fail to produce a new
* number, but it is so cheap that it is okay to take the risk. Just
* increase the last number by one or reset it to 0 if we reached the upper
* bound of SMIs (which stands for small integers). When the last number is
* unknown it is assumed that the collection contains zero based consecutive
* numbers.
*/
let nextNumber = lastNumber === undefined ? collection.size : lastNumber < TWO_TO_THE_POWER_OF_THIRTY ? lastNumber + 1 : 0;
if (!collection.has(nextNumber)) {
return cache(collection, nextNumber);
}
/*
* If there are less than half of 2 ** 30 numbers stored in the collection,
* the chance to generate a new random number in the range from 0 to 2 ** 30
* is at least 50%. It's benifitial to use only SMIs because they perform
* much better in any environment based on V8.
*/
if (collection.size < TWO_TO_THE_POWER_OF_TWENTY_NINE) {
while (collection.has(nextNumber)) {
nextNumber = Math.floor(Math.random() * TWO_TO_THE_POWER_OF_THIRTY);
}
return cache(collection, nextNumber);
}
// Quickly check if there is a theoretical chance to generate a new number.
if (collection.size > MAX_SAFE_INTEGER) {
throw new Error('Congratulations, you created a collection of unique numbers which uses all available integers!');
}
// Otherwise use the full scale of safely usable integers.
while (collection.has(nextNumber)) {
nextNumber = Math.floor(Math.random() * MAX_SAFE_INTEGER);
}
return cache(collection, nextNumber);
};
};
const LAST_NUMBER_WEAK_MAP = new WeakMap();
const cache = createCache(LAST_NUMBER_WEAK_MAP);
const generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
const isCallNotification = (message) => {
return message.method !== undefined && message.method === 'call';
};
const isClearResponse = (message) => {
return message.error === null && typeof message.id === 'number';
};
const load = (url) => {
// Prefilling the Maps with a function indexed by zero is necessary to be compliant with the specification.
const scheduledIntervalFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
const scheduledTimeoutFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
const unrespondedRequests = new Map();
const worker = new Worker(url);
worker.addEventListener('message', ({ data }) => {
if (isCallNotification(data)) {
const { params: { timerId, timerType } } = data;
if (timerType === 'interval') {
const idOrFunc = scheduledIntervalFunctions.get(timerId);
if (typeof idOrFunc === 'number') {
const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
if (timerIdAndTimerType === undefined ||
timerIdAndTimerType.timerId !== timerId ||
timerIdAndTimerType.timerType !== timerType) {
throw new Error('The timer is in an undefined state.');
}
}
else if (typeof idOrFunc !== 'undefined') {
idOrFunc();
}
else {
throw new Error('The timer is in an undefined state.');
}
}
else if (timerType === 'timeout') {
const idOrFunc = scheduledTimeoutFunctions.get(timerId);
if (typeof idOrFunc === 'number') {
const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
if (timerIdAndTimerType === undefined ||
timerIdAndTimerType.timerId !== timerId ||
timerIdAndTimerType.timerType !== timerType) {
throw new Error('The timer is in an undefined state.');
}
}
else if (typeof idOrFunc !== 'undefined') {
idOrFunc();
// A timeout can be savely deleted because it is only called once.
scheduledTimeoutFunctions.delete(timerId);
}
else {
throw new Error('The timer is in an undefined state.');
}
}
}
else if (isClearResponse(data)) {
const { id } = data;
const timerIdAndTimerType = unrespondedRequests.get(id);
if (timerIdAndTimerType === undefined) {
throw new Error('The timer is in an undefined state.');
}
const { timerId, timerType } = timerIdAndTimerType;
unrespondedRequests.delete(id);
if (timerType === 'interval') {
scheduledIntervalFunctions.delete(timerId);
}
else {
scheduledTimeoutFunctions.delete(timerId);
}
}
else {
const { error: { message } } = data;
throw new Error(message);
}
});
const clearInterval = (timerId) => {
const id = generateUniqueNumber(unrespondedRequests);
unrespondedRequests.set(id, { timerId, timerType: 'interval' });
scheduledIntervalFunctions.set(timerId, id);
worker.postMessage({
id,
method: 'clear',
params: { timerId, timerType: 'interval' }
});
};
const clearTimeout = (timerId) => {
const id = generateUniqueNumber(unrespondedRequests);
unrespondedRequests.set(id, { timerId, timerType: 'timeout' });
scheduledTimeoutFunctions.set(timerId, id);
worker.postMessage({
id,
method: 'clear',
params: { timerId, timerType: 'timeout' }
});
};
const setInterval = (func, delay = 0) => {
const timerId = generateUniqueNumber(scheduledIntervalFunctions);
scheduledIntervalFunctions.set(timerId, () => {
func();
// Doublecheck if the interval should still be rescheduled because it could have been cleared inside of func().
if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
worker.postMessage({
id: null,
method: 'set',
params: {
delay,
now: performance.now(),
timerId,
timerType: 'interval'
}
});
}
});
worker.postMessage({
id: null,
method: 'set',
params: {
delay,
now: performance.now(),
timerId,
timerType: 'interval'
}
});
return timerId;
};
const setTimeout = (func, delay = 0) => {
const timerId = generateUniqueNumber(scheduledTimeoutFunctions);
scheduledTimeoutFunctions.set(timerId, func);
worker.postMessage({
id: null,
method: 'set',
params: {
delay,
now: performance.now(),
timerId,
timerType: 'timeout'
}
});
return timerId;
};
return {
clearInterval,
clearTimeout,
setInterval,
setTimeout
};
};
const createLoadOrReturnBroker = (loadBroker, worker) => {
let broker = null;
return () => {
if (broker !== null) {
return broker;
}
const blob = new Blob([worker], { type: 'application/javascript; charset=utf-8' });
const url = URL.createObjectURL(blob);
broker = loadBroker(url);
// Bug #1: Edge up until v18 didn't like the URL to be revoked directly.
setTimeout(() => URL.revokeObjectURL(url));
return broker;
};
};
// This is the minified and stringified code of the worker-timers-worker package.
const worker = `(()=>{"use strict";const e=new Map,t=new Map,r=(e,t)=>{let r,o;const i=performance.now();r=i,o=e-Math.max(0,i-t);return{expected:r+o,remainingDelay:o}},o=(e,t,r,i)=>{const s=performance.now();s>r?postMessage({id:null,method:"call",params:{timerId:t,timerType:i}}):e.set(t,setTimeout(o,r-s,e,t,r,i))};addEventListener("message",(i=>{let{data:s}=i;try{if("clear"===s.method){const{id:r,params:{timerId:o,timerType:i}}=s;if("interval"===i)(t=>{const r=e.get(t);if(void 0===r)throw new Error('There is no interval scheduled with the given id "'.concat(t,'".'));clearTimeout(r),e.delete(t)})(o),postMessage({error:null,id:r});else{if("timeout"!==i)throw new Error('The given type "'.concat(i,'" is not supported'));(e=>{const r=t.get(e);if(void 0===r)throw new Error('There is no timeout scheduled with the given id "'.concat(e,'".'));clearTimeout(r),t.delete(e)})(o),postMessage({error:null,id:r})}}else{if("set"!==s.method)throw new Error('The given method "'.concat(s.method,'" is not supported'));{const{params:{delay:i,now:n,timerId:a,timerType:d}}=s;if("interval"===d)((t,i,s)=>{const{expected:n,remainingDelay:a}=r(t,s);e.set(i,setTimeout(o,a,e,i,n,"interval"))})(i,a,n);else{if("timeout"!==d)throw new Error('The given type "'.concat(d,'" is not supported'));((e,i,s)=>{const{expected:n,remainingDelay:a}=r(e,s);t.set(i,setTimeout(o,a,t,i,n,"timeout"))})(i,a,n)}}}}catch(e){postMessage({error:{message:e.message},id:s.id,result:null})}}))})();`; // tslint:disable-line:max-line-length
const loadOrReturnBroker = createLoadOrReturnBroker(load, worker);
const clearInterval$1 = (timerId) => loadOrReturnBroker().clearInterval(timerId);
const clearTimeout = (timerId) => loadOrReturnBroker().clearTimeout(timerId);
const setInterval$1 = (...args) => loadOrReturnBroker().setInterval(...args);
const setTimeout$1 = (...args) => loadOrReturnBroker().setTimeout(...args);
var workerTimers = /*#__PURE__*/Object.freeze({
__proto__: null,
clearInterval: clearInterval$1,
clearTimeout: clearTimeout,
setInterval: setInterval$1,
setTimeout: setTimeout$1
});
var require$$0 = /*@__PURE__*/getAugmentedNamespace(workerTimers);
var jsonpatch = {exports: {}};
/* @preserve
* JSONPatch.js
*
* A Dharmafly project written by Thomas Parslow
* <tom@almostobsolete.net> and released with the kind permission of
* NetDev.
*
* Copyright 2011-2013 Thomas Parslow. All rights reserved.
* Permission is hereby granted,y free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Implements the JSON Patch IETF RFC 6902 as specified at:
*
* http://tools.ietf.org/html/rfc6902
*
* Also implements the JSON Pointer IETF RFC 6901 as specified at:
*
* http://tools.ietf.org/html/rfc6901
*
*/
var hasRequiredJsonpatch;
function requireJsonpatch () {
if (hasRequiredJsonpatch) return jsonpatch.exports;
hasRequiredJsonpatch = 1;
(function (module, exports) {
(function (root, factory) {
{
// Node
factory(module.exports);
}
}(commonjsGlobal, function (exports) {
var JSONPatch, JSONPointer,_operationRequired,isArray;
// Taken from underscore.js
isArray = Array.isArray || function(obj) {
return Object.prototype.toString.call(obj) == '[object Array]';
};
/* Public: Shortcut to apply a patch the document without having to
* create a patch object first. Returns the patched document. Does
* not damage the original document, but will reuse parts of its
* structure in the new one.
*
* doc - The target document to which the patch should be applied.
* patch - A JSON Patch document specifying the changes to the
* target documentment
*
* Example (node.js)
*
* jsonpatch = require('jsonpatch');
* doc = JSON.parse(sourceJSON);
* doc = jsonpatch.apply_patch(doc, thepatch);
* destJSON = JSON.stringify(doc);
*
* Example (in browser)
*
* <script src="jsonpatch.js" type="text/javascript"></script>
* <script type="application/javascript">
* doc = JSON.parse(sourceJSON);
* doc = jsonpatch.apply_patch(doc, thepatch);
* destJSON = JSON.stringify(doc);
* </script>
*
* Returns the patched document
*/
exports.apply_patch = function (doc, patch) {
return (new JSONPatch(patch)).apply(doc);
};
/* Public: Error thrown if the patch supplied is invalid.
*/
function InvalidPatch(message) {
Error.call(this, message); this.message = message;
}
exports.InvalidPatch = InvalidPatch;
InvalidPatch.prototype = new Error();
/* Public: Error thrown if the patch can not be apllied to the given document
*/
function PatchApplyError(message) {
Error.call(this, message); this.message = message;
}
exports.PatchApplyError = PatchApplyError;
PatchApplyError.prototype = new Error();
/* Public: A class representing a JSON Pointer. A JSON Pointer is
* used to point to a specific sub-item within a JSON document.
*
* Example (node.js);
*
* jsonpatch = require('jsonpatch');
* var pointer = new jsonpatch.JSONPointer('/path/to/item');
* var item = pointer.follow(doc)
*
*/
exports.JSONPointer = JSONPointer = function JSONPointer (pathStr) {
var i,split,path=[];
// Split up the path
split = pathStr.split('/');
if ('' !== split[0]) {
throw new InvalidPatch('JSONPointer must start with a slash (or be an empty string)!');
}
for (i = 1; i < split.length; i++) {
path[i-1] = split[i].replace(/~1/g,'/').replace(/~0/g,'~');
}
this.path = path;
this.length = path.length;
};
/* Private: Get a segment of the pointer given a current doc
* context.
*/
JSONPointer.prototype._get_segment = function (index, node) {
var segment = this.path[index];
if(isArray(node)) {
if ('-' === segment) {
segment = node.length;
} else {
// Must be a non-negative integer in base-10 without leading zeros
if (!segment.match(/^0$|^[1-9][0-9]*$/)) {
throw new PatchApplyError('Expected a number to segment an array');
}
segment = parseInt(segment,10);
}
}
return segment;
};
// Return a shallow copy of an object
function clone(o) {
var cloned, key;
if (isArray(o)) {
return o.slice();
// typeof null is "object", but we want to copy it as null
} if (o === null) {
return o;
} else if (typeof o === "object") {
cloned = {};
for(key in o) {
if (Object.hasOwnProperty.call(o, key)) {
cloned[key] = o[key];
}
}
return cloned;
} else {
return o;
}
}
/* Private: Follow the pointer to its penultimate segment then call
* the handler with the current doc and the last key (converted to
* an int if the current doc is an array). The handler is expected to
* return a new copy of the penultimate part.
*
* doc - The document to search within
* handler - The callback function to handle the last part
*
* Returns the result of calling the handler
*/
JSONPointer.prototype._action = function (doc, handler, mutate) {
var that = this;
function follow_pointer(node, index) {
var segment, subnode;
if (!mutate) {
node = clone(node);
}
segment = that._get_segment(index, node);
// Is this the last segment?
if (index == that.path.length-1) {
node = handler(node, segment);
} else {
// Make sure we can follow the segment
if (isArray(node)) {
if (node.length <= segment) {
throw new PatchApplyError('Path not found in document');
}
} else if (typeof node === "object") {
if (!Object.hasOwnProperty.call(node, segment)) {
throw new PatchApplyError('Path not found in document');
}
} else {
throw new PatchApplyError('Path not found in document');
}
subnode = follow_pointer(node[segment], index+1);
if (!mutate) {
node[segment] = subnode;
}
}
return node;
}
return follow_pointer(doc, 0);
};
/* Public: Takes a JSON document and a value and adds the value into
* the doc at the position pointed to. If the position pointed to is
* in an array then the existing element at that position (if any)
* and all that follow it have their position incremented to make
* room. It is an error to add to a parent object that doesn't exist
* or to try to replace an existing value in an object.
*
* doc - The document to operate against. Will be mutated so should
* not be reused after the call.
* value - The value to insert at the position pointed to
*
* Examples
*
* var doc = new JSONPointer("/obj/new").add({obj: {old: "hello"}}, "world");
* // doc now equals {obj: {old: "hello", new: "world"}}
*
* Returns the updated doc (the value passed in may also have been mutated)
*/
JSONPointer.prototype.add = function (doc, value, mutate) {
// Special case for a pointer to the root
if (0 === this.length) {
return value;
}
return this._action(doc, function (node, lastSegment) {
if (isArray(node)) {
if (lastSegment > node.length) {
throw new PatchApplyError('Add operation must not attempt to create a sparse array!');
}
node.splice(lastSegment, 0, value);
} else {
node[lastSegment] = value;
}
return node;
}, mutate);
};
/* Public: Takes a JSON document and removes the value pointed to.
* It is an error to attempt to remove a value that doesn't exist.
*
* doc - The document to operate against. May be mutated so should
* not be reused after the call.
*
* Examples
*
* var doc = new JSONPointer("/obj/old").add({obj: {old: "hello"}});
* // doc now equals {obj: {}}
*
* Returns the updated doc (the value passed in may also have been mutated)
*/
JSONPointer.prototype.remove = function (doc, mutate) {
// Special case for a pointer to the root
if (0 === this.length) {
// Removing the root makes the whole value undefined.
// NOTE: Should it be an error to remove the root if it is
// ALREADY undefined? I'm not sure...
return undefined;
}
return this._action(doc, function (node, lastSegment) {
if (!Object.hasOwnProperty.call(node,lastSegment)) {
throw new PatchApplyError('Remove operation must point to an existing value!');
}
if (isArray(node)) {
node.splice(lastSegment, 1);
} else {
delete node[lastSegment];
}
return node;
}, mutate);
};
/* Public: Semantically equivalent to a remove followed by an add
* except when the pointer points to the root element in which case
* the whole document is replaced.
*
* doc - The document to operate against. May be mutated so should
* not be reused after the call.
*
* Examples
*
* var doc = new JSONPointer("/obj/old").replace({obj: {old: "hello"}}, "world");
* // doc now equals {obj: {old: "world"}}
*
* Returns the updated doc (the value passed in may also have been mutated)
*/
JSONPointer.prototype.replace = function (doc, value, mutate) {
// Special case for a pointer to the root
if (0 === this.length) {
return value;
}
return this._action(doc, function (node, lastSegment) {
if (!Object.hasOwnProperty.call(node,lastSegment)) {
throw new PatchApplyError('Replace operation must point to an existing value!');
}
if (isArray(node)) {
node.splice(lastSegment, 1, value);
} else {
node[lastSegment] = value;
}
return node;
}, mutate);
};
/* Public: Returns the value pointed to by the pointer in the given doc.
*
* doc - The document to operate against.
*
* Examples
*
* var value = new JSONPointer("/obj/value").get({obj: {value: "hello"}});
* // value now equals 'hello'
*
* Returns the value
*/
JSONPointer.prototype.get = function (doc) {
var value;
if (0 === this.length) {
return doc;
}
this._action(doc, function (node, lastSegment) {
if (!Object.hasOwnProperty.call(node,lastSegment)) {
throw new PatchApplyError('Path not found in document');
}
value = node[lastSegment];
return node;
}, true);
return value;
};
/* Public: returns true if this pointer points to a child of the
* other pointer given. Returns true if both point to the same place.
*
* otherPointer - Another JSONPointer object
*
* Examples
*
* var pointer1 = new JSONPointer('/animals/mammals/cats/holly');
* var pointer2 = new JSONPointer('/animals/mammals/cats');
* var isChild = pointer1.subsetOf(pointer2);
*
* Returns a boolean
*/
JSONPointer.prototype.subsetOf = function (otherPointer) {
if (this.length <= otherPointer.length) {
return false;
}
for (var i = 0; i < otherPointer.length; i++) {
if (otherPointer.path[i] !== this.path[i]) {
return false;
}
}
return true;
};
_operationRequired = {
add: ['value'],
replace: ['value'],
test: ['value'],
remove: [],
move: ['from'],
copy: ['from']
};
// Check if a is deep equal to b (by the rules given in the
// JSONPatch spec)
function deepEqual(a,b) {
var key;
if (a === b) {
return true;
} else if (typeof a !== typeof b) {
return false;
} else if ('object' === typeof(a)) {
var aIsArray = isArray(a),
bIsArray = isArray(b);
if (aIsArray !== bIsArray) {
return false;
} else if (aIsArray) {
// Both are arrays
if (a.length != b.length) {
return false;
} else {
for (var i = 0; i < a.length; i++) {
if(!deepEqual(a[i], b[i])) {
return false;
}
}
}
return true;
} else {
// Check each key of the object recursively
for(key in a) {
if (Object.hasOwnProperty(a, key)) {
if (!(Object.hasOwnProperty(b,key) && deepEqual(a[key], b[key]))) {
return false;
}
}
}
for(key in b) {
if(Object.hasOwnProperty(b,key) && !Object.hasOwnProperty(a, key)) {
return false;
}
}
return true;
}
} else {
return false;
}
}
function validateOp(operation) {
var i, required;
if (!operation.op) {
throw new InvalidPatch('Operation missing!');
}
if (!_operationRequired.hasOwnProperty(operation.op)) {
throw new InvalidPatch('Invalid operation!');
}
if (!('path' in operation)) {
throw new InvalidPatch('Path missing!');
}
required = _operationRequired[operation.op];
// Check that all required keys are present
for(i = 0; i < required.length; i++) {
if(!(required[i] in operation)) {
throw new InvalidPatch(operation.op + ' must have key ' + required[i]);
}
}
}
function compileOperation(operation, mutate) {
validateOp(operation);
var op = operation.op;
var path = new JSONPointer(operation.path);
var value = operation.value;
var from = operation.from ? new JSONPointer(operation.from) : null;
switch (op) {
case 'add':
return function (doc) {
return path.add(doc, value, mutate);
};
case 'remove':
return function (doc) {
return path.remove(doc, mutate);
};
case 'replace':
return function (doc) {
return path.replace(doc, value, mutate);
};
case 'move':
// Check that destination isn't inside the source
if (path.subsetOf(from)) {
throw new InvalidPatch('destination must not be a child of source');
}
return function (doc) {
var value = from.get(doc);
var intermediate = from.remove(doc, mutate);
return path.add(intermediate, value, mutate);
};
case 'copy':
return function (doc) {
var value = from.get(doc);
return path.add(doc, value, mutate);
};
case 'test':
return function (doc) {
if (!deepEqual(path.get(doc), value)) {
throw new PatchApplyError("Test operation failed. Value did not match.");
}
return doc;
};
}
}
/* Public: A class representing a patch.
*
* patch - The patch as an array or as a JSON string (containing an
* array)
* mutate - Indicates that input documents should be mutated
* (default is for the input to be unaffected.) This will
* not work correctly if the patch replaces the root of
* the document.
*/
exports.JSONPatch = JSONPatch = function JSONPatch(patch, mutate) {
this._compile(patch, mutate);
};
JSONPatch.prototype._compile = function (patch, mutate) {
var i, _this = this;
this.compiledOps = [];
if ('string' === typeof patch) {
patch = JSON.parse(patch);
}
if(!isArray(patch)) {
throw new InvalidPatch('Patch must be an array of operations');
}
for(i = 0; i < patch.length; i++) {
var compiled = compileOperation(patch[i], mutate);
_this.compiledOps.push(compiled);
}
};
/* Public: Apply the patch to a document and returns the patched
* document.
*
* doc - The document to which the patch should be applied.
*
* Returns the patched document
*/
exports.JSONPatch.prototype.apply = function (doc) {
var i;
for(i = 0; i < this.compiledOps.length; i++) {
doc = this.compiledOps[i](doc);
}
return doc;
};
}));
} (jsonpatch));
return jsonpatch.exports;
}
/**
* This is a dummy constructor not to be used in any case.
* @constructor
*
* @exports Logger
* @class Simple Interface to be implemented to produce log.
*/
var Logger = function() {
};
Logger.prototype = {
/**
* Receives log messages at FATAL level.
*
* @param {String} message The message to be logged.
* @param {Error} [exception] An Exception instance related to the current log message.
*
* @see LoggerProvider
*/
fatal: function(message,exception) {
},
/**
* Checks if this Logger is enabled for the FATAL level.
* The method should return true if this Logger is enabled for FATAL events,
* false otherwise.
* <BR>This property is intended to let the library save computational cost by suppressing the generation of
* log FATAL statements. However, even if the method returns false, FATAL log
* lines may still be received by the {@link Logger#fatal} method
* and should be ignored by the Logger implementation.
*
* @return {boolean} true if FATAL logging is enabled, false otherwise
*/
isFatalEnabled: function() {
},
/**
* Receives log messages at ERROR level.
*
* @param {String} message The message to be logged.
* @param {Error} [exception] An Exception instance related to the current log message.
*/
error: function(message,exception) {
},
/**
* Checks if this Logger is enabled for the ERROR level.
* The method should return true if this Logger is enabled for ERROR events,
* false otherwise.
* <BR>This property is intended to let the library save computational cost by suppressing the generation of
* log ERROR statements. However, even if the method returns false, ERROR log
* lines may still be received by the {@link Logger#error} method
* and should be ignored by the Logger implementation.
*
* @return {boolean} true if ERROR logging is enabled, false otherwise
*/
isErrorEnabled: function() {
},
/**
* Receives log messages at WARN level.
*
* @param {String} message The message to be logged.
* @param {Error} [exception] An Exception instance related to the current log message.
*/
warn: function(message,exception) {
},
/**
* Checks if this Logger is enabled for the WARN level.
* The method should return true if this Logger is enabled for WARN events,
* false otherwise.
* <BR>This property is intended to let the library save computational cost by suppressing the generation of
* log WARN statements. However, even if the method returns false, WARN log
* lines may still be received by the {@link Logger#warn} method
* and should be ignored by the Logger implementation.
*
* @return {boolean} true if WARN logging is enabled, false otherwise
*/
isWarnEnabled: function() {
},
/**
* Receives log messages at INFO level.
*
* @param {String} message The message to be logged.
* @param {Error} [exception] An Exception instance related to the current log message.
*/
info: function(message,exception) {
},
/**
* Checks if this Logger is enabled for the INFO level.
* The method should return true if this Logger is enabled for INFO events,
* false otherwise.
* <BR>This property is intended to let the library save computational cost by suppressing the generation of
* log INFO statements. However, even if the method returns false, INFO log
* lines may still be received by the {@link Logger#info} method
* and should be ignored by the Logger implementation.
*
* @return {boolean} true if INFO logging is enabled, false otherwise
*/
isInfoEnabled: function() {
},
/**
* Receives log messages at DEBUG level.
*
* @param {String} message The message to be logged.
* @param {Error} [exception] An Exception instance related to the current log message.
*/
debug: function(message,exception) {
},
/**
* Checks if this Logger is enabled for the DEBUG level.
* The method should return true if this Logger is enabled for DEBUG events,
* false otherwise.
* <BR>This property is intended to let the library save computational cost by suppressing the generation of
* log DEBUG statements. However, even if the method returns false, DEBUG log
* lines may still be received by the {@link Logger#debug} method
* and should be ignored by the Logger implementation.
*
* @return {boolean} true if DEBUG logging is enabled, false otherwise
*/
isDebugEnabled: function() {
},
/**
* Receives log messages at TRACE level.
*
* @param {String} message The message to be logged.
* @param {Error} [exception] An Exception instance related to the current log message.
*/
trace: function(message,exception) {
},
/**
* Checks if this Logger is enabled for the TRACE level.
* The method should return true if this Logger is enabled for TRACE events,
* false otherwise.
* <BR>This property is intended to let the library save computational cost by suppressing the generation of
* log TRACE statements. However, even if the method returns false, TRACE log
* lines may still be received by the {@link Logger#trace} method
* and should be ignored by the Logger implementation.
*
* @return {boolean} true if TRACE logging is enabled, false otherwise
*/
isTraceEnabled: function() {
}
};/**
* This is a dummy constructor not to be used in any case.
* @constructor
*
* @exports LoggerProvider
* @class Simple interface to be implemented to provide custom log producers.
*
* <BR>A simple implementation of this interface is included with this library:
* {@link ConsoleLoggerProvider}.
*/
var LoggerProvider = function() {
};
LoggerProvider.prototype = {
/**
* Invoked to request a {@link Logger} instance that will be used for logging occurring
* on the given category. It is suggested, but not mandatory, that subsequent
* calls to this method related to the same category return the same {@link Logger}
* instance.
*
* @param {String} category the log category all messages passed to the given
* Logger instance will pertain to.
*
* @return {Logger} A Logger instance that will receive log lines related to
* the given category.
*/
getLogger: function(category) {
}
};/**
* This is a dummy constructor not to be used in any case.
* @constructor
*
* @exports ClientListener
* @class Interface to be implemented to listen to {@link LightstreamerClient} events
* comprehending notifications of connection activity and errors.
* <BR>Events for these listeners are executed asynchronously with respect to the code
* that generates them. This means that, upon reception of an event, it is possible that
* the current state of the client has changed furtherly.
* <BR>Note that it is not necessary to implement all of the interface methods for
* the listener to be successfully passed to the {@link LightstreamerClient#addListener}
* method.
* <BR>A ClientListener implementation is distributed together with the library:
* {@link StatusWidget}.
*/
function ClientListener() {
}
ClientListener.prototype = {
/**
* Event handler that is called when the Server notifies a refusal on the
* client attempt to open a new connection or the interruption of a
* streaming connection. In both cases, the {@link ClientListener#onStatusChange}
* event handler has already been invoked with a "DISCONNECTED" status and
* no recovery attempt has been performed. By setting a custom handler, however,
* it is possible to override this and perform custom recovery actions.
*
* @param {Number} errorCode The error code. It can be one of the
* following:
* <ul>
* <li>1 - user/password check failed</li>
* <li>2 - requested Adapter Set not available</li>
* <li>7 - licensed maximum number of sessions reached
* (this can only happen with some licenses)</li>
* <li>8 - configured maximum number of sessions reached</li>
* <li>9 - configured maximum server load reached</li>
* <li>10 - new sessions temporarily blocked</li>
* <li>11 - streaming is not available because of Server license
* restrictions (this can only happen with special licenses)</li>
* <li>21 - a bind request has unexpectedly reached a wrong Server instance, which suggests that a routing issue may be in place</li>
* <li>30-41 - the current connection or the whole session has been closed
* by external agents; the possible cause may be:
* <ul>
* <li>The session was closed on the Server side (via software or by
* the administrator) (32) or through a client "destroy" request (31);</li>
* <li>The Metadata Adapter imposes limits on the overall open sessions
* for the current user and has requested the closure of the current session
* upon opening of a new session for the same user
* on a different browser window
* (35);</li>
* <li>An unexpected error occurred on the Server while the session was in
* activity (33, 34);</li>
* <li>An unknown or unexpected cause; any code different from the ones
* identified in the above cases could be issued.</li>
* </ul>
* A detailed description for the specific cause is currently not supplied
* (i.e. errorMessage is null in this case).</li>
* <li>60 - this version of the client is not allowed by the current license terms.</li>
* <li>61 - there was an error in the parsing of the server response thus the client cannot continue with the current session.</li>
* <li>66 - an unexpected exception was thrown by the Metadata Adapter while authorizing the connection.</li>
* <li>68 - the Server could not open or continue with the session because of an internal error.</li>
* <li>70 - an unusable port was configured on the server address.</li>
* <li>71 - this kind of client is not allowed by the current license terms.</li>
* <li><= 0 - the Metadata Adapter has refused the user connection;
* the code value is dependent on the specific Metadata Adapter
* implementation</li>
* </ul>
* @param {String} errorMessage The description of the error as sent
* by the Server.
*
* @see ConnectionDetails#setAdapterSet
* @see ClientListener#onStatusChange
*/
onServerError: function(errorCode, errorMessage) {
},
/**
* Event handler that receives a notification each time the LightstreamerClient
* status has changed. The status changes may be originated either by custom
* actions (e.g. by calling {@link LightstreamerClient#disconnect}) or by
* internal actions.
* <BR/><BR/>The normal cases are the following:
* <ul>
* <li>After issuing connect(), if the current status is "DISCONNECTED*", the
* client will switch to "CONNECTING" first and
* to "CONNECTED:STREAM-SENSING" as soon as the pre-flight request receives its
* answer.
* <BR>As soon as the new session is established, it will switch to
* "CONNECTED:WS-STREAMING" if the browser/environment permits WebSockets;
* otherwise it will switch to "CONNECTED:HTTP-STREAMING" if the
* browser/environment permits streaming or to "CONNECTED:HTTP-POLLING"
* as a last resort.
* <BR>On the other hand if the status is already "CONNECTED:*" a
* switch to "CONNECTING" is usually not needed.</li>
* <li>After issuing disconnect(), the status will switch to "DISCONNECTED".</li>
* <li>In case of a server connection refusal, the status may switch from
* "CONNECTING" directly to "DISCONNECTED". After that, the
* {@link ClientListener#onServerError} event handler will be invoked.</li>
* </ul>
* <BR/>Possible special cases are the following:
* <ul>
* <li>In case of Server unavailability during streaming, the status may
* switch from "CONNECTED:*-STREAMING" to "STALLED" (see
* {@link ConnectionOptions#setStalledTimeout}).
* If the unavailability ceases, the status will switch back to
* ""CONNECTED:*-STREAMING"";
* otherwise, if the unavailability persists (see
* {@link ConnectionOptions#setReconnectTimeout}),
* the status will switch to "DISCONNECTED:TRYING-RECOVERY" and eventually to
* "CONNECTED:*-STREAMING".</li>
* <li>In case the connection or the whole session is forcibly closed
* by the Server, the status may switch from "CONNECTED:*-STREAMING"
* or "CONNECTED:*-POLLING" directly to "DISCONNECTED". After that, the
* {@link ClientListener#onServerError} event handler will be invoked.</li>
* <li>Depending on the setting in {@link ConnectionOptions#setSlowingEnabled},
* in case of slow update processing, the status may switch from
* "CONNECTED:WS-STREAMING" to "CONNECTED:WS-POLLING" or from
* "CONNECTED:HTTP-STREAMING" to "CONNECTED:HTTP-POLLING".</li>
* <li>If the status is "CONNECTED:*-POLLING" and any problem during an
* intermediate poll occurs, the status may switch to "CONNECTING" and
* eventually to "CONNECTED:*-POLLING". The same may hold for the
* "CONNECTED:*-STREAMING" case, when a rebind is needed.</li>
* <li>In case a forced transport was set through
* {@link ConnectionOptions#setForcedTransport}, only the related final
* status or statuses are possible. Note that if the transport is forced
* while a Session is active and this requires a reconnection, the status
* may do a preliminary switch to CONNECTED:STREAM-SENSING.</li>
* <li>In case of connection problems, the status may switch from any value
* to "DISCONNECTED:WILL-RETRY" (see {@link ConnectionOptions#setRetryDelay}),
* then to "CONNECTING" and a new attempt will start.
* However, in most cases, the client will try to recover the current session;
* hence, the "DISCONNECTED:TRYING-RECOVERY" status will be entered
* and the recovery attempt will start.</li>
* <li>In case of connection problems during a recovery attempt, the status may stay
* in "DISCONNECTED:TRYING-RECOVERY" for long time, while further attempts are made.
* On the other hand, if the connection is successful, the status will do
* a preliminary switch to CONNECTED:STREAM-SENSING. If the recovery is finally
* unsuccessful, the current session will be abandoned and the status
* will switch to "DISCONNECTED:WILL-RETRY" before the next attempts.</li>
* </ul>
*
* <BR>By setting a custom handler it is possible to perform
* actions related to connection and disconnection occurrences. Note that
* {@link LightstreamerClient#connect} and {@link LightstreamerClient#disconnect},
* as any other method, can be issued directly from within a handler.
*
* @param {String} chngStatus The new status. It can be one of the
* following values:
* <ul>
* <li>"CONNECTING" the client has started a connection attempt and is
* waiting for a Server answer.</li>
* <li>"CONNECTED:STREAM-SENSING" the client received a first response from
* the server and is now evaluating if a streaming connection is fully
* functional. </li>
* <li>"CONNECTED:WS-STREAMING" a streaming connection over WebSocket has
* been established.</li>
* <li>"CONNECTED:HTTP-STREAMING" a streaming connection over HTTP has
* been established.</li>
* <li>"CONNECTED:WS-POLLING" a polling connection over WebSocket has
* been started. Note that, unlike polling over HTTP, in this case only one
* connection is actually opened (see {@link ConnectionOptions#setSlowingEnabled}).
* </li>
* <li>"CONNECTED:HTTP-POLLING" a polling connection over HTTP has
* been started.</li>
* <li>"STALLED" a streaming session has been silent for a while,
* the status will eventually return to its previous CONNECTED:*-STREAMING
* status or will switch to "DISCONNECTED:WILL-RETRY" / "DISCONNECTED:TRYING-RECOVERY".</li>
* <li>"DISCONNECTED:WILL-RETRY" a connection or connection attempt has been
* closed; a new attempt will be performed (possibly after a timeout).</li>
* <li>"DISCONNECTED:TRYING-RECOVERY" a connection has been closed and
* the client has started a connection attempt and is waiting for a Server answer;
* if successful, the underlying session will be kept.</li>
* <li>"DISCONNECTED" a connection or connection attempt has been closed. The
* client will not connect anymore until a new {@link LightstreamerClient#connect}
* call is issued.</li>
* </ul>
*
* @see LightstreamerClient#connect
* @see LightstreamerClient#disconnect
* @see LightstreamerClient#getStatus
*/
onStatusChange: function(chngStatus) {
},
/**
* Event handler that receives a notification each time the value of a property of
* {@link LightstreamerClient#connectionDetails} or {@link LightstreamerClient#connectionOptions}
* is changed.
*
* @param {String} the name of the changed property.
* <BR>Possible values are:
* <ul>
* <li>adapterSet</li>
* <li>serverAddress</li>
* <li>user</li>
* <li>password</li>
* <li>contentLength</li>
* <li>requestedMaxBandwidth</li>
* <li>reverseHeartbeatInterval</li>
* <li>httpExtraHeaders</li>
* <li>httpExtraHeadersOnSessionCreationOnly</li>
* <li>forcedTransport</li>
* <li>retryDelay</li>
* <li>firstRetryMaxDelay</li>
* <li>sessionRecoveryTimeout</li>
* <li>stalledTimeout</li>
* <li>reconnectTimeout</li>
* <li>slowingEnabled</li>
* <li>serverInstanceAddressIgnored</li>
* <li>cookieHandlingRequired</li>
* <li>proxy</li>
* <li>serverInstanceAddress</li>
* <li>serverSocketName</li>
* <li>clientIp</li>
* <li>sessionId</li>
* <li>realMaxBandwidth</li>
* <li>idleTimeout</li>
* <li>keepaliveInterval</li>
* <li>pollingInterval</li>
* </ul>
*
* @see LightstreamerClient#connectionDetails
* @see LightstreamerClient#connectionOptions
*/
onPropertyChange: function(propertyName) {
},
/**
* Event handler that receives a notification when the ClientListener instance
* is added to a LightstreamerClient through
* {@link LightstreamerClient#addListener}.
* This is the first event to be fired on the listener.
*/
onListenStart: function() {
},
/**
* Event handler that receives a notification when the ClientListener instance
* is removed from a LightstreamerClient through
* {@link LightstreamerClient#removeListener}.
* This is the last event to be fired on the listener.
*/
onListenEnd: function() {
},
/**
* Notifies that the Server has sent a keepalive message because a streaming connection
* is in place and no update had been sent for the configured time
* (see {@link ConnectionOptions#setKeepaliveInterval}).
* However, note that the lack of both updates and keepalives is already managed by the library
* (see {@link ConnectionOptions#setReconnectTimeout} and {@link ConnectionOptions#setStalledTimeout}).
*/
onServerKeepalive: function() {
}
};
/**
* This is a dummy cons