UNPKG

matssocket

Version:
657 lines 47 kB
/** * Creates a MatsSocket, requiring the using Application's name and version, and which URLs to connect to. * <p/> * Note: Public, Private and Privileged modelled after * <a href="http://crockford.com/javascript/private.html">http://crockford.com/javascript/private.html</a> * * @param {string} appName the name of the application using this MatsSocket.js client library * @param {string} appVersion the version of the application using this MatsSocket.js client library * @param {array} urls an array of WebSocket URLs speaking 'matssocket' protocol, or a single string URL. * @param {object} config an optional object carrying extra configuration. Current sole key: 'webSocketFactory': how to * make WebSockets, not required in a browser setting as it will use window.WebSocket if not set. * @class */ export function MatsSocket(appName: string, appVersion: string, urls: any[], config?: object): void; export class MatsSocket { /** * Creates a MatsSocket, requiring the using Application's name and version, and which URLs to connect to. * <p/> * Note: Public, Private and Privileged modelled after * <a href="http://crockford.com/javascript/private.html">http://crockford.com/javascript/private.html</a> * * @param {string} appName the name of the application using this MatsSocket.js client library * @param {string} appVersion the version of the application using this MatsSocket.js client library * @param {array} urls an array of WebSocket URLs speaking 'matssocket' protocol, or a single string URL. * @param {object} config an optional object carrying extra configuration. Current sole key: 'webSocketFactory': how to * make WebSockets, not required in a browser setting as it will use window.WebSocket if not set. * @class */ constructor(appName: string, appVersion: string, urls: any[], config?: object); /** * 'sessionId' is set when we get the SessionId from WELCOME, set back to undefined on SessionClose * (along with _matsSocketOpen = false) * * @type {string} */ sessionId: string; /** * Whether to log via console.log. The logging is quite extensive. <b>Default <code>false</code></b>. * * @type {boolean} */ logging: boolean; /** * Whether to log errors via console.error. <b>Default <code>true</code></b>. * * @type {boolean} */ errorLogging: boolean; /** * "Out-of-band Close" refers to a small hack to notify the server about a MatsSocketSession being Closed even * if the WebSocket is not live anymore: When {@link MatsSocket#close} is invoked, an attempt is done to close * the WebSocket with CloseCode {@link MatsSocketCloseCodes.CLOSE_SESSION} - but whether the WebSocket is open * or not, this "Out-of-band Close" will also be invoked if enabled and MatsSocket SessionId is present. * <p/> * Values: * <ul> * <li>"Falsy", e.g. <code>false</code>: Disables this functionality</li> * <li>A <code>function</code>: The function is invoked when close(..) is invoked, the * single parameter being an object with two keys: <code>'webSocketUrl'</code> is the current WebSocket * url, i.e. the URL that the WebSocket was connected to, e.g. "wss://example.com/matssocket". * <code>'sessionId'</code> is the current MatsSocket SessionId - the one we're trying to close.</li> * <li>"Truthy", e.g. <code>true</code> <b>(default)</b>: When this MatsSocket library is used in * a web browser context, the following code is executed: * <code>navigator.sendBeacon(webSocketUrl.replace('ws', 'http')+"/close_session?sessionId={sessionId}")</code>. * Note that replace is replace-first, and that an extra 's' in 'wss' thus results in 'https'.</li> * </ul> * The default is <code>true</code>. * <p/> * Note: A 'beforeunload' listener invoking {@link MatsSocket#close} is attached when running in a web browser, * so that if the user navigates away, the current MatsSocketSession is closed. * * @type {(function|boolean)} */ outofbandclose: (Function | boolean); /** * "Pre Connection Operation" refers to a hack whereby the MatsSocket performs a specified operation - by default * a {@link XMLHttpRequest} to the same URL as the WebSocket will be connected to - before initiating the * WebSocket connection. The goal of this solution is to overcome a deficiency with the WebSocket Web API * where it is impossible to add headers, in particular "Authorization": The XHR adds the Authorization header * as normal, and the server side can transfer this header value over to a Cookie (e.g. named "MatsSocketAuthCookie"). * When the WebSocket connect is performed, the cookies will be transferred along with the initial "handshake" * HTTP Request - and the AuthenticationPlugin on the server side can then validate the Authorization header - * now present in a cookie. <i>Note: One could of course have supplied it in the URL of the WebSocket HTTP Handshake, * but this is very far from ideal, as a live authentication then could be stored in several ACCESS LOG style * logging systems along the path of the WebSocket HTTP Handshake Request call.</i> * <p/> * Values: * <ul> * <li>"Falsy", e.g. <code>false</code> <b>(default)</b>: Disables this functionality.</li> * <li>A <code>string</code>: Performs a <code>XMLHttpRequest</code> with the URL set to the specified string, with the * HTTP Header "<code>Authorization</code>" set to the current AuthorizationValue. Expects 200, 202 or 204 * as returned status code to go on.</li> * <li>A <code>function</code>: Invokes the function with a parameter object containing <code>'webSocketUrl'</code>, * which is the current WebSocket URL that we will connect to when this PreConnectionOperation has gone through, * and <code>'authorization'</code>, which is the current Authorization Value. <b>Expects * a two-element array returned</b>: [abortFunction, requestPromise]. The abortFunction is invoked when * the connection-retry system deems the current attempt to have taken too long time. The requestPromise must * be resolved by your code when the request has been successfully performed, or rejected if it didn't go through. * In the latter case, a new invocation of the 'preconnectoperation' will be performed after a countdown, * possibly with a different 'webSocketUrl' value if the MatsSocket is configured with multiple URLs.</li> * <li>"Truthy", e.g. <code>true</code>: Performs a <code>XMLHttpRequest</code> to the same URL as * the WebSocket URL, with "ws" replaced with "http", similar to {@link MatsSocket#outofbandclose}, and the HTTP * Header "<code>Authorization</code>" set to the current Authorization Value. Expects 200, 202 or 204 as * returned status code to go on.</li> * </ul> * The default is <code>false</code>. * <p/> * Note: For inspiration for the function-style value of this config, look in the source for the method * <code>w_defaultXhrPromiseFactory(params)</code>. * <p/> * Note: A WebSocket is set up with a single HTTP Request, called the "Upgrade" or "Handshake" request. The * point about being able to send Authorization along with the WebSocket connect only refers to this initial * HTTP Request. Subsequent updates of the Authorization by means of invocation of * {@link MatsSocket#setCurrentAuthorization} will not result in new HTTP calls - these new Authorization * strings are sent in-band with WebSocket messages (MatsSocket envelopes). * * @type {(boolean|string|function)} */ preconnectoperation: (boolean | string | Function); /** * A bit field requesting different types of debug information from the server - the flags/bits are defined in * {@link DebugOption}. The information concerns timings and which server nodes have handled the messages. * <p/> * This field is used as the default for requests sent to the server, but individual requests may also set * the debug flags explicitly (i.e. override) by use of the optional "config" object on * {@link MatsSocket#requestReplyTo} or {@link MatsSocket#request}. * <p/> * To facilitate debug information also on Server initiated messages, the <i>last sent</i> debug flags is * also stored on the server and used when messages originate there (i.e. Server-to-Client SENDs and REQUESTs). * This goes both if the default was used (this flag), or overridden-per-request config: The last flag sent over * is used for any subsequent server-initiated message. This is arguably a pretty annoying way to control the server * initiated debug flags - vote for <a href="https://github.com/centiservice/matssocket/issues/13">Issue 13</a> * if you want something more explicit. * <p/> * The value is a bit field (values in {@link DebugOption}), so you bitwise-or (or simply add) together the * different things you want. * <p/> * The value from the client is bitwise-and'ed together with the debug capabilities the authenticated user has * gotten by the AuthenticationPlugin on the Server side. This means that the AuthenticationPlugin ultimately * controls how much info the accessing user is allowed to get. * <p/> * Default is <code>0</code>, i.e. no debug. * * @type {number} */ debug: number; /** * When performing a {@link MatsSocket#request Request} and {@link MatsSocket#requestReplyTo RequestReplyTo}, * you may not always get a (timely) answer: Either you can lose the connection, thus lagging potentially forever - * or, depending on the Mats message handling on the server (i.e. using "non-persistent messaging" for blazing fast * performance for non-state changing operations), there is a minuscule chance that the message may be lost - or, if * there is a massive backlog of messages for the particular Mats endpoint that is interfaced, you might not get an * answer for 20 minutes. This setting controls the default timeout in milliseconds for Requests, and is default * 45000 milliseconds (45 seconds), but you may override this per Request by specifying a different timeout in the * config object for the request. When the timeout is hit, the Promise of a {@link MatsSocket#request} - or the * specified ReplyTo Terminator for a {@link MatsSocket#requestReplyTo} - will be rejected with a * {@link MessageEvent} of type {@link MessageEventType.TIMEOUT}. In addition, if the Received acknowledgement has * not gotten in either, this will also (<i>before</i> the Promise reject!) be NACK'ed with * {@link ReceivedEventType.TIMEOUT} * * @type {number} */ requestTimeout: number; /** * Way to let integration tests checking failed connections take a bit less time..! Default is 'undefined', which * yields a small number (60ish x 15 seconds) when we do not have SessionId (i.e. trying to connect, we have still * not started the app), and a rather large one (a full day) if we do have a SessionId (implying that we're trying * to reconnect). * * @type {number} */ maxConnectionAttempts: number; /** * Default is 3-7 seconds for the initial ping delay, and then 15 seconds for subsequent pings. Can be overridden * for tests. * * @type {number} */ initialPingDelay: number; /** * Callback function for {@link MatsSocket#addSessionClosedEventListener}. * * @callback sessionClosedEventCallback * @param {CloseEvent} closeEvent the WebSocket's {@link CloseEvent}. */ /** * <b>Note: You <i>should</i> register a SessionClosedEvent listener, as any invocation of this listener by this * client library means that you've either not managed to do initial authentication, or lost sync with the * server, and you should crash or "reboot" the application employing the library to regain sync.</b> * <p /> * The registered event listener functions are called when the Server kicks us off the socket and the session is * closed due to a multitude of reasons, where most should never happen if you use the library correctly, in * particular wrt. authentication. <b>It is NOT invoked when you explicitly invoke matsSocket.close() from * the client yourself!</b> * <p /> * The event object is the WebSocket's {@link CloseEvent}, adorned with properties 'codeName', giving the * <i>key name</i> of the {@link MatsSocketCloseCodes} (as provided by {@link MatsSocketCloseCodes#nameFor}), * and 'outstandingInitiations', giving the number of outstanding initiations when the session was closed. * You can use the 'code' to "enum-compare" to <code>MatsSocketCloseCodes</code>, the enum keys are listed here: * <ul> * <li>{@link MatsSocketCloseCodes.UNEXPECTED_CONDITION UNEXPECTED_CONDITION}: Error on the Server side, * typically that the data store (DB) was unavailable, and the MatsSocketServer could not reliably recover * the processing of your message.</li> * <li>{@link MatsSocketCloseCodes.MATS_SOCKET_PROTOCOL_ERROR MATS_SOCKET_PROTOCOL_ERROR}: This client library * has a bug!</li> * <li>{@link MatsSocketCloseCodes.VIOLATED_POLICY VIOLATED_POLICY}: Initial Authorization was wrong. Always * supply a correct and non-expired Authorization value, which has sufficient 'roomForLatency' wrt. * the expiry time.</li> * <li>{@link MatsSocketCloseCodes.CLOSE_SESSION CLOSE_SESSION}: * <code>MatsSocketServer.closeSession(sessionId)</code> was invoked Server side for this MatsSocketSession</li> * <li>{@link MatsSocketCloseCodes.SESSION_LOST SESSION_LOST}: A reconnect attempt was performed, but the * MatsSocketSession was timed out on the Server. The Session will never time out if the WebSocket connection * is open. Only if the Client has lost connection, the timer will start. The Session timeout is measured in * hours or days. This could conceivably happen if you close the lid of a laptop, and open it again days later * - but one would think that the Authentication session (the one giving you Authorization headers) had timed * out long before.</li> * </ul> * Again, note: No such error should happen if this client is used properly, and the server does not get * problems with its data store. * <p /> * Note that when this event listener is invoked, the MatsSocketSession is just as closed as if you invoked * {@link MatsSocket#close} on it: All outstanding send/requests are NACK'ed (with * {@link ReceivedEventType.SESSION_CLOSED}), all request Promises are rejected * (with {@link MessageEventType.SESSION_CLOSED}), and the MatsSocket object is as if just constructed and * configured. You may "boot it up again" by sending a new message where you then will get a new MatsSocket * SessionId. However, you should consider restarting the application if this happens, or otherwise "reboot" * it as if it just started up (gather all required state and null out any other that uses lazy fetching). * Realize that any outstanding "addOrder" request's Promise will now have been rejected - and you don't really * know whether the order was placed or not, so you should get the entire order list. On the received event, * the property 'outstandingInitiations' details the number of outstanding send/requests and Promises that was * rejected: If this is zero, you <i>might</i> actually be in sync (barring failed/missing Server-to-Client * SENDs or REQUESTs), and could <i>consider</i> to just "act as if nothing happened" - by sending a new message * and thus get a new MatsSocket Session going. * * @param {sessionClosedEventCallback} sessionClosedEventListener a function that is invoked when the library gets the current * MatsSocketSession closed from the server. The event object is the WebSocket's {@link CloseEvent}. */ addSessionClosedEventListener: (sessionClosedEventListener: (closeEvent: CloseEvent) => any) => void; /** * Callback function for {@link MatsSocket#addConnectionEventListener}. * * @callback connectionEventCallback * @param {ConnectionEvent} connectionEvent giving information about what happened. */ /** * <b>Note: You <i>could</i> register a ConnectionEvent listener, as these are only informational messages * about the state of the Connection.</b> It is nice if the user gets a small notification about <i>"Connection * Lost, trying to reconnect in 2 seconds"</i> to keep him in the loop of why the application's data fetching * seems to be lagging. There are suggestions of how to approach this with each of the enum values of * {@link ConnectionEventType}. * <p /> * The registered event listener functions are called when this client library performs WebSocket connection * operations, including connection closed events that are not "Session Close" style. This includes the simple * situation of "lost connection, reconnecting" because you passed through an area with limited or no * connectivity. * <p /> * Read more at {@link ConnectionEvent} and {@link ConnectionEventType}. * * @param {connectionEventCallback} connectionEventListener a function that is invoked when the library issues * {@link ConnectionEvent}s. */ addConnectionEventListener: (connectionEventListener: (connectionEvent: ConnectionEvent) => any) => void; /** * Callback function for {@link MatsSocket#addSubscriptionEventListener}. * * @callback subscriptionEventCallback * @param {SubscriptionEvent} subscriptionEvent giving information about what the server had to say about * subscriptions. */ /** * <b>Note: If you use {@link #subscribe subscriptions}, you <i>should</i> register a * {@link SubscriptionEvent} listener, as you should be concerned about {@link SubscriptionEventType.NOT_AUTHORIZED} * and {@link SubscriptionEventType.LOST_MESSAGES}.</b> * <p /> * Read more at {@link SubscriptionEvent} and {@link SubscriptionEventType}. * * @param {subscriptionEventCallback} subscriptionEventListener a function that is invoked when the library * gets information from the Server wrt. subscriptions. */ addSubscriptionEventListener: (subscriptionEventListener: (subscriptionEvent: SubscriptionEvent) => any) => void; /** * Callback function for {@link MatsSocket#addErrorEventListener}. * * @callback errorEventCallback * @param {ErrorEvent} errorEvent information about what error happened. */ /** * Some 25 places within the MatsSocket client catches errors of different kinds, typically where listeners * cough up errors, or if the library catches mistakes with the protocol, or if the WebSocket emits an error. * Add a ErrorEvent listener to get hold of these, and send them back to your server for * inspection - it is best to do this via out-of-band means, e.g. via HTTP. For browsers, consider * <code>navigator.sendBeacon(..)</code>. * <p /> * The event object is {@link ErrorEvent}. * * @param {errorEventCallback} errorEventListener */ addErrorEventListener: (errorEventListener: (errorEvent: ErrorEvent) => any) => void; /** * Callback function for {@link MatsSocket#setAuthorizationExpiredCallback}. * * @callback authorizationExpiredCallback * @param {AuthorizationRequiredEvent} authorizationRequiredEvent information about why authorization information * is requested. */ /** * If this MatsSockets client realizes that the expiration time (minus the room for latency) of the authorization * has passed when about to send a message, it will invoke this callback function. A new authorization must then * be provided by invoking the 'setCurrentAuthorization' function - only when this is invoked, the MatsSocket * will send messages. The MatsSocket will queue up any messages that are initiated while waiting for new * authorization, and send them all at once in a single pipeline when the new authorization is in. * * @param {authorizationExpiredCallback} authorizationExpiredCallback function which will be invoked * when about to send a new message <i>if</i> * '<code>Date.now() > (expirationTimeMillisSinceEpoch - roomForLatencyMillis)</code>' from the paramaters of * the last invocation of {@link MatsSocket#setCurrentAuthorization}. */ setAuthorizationExpiredCallback: (authorizationExpiredCallback: (authorizationRequiredEvent: AuthorizationRequiredEvent) => any) => void; /** * Sets an authorization String, which for several types of authorization must be invoked on a regular basis with * fresh authorization - this holds for a OAuth/JWT/OIDC-type system where an access token will expire within a short time * frame (e.g. expires within minutes). For an Oauth2-style authorization scheme, this could be "Bearer: ......". * This must correspond to what the server side authorization plugin expects. * <p /> * <b>NOTE: This SHALL NOT be used to CHANGE the user!</b> It should only refresh an existing authorization for the * initially authenticated user. One MatsSocket (Session) shall only be used by a single user: If changing * user, you should ditch the existing MatsSocket after invoking {@link MatsSocket#close} to properly clean up the * current MatsSocketSession on the server side too, and then make a new MatsSocket thus getting a new Session. * <p /> * Note: If the underlying WebSocket has not been established and HELLO sent, then invoking this method will NOT * do that - only the first actual MatsSocket message will start the WebSocket and perform the HELLO/WELCOME * handshake. * * @param {string} authorizationValue the string Value which will be transfered to the Server and there resolved * to a Principal and UserId on the server side by the AuthorizationPlugin. Note that this value potentially * also will be forwarded to other resources that requires authorization. * @param {number} expirationTimestamp the millis-since-epoch at which this authorization expires * (in case of OAuth-style tokens), or -1 if it never expires or otherwise has no defined expiration mechanism. * <i>Notice that in a JWT token, the expiration time is in seconds, not millis: Multiply by 1000.</i> * @param {number} roomForLatencyMillis the number of millis which is subtracted from the 'expirationTimestamp' to * find the point in time where the MatsSocket will refuse to use the authorization and instead invoke the * {@link #setAuthorizationExpiredCallback AuthorizationExpiredCallback} and wait for a new authorization * being set by invocation of the present method. Depending on what the usage of the Authorization string * is on server side is, this should probably <b>at least</b> be 10000, i.e. 10 seconds - but if the Mats * endpoints uses the Authorization string to do further accesses, both latency and queue time must be * taken into account (e.g. for calling into another API that also needs a valid token). If * expirationTimestamp is '-1', then this parameter is not used. <i>Default value is 30000 (30 seconds).</i> */ setCurrentAuthorization: (authorizationValue: string, expirationTimestamp?: number, roomForLatencyMillis?: number) => void; /** * Callback function for {@link MatsSocket#addPingPongListener}. * * @callback addPingPongCallback * @param {PingPong} pingPong information about the ping and the pong. */ /** * A {@link PingPong} listener is invoked each time a {@link MessageType#PONG} message comes in, giving you * information about the experienced {@link PingPong#roundTripMillis round-trip time}. The PINGs and PONGs are * handled slightly special in that they always are handled ASAP with short-path code routes, and should thus * give a good indication about experienced latency from the network. That said, they are sent on the same * connection as all data, so if there is a gigabyte document "in the pipe", the PING will come behind that * and thus get a big hit. Thus, you should consider this when interpreting the results - a high outlier should * be seen in conjunction with a message that was sent at the same time. * * @param {addPingPongCallback} pingPongListener a function that is invoked when the library issues */ addPingPongListener: (pingPongListener: (pingPong: PingPong) => any) => void; /** * Callback function for {@link MatsSocket#addInitiationProcessedEventListener}. * * @callback initiationProcessedEventCallback * @param {InitiationProcessedEvent} initiationProcessedEvent information about the processing of the initiation. */ /** * Registering an {@link InitiationProcessedEvent} listener will give you meta information about each Send * and Request that is performed through the library when it is fully processed, thus also containing * information about experienced round-trip times. The idea is that you thus can gather metrics of * performance as experienced out on the client, by e.g. periodically sending this gathering to the Server. * <b>Make sure that you understand that if you send to the server each time this listener is invoked, using * the MatsSocket itself, you WILL end up in a tight loop!</b> This is because the sending of the statistics * message itself will again trigger a new invocation of this listener. This can be avoided in two ways: Either * instead send periodically - in which case you can include the statistics message itself, OR specify that * you do NOT want a listener-invocation of these messages by use of the config object on the send, request * and requestReplyTo methods. * <p /> * Note: Each listener gets its own instance of {@link InitiationProcessedEvent}, which also is different from * the ones in the {@link MatsSocket.initiations} array. * * @param {initiationProcessedEventCallback} initiationProcessedEventListener a function that is invoked when * the library issues {@link InitiationProcessedEvent}s. * @param {boolean} includeInitiationMessage whether to include the {@link InitiationProcessedEvent#initiationMessage} * @param {boolean} includeReplyMessageEvent whether to include the {@link InitiationProcessedEvent#replyMessageEvent} * Reply {@link MessageEvent}s. */ addInitiationProcessedEventListener: (initiationProcessedEventListener: (initiationProcessedEvent: InitiationProcessedEvent) => any, includeInitiationMessage: boolean, includeReplyMessageEvent: boolean) => void; /** * Registers a Terminator, on the specified terminatorId, and with the specified callbacks. A Terminator is * the target for Server-to-Client SENDs, and the Server's REPLYs from invocations of * <code>requestReplyTo(terminatorId ..)</code> where the terminatorId points to this Terminator. * <p /> * Note: You cannot register any Terminators, Endpoints or Subscriptions starting with "MatsSocket". * * @param terminatorId the id of this client side Terminator. * @param messageCallback receives an Event when everything went OK, containing the message on the "data" property. * @param rejectCallback is relevant if this endpoint is set as the replyTo-target on a requestReplyTo(..) invocation, and will * get invoked with the Event if the corresponding Promise-variant would have been rejected. */ terminator: (terminatorId: any, messageCallback: any, rejectCallback: any) => void; /** * Registers an Endpoint, on the specified endpointId, with the specified "promiseProducer". An Endpoint is * the target for Server-to-Client REQUESTs. The promiseProducer is a function that takes a message event * (the incoming REQUEST) and produces a Promise, whose return (resolve or reject) is the return value of the * endpoint. * <p /> * Note: You cannot register any Terminators, Endpoints or Subscriptions starting with "MatsSocket". * * @param endpointId the id of this client side Endpoint. * @param {function} promiseProducer a function that takes a Message Event and returns a Promise which when * later either Resolve or Reject will be the return value of the endpoint call. */ endpoint: (endpointId: any, promiseProducer: Function) => void; /** * Subscribes to a Topic. The Server may do an authorization check for the subscription. If you are not allowed, * a {@link SubscriptionEvent} of type {@link SubscriptionEventType.NOT_AUTHORIZED} is issued, and the callback * will not get any messages. Otherwise, the event type is {@link SubscriptionEventType.OK}. * <p /> * Note: If the 'messageCallback' was already registered, an error is emitted, but the method otherwise returns * silently. * <p /> * Note: You will not get messages that was issued before the subscription initially is registered with the * server, which means that you by definition cannot get any messages issued earlier than the initial * {@link ConnectionEventType.SESSION_ESTABLISHED}. Code accordingly. <i>Tip for a "ticker stream" or "cache * update stream" or similar: Make sure you have some concept of event sequence number on updates. Do the MatsSocket * connect with the Subscription in place, but for now just queue up any updates. Do the request for "full initial load", whose reply * contains the last applied sequence number. Now process the queued events that arrived while getting the * initial load (i.e. in front, or immediately after), taking into account which event sequence numbers that * already was applied in the initial load: Discard the earlier and same, apply the later. Finally, go over to * immediate processing of the events. If you get a reconnect telling you that messages was lost (next "Note"!), * you could start this process over.</i> * <p /> * Note: Reconnects are somewhat catered for, in that a "re-subscription" after re-establishing the session will * contain the latest messageId the client has received, and the server will then send along all the messages * <i>after</i> this that was lost - up to some limit specified on the server. If the messageId is not known by the server, * implying that the client has been gone for too long time, a {@link SubscriptionEvent} of type * {@link SubscriptionEventType.LOST_MESSAGES} is issued. Otherwise, the event type is * {@link SubscriptionEventType.OK}. * <p /> * Note: You should preferably add all "static" subscriptions in the "configuration phase" while setting up * your MatsSocket, before starting it (i.e. sending first message). However, dynamic adding and * {@link MatsSocket#deleteSubscription deleting} is also supported. * <p /> * Note: Pub/sub is not designed to be as reliable as send/request - but it should be pretty ok anyway! * <p /> * Wrt. to how many topics a client can subscribe to: Mainly bandwidth constrained wrt. to the total number of * messages, although there is a slight memory and CPU usage to consider too (several hundred should not really * be a problem). In addition, the client needs to send over the actual subscriptions, and if these number in * the thousands, the connect and any reconnects could end up with tens or hundreds of kilobytes of "system * information" passed over the WebSocket. * <p /> * Wrt. to how many topics that can exist: Mainly memory constrained on the server based on the number of topics * multiplied by the number of subscriptions per topic, in addition to the number of messages passed in total * as each node in the cluster will have to listen to either the full total of messages, or at least a * substantial subset of the messages - and it will also retain these messages for hours to allow for client * reconnects. * <p /> * Note: You cannot register any Terminators, Endpoints or Subscriptions starting with "MatsSocket". */ subscribe: (topicId: any, messageCallback: any) => void; /** * Removes a previously added {@link MatsSocket#subscribe subscription}. If there are no more listeners for this topic, * it is de-subscribed from the server. If the 'messageCallback' was not already registered, an error is * emitted, but the method otherwise returns silently. * * @param topicId * @param messageCallback */ deleteSubscription: (topicId: any, messageCallback: any) => void; /** * "Fire-and-forget"-style send-a-message. The returned promise is Resolved when the Server receives and accepts * the message for processing, while it is Rejected if the Server denies it. * <p/> * The config object has a single key - <i>which is optional</i>: * <ul> * <li>suppressInitiationProcessedEvent: If <code>true</code>, no event will be sent to listeners added * using {@link MatsSocket#addInitiationProcessedEventListener}.</li> * </ul> * * @param endpointId the Server MatsSocket Endpoint/Terminator that this message should go to. * @param traceId the TraceId for this message - will go through all parts of the call, including the Mats flow. * @param message the actual message for the Server MatsSocket Endpoint. * @param {object} config an optional configuration object - read JSDoc. * @returns {Promise<ReceivedEvent>} */ send: (endpointId: any, traceId: any, message: any, config?: object) => Promise<ReceivedEvent>; /** * Perform a Request, and have the reply come back via the returned Promise. As opposed to Send, where the * returned Promise is resolved when the server accepts the message, the Promise is now resolved by the Reply. * To get information of whether the server accepted or did not accept the message, you can provide either * a receivedCallback function (set the 'config' parameter to this function) or set the two config properties * 'ackCallback' and 'nackCallback' to functions. If you supply the single function variant, this is equivalent * to setting both ack- and nackCallback to the same function. The {@link ReceivedEvent}'s type will distinguish * between {@link ReceivedEventType.ACK ACK} or {@link ReceivedEventType.NACK NACK}. * <p/> * The config object has keys as such - <i>all are optional</i>: * <ul> * <li><b><code>receivedCallback</code></b>: {function} invoked when the Server receives the event and either ACK or NACKs it * - or when {@link MessageEventType.TIMEOUT} or {@link MessageEventType.SESSION_CLOSED} happens. * This overrides the ack- and nackCallbacks.</li> * <li><b><code>ackCallback</code></b>: {function} invoked when the Server receives the event and ACKs it.</li> * <li><b><code>nackCallback</code></b>: {function} invoked when the Server receives the event and NACKs it * - or when {@link MessageEventType.TIMEOUT} or {@link MessageEventType.SESSION_CLOSED} happens.</li> * <li><b><code>timeout</code></b>: number of milliseconds before the Client times out the Server reply. When this happens, * the 'nackCallback' (or receivedCallback if this is used) is invoked with a {@link ReceivedEvent} of * type {@link ReceivedEventType.TIMEOUT}, and the Request's Promise will be <i>rejected</i> with a * {@link MessageEvent} of type {@link MessageEventType.TIMEOUT}.</li> * <li><b><code>suppressInitiationProcessedEvent</code></b>: if <code>true</code>, no event will be sent to listeners added * using {@link MatsSocket#addInitiationProcessedEventListener}.</li> * <li><b><code>debug</code></b>: If set, this specific call flow overrides the global {@link MatsSocket#debug} setting, read * more about debug and {@link DebugOption}s there.</li> * </ul> * <p /> * <b>Note on event ordering:</b> {@link ReceivedEvent}s shall always be delivered <i>before</i> {@link MessageEvent}s. * This means that for a <i>request</i>, if receivedCallback (or ack- or nackCallback) is provided, it shall be * invoked <i>before</i> the return Reply-Promise will be settled. For more on event ordering wrt. message * processing, read {@link InitiationProcessedEvent}. * * @param endpointId the Server MatsSocket Endpoint that this message should go to. * @param traceId the TraceId for this message - will go through all parts of the call, including the Mats flow. * @param message the actual message for the Server MatsSocket Endpoint. * @param {function|object} configOrCallback (optional) either directly a "receivedCallback" function as * described in the config object, or a config object - read JSDoc above. * @returns {Promise<MessageEvent>} */ request: (endpointId: any, traceId: any, message: any, configOrCallback?: Function | object) => Promise<MessageEvent>; /** * Perform a Request, but send the reply to a specific client terminator registered on this MatsSocket instance. * The returned Promise functions as for Send, since the reply will not go to the Promise, but to the * terminator. Notice that you can set any CorrelationInformation object which will be available for the Client * terminator when it receives the reply - this is kept on the client (not serialized and sent along with * request and reply), so it can be any object: An identifier, some object to apply the result on, or even a * function. * <p/> * The config object has keys as such - <i>all are optional</i>: * <ul> * <li><b><code>timeout</code></b>: number of milliseconds before the Client times out the Server reply. When this happens, * the returned Promise is <i>rejected</i> with a {@link ReceivedEvent} of * type {@link ReceivedEventType.TIMEOUT}, and the specified Client Terminator will have its * rejectCallback invoked with a {@link MessageEvent} of type {@link MessageEventType.TIMEOUT}.</li> * <li><b><code>suppressInitiationProcessedEvent</code></b>: if <code>true</code>, no event will be sent to listeners added * using {@link MatsSocket#addInitiationProcessedEventListener}.</li> * <li><b><code>debug</code></b>: If set, this specific call flow overrides the global {@link MatsSocket#debug} setting, read * more about debug and {@link DebugOption}s there.</li> * </ul> * <p /> * <b>Note on event ordering:</b> {@link ReceivedEvent}s shall always be delivered before {@link MessageEvent}s. This means * that for a <i>requestReplyTo</i>, the returned Received-Promise shall be settled <i>before</i> the * Terminator gets its resolve- or rejectCallback invoked. For more on event ordering wrt. message * processing, read {@link InitiationProcessedEvent}. * * @param endpointId the Server MatsSocket Endpoint that this message should go to. * @param traceId the TraceId for this message - will go through all parts of the call, including the Mats flow. * @param message the actual message for the Server MatsSocket Endpoint. * @param replyToTerminatorId which Client Terminator the reply should go to * @param correlationInformation information that will be available to the Client Terminator * (in {@link MessageEvent#correlationInformation}) when the reply comes back. * @param {object} config an optional configuration object - the one parameter you can set is 'timeout', which * works like it does for {@link MatsSocket#request}. * @returns {Promise<ReceivedEvent>} */ requestReplyTo: (endpointId: any, traceId: any, message: any, replyToTerminatorId: any, correlationInformation: any, config?: object) => Promise<ReceivedEvent>; /** * Synchronously flush any pipelined messages, i.e. when the method exits, webSocket.send(..) has been invoked * with the serialized pipelined messages, <i>unless</i> the authorization had expired (read more at * {@link MatsSocket#setCurrentAuthorization} and {@link MatsSocket#setAuthorizationExpiredCallback}). */ flush: () => void; /** * Closes any currently open WebSocket with MatsSocket-specific CloseCode CLOSE_SESSION (4000). Depending * of the value of {@link MatsSocket#outofbandclose}, it <i>also</i> uses <code>navigator.sendBeacon(..)</code> * (if present, i.e. web browser context) to send an out-of-band Close Session HTTP POST, or, if * 'outofbancclose' is a function, this is invoked (if 'outofbandclose' is <code>false</code>, this * functionality is disabled). Upon receiving the WebSocket close, the server terminates the MatsSocketSession. * The MatsSocket instance's SessionId is made undefined. If there currently is a pipeline, * this will be dropped (i.e. messages deleted), any outstanding receiveCallbacks * (from Requests) are invoked, and received Promises (from sends) are rejected, with type * {@link ReceivedEventType.SESSION_CLOSED}, outstanding Reply Promises (from Requests) * are rejected with {@link MessageEventType.SESSION_CLOSED}. The effect is to cleanly shut down the * MatsSocketSession (all session data removed from server), and also clean the MatsSocket instance. * <p /> * Afterwards, the MatsSocket can be started up again by sending a message - keeping its configuration wrt. * terminators, endpoints and listeners. As The SessionId on this client MatsSocket was cleared (and the * previous Session on the server is deleted), this will result in a new server side Session. If you want a * totally clean MatsSocket instance, then just ditch the current instance and make a new one (which then will * have to be configured with terminators etc). * <p /> * <b>Note: A 'beforeunload' event handler is automatically registered on 'window' (if present, i.e. MatsSocket is * running in a web browser), which invokes this method</b>, so that if the user navigates away, the session will * be closed. * * @param {string} reason short descriptive string. Will be supplied with the webSocket close reason string, * and must therefore be quite short (max 123 chars). */ close: (reason: string) => void; /** * Effectively emulates "lost connection". Used in testing. * <p /> * If the "disconnect" parameter is true, it will disconnect with {@link MatsSocketCloseCodes.DISCONNECT} * instead of {@link MatsSocketCloseCodes.RECONNECT}, which will result in the MatsSocket not immediately * starting the reconnection procedure until a new message is added. * * @param reason {String} a string saying why. * @param disconnect {Boolean} whether to close with {@link MatsSocketCloseCodes.DISCONNECT} instead of * {@link MatsSocketCloseCodes.RECONNECT} - default <code>false</code>. AFAIK, only useful in testing..! */ reconnect: (reason: string, disconnect?: boolean) => void; /** * Convenience method for making random strings meant for user reading, e.g. as a part of a good TraceIds, since this * alphabet only consists of lower and upper case letters, and digits. To make a traceId "unique enough" for * finding it in a log system, a length of 6 should be plenty. The alphabet is 62 chars. * * @param {number} length how long the string should be, default is 6. * @returns {string} a random string consisting of characters from from digits, lower and upper case letters * (62 chars). */ randomId: (length?: number) => string; /** * Convenience method for making random strings for correlationIds, not meant for human reading as the alphabet * consist of all visible ACSII chars that won't be quoted in a JSON string. Should you want to make actual Session * cookies or similar, that is, ids being very unique and hard to brute force, you would want to have a longer length, * use e.g. length=16. The alphabet is 92 chars. * @param {number} length how long the string should be, default is 10. * @returns {string} a random string consisting of characters from all visible and non-JSON-quoted chars of * ASCII (92 chars). */ randomCId: (length?: number) => string; } import { AuthorizationRequiredEvent } from './AuthorizationRequiredEvent.js'; import { AuthorizationRequiredEventType } from './AuthorizationRequiredEvent.js'; import { ConnectionState } from './ConnectionState.js'; import { ConnectionEvent } from './ConnectionEvent.js'; import { ConnectionEventType } from './ConnectionEvent.js'; import { MessageType } from './MessageType.js'; import { ReceivedEvent } from './ReceivedEvent.js'; import { ReceivedEventType } from './ReceivedEvent.js'; import { MessageEvent } from './MessageEvent.js'; import { MessageEventType } from './MessageEvent.js'; import { SubscriptionEvent } from "./SubscriptionEvent.js"; import { SubscriptionEventType } from "./SubscriptionEvent.js"; import { InitiationProcessedEvent } from './InitiationProcessedEvent.js'; import { InitiationProcessedEventType } from './InitiationProcessedEvent.js'; import { PingPong } from './PingPong.js'; import { MatsSocketCloseCodes } from './MatsSocketCloseCodes.js'; import { ErrorEvent } from './ErrorEvent.js'; import { DebugOption } from "./DebugInformation.js"; import { DebugInformation } from "./DebugInformation.js"; export { AuthorizationRequiredEvent, AuthorizationRequiredEventType, ConnectionState, ConnectionEvent, ConnectionEventType, MessageType, ReceivedEvent, ReceivedEventType, MessageEvent, MessageEventType, SubscriptionEvent, SubscriptionEventType, InitiationProcessedEvent, InitiationProcessedEventType, PingPong, MatsSocketCloseCodes, ErrorEvent, DebugOption, DebugInformation }; //# sourceMappingURL=MatsSocket.d.ts.map