;
/**
* Escapes special characters in a string that is to be used within a topic
* property or a session filter.
*
* This is a convenience method which inserts an escape character '\' before
* any of the special characters ' " or \.
*
* @param s the string to be escaped
* @returns the string value with escape characters inserted as appropriate
*
* @since 6.1
*/
export declare function escape(s: string): string;
/**
* Utility method which converts a string of the format required by the
* {@link PropertyKeys.ROLES $Roles} session property into a mutable set of
* strings.
*
* @param s the string with quoted roles separated by whitespace or
* commas
*
* @return set of roles
* @throws an error if the argument is `null` or `undefined`
* @throws an {@link IllegalArgumentError} if the input is not correctly quoted
*
* @since 6.2
*/
export declare function stringToRoles(s: string): Set;
/**
* Utility method which converts a set of authorisation roles to the string
* format required by the {@link PropertyKeys.ROLES $Roles} session property.
*
* @param roles a set of roles
* @return a string representing the supplied roles, formatted as
* required by the {@link PropertyKeys.ROLES $Roles} session
* property
*
* @since 6.2
*/
export declare function rolesToString(roles: Set | string[]): string;
/**
* Returns an update constraint factory.
*
* @function diffusion#updateConstraints
* @return {diffusion.topicUpdate.UpdateConstraintFactory} update constraint
* factory
* @since 6.2
*/
export declare function updateConstraints(): UpdateConstraintFactory;
/**
* Create a new {@link BranchMappingTableBuilder}.
*
* @since 6.7
* @see SessionTrees
*/
export declare function newBranchMappingTableBuilder(): BranchMappingTableBuilder;
/**
* Create a new {@link SessionMetricCollectorBuilder}.
*
* @since 6.7
*/
export declare function newSessionMetricCollectorBuilder(): SessionMetricCollectorBuilder;
/**
* Create a new {@link TopicMetricCollectorBuilder}.
*
* @since 6.7
*/
export declare function newTopicMetricCollectorBuilder(): TopicMetricCollectorBuilder;
/**
* Access to the selectors namespace
*/
export declare const selectors: TopicSelectors;
export declare function newRemoteServerBuilder(): RemoteServerBuilder;
export declare function newRemoteServerBuilder(type: RemoteServerType.PRIMARY_INITIATOR): PrimaryInitiatorBuilder;
export declare function newRemoteServerBuilder(type: RemoteServerType.SECONDARY_ACCEPTOR): SecondaryAcceptorBuilder;
export declare function newRemoteServerBuilder(type: RemoteServerType.SECONDARY_INITIATOR): SecondaryInitiatorBuilder;
export declare function newRemoteServerBuilder(type?: RemoteServerType): RemoteServerBuilder | PrimaryInitiatorBuilder | SecondaryAcceptorBuilder | SecondaryInitiatorBuilder;
/**
* Create a new {@link SessionEventParametersBuilder}.
*
* @return the builder
*
* @since 6.11
*/
export declare function newSessionEventParametersBuilder(): SessionEventParametersBuilder;
/**
* Access to the datatypes namespace
*/
export declare const datatypes: DataTypes;
/**
* Access to the topics namespace
*/
export declare const topics: TopicsNamespace;
/**
* Access to the topicUpdate namespace
*/
export declare const topicUpdate: TopicUpdateNamespace;
/**
* The ErrorReason enum
*/
export declare const errors: {
[key: string]: ErrorReasonType;
};
/**
* Access to PropertyKeys
*/
export declare const clients: ClientControlOptionsNamespace;
/**
* Access to the locks namespace
*/
export declare const locks: SessionLockOptionsNamespace;
/**
* Access to the Buffer API that is packaged with diffusion.
*
* This can be used in browsers that don't have a native Buffer class. It allows
* the creation of buffers for use with {@link BinaryDataType binary} datatypes.
*
* @example
* ```
* const buf = diffusion.buffer.from('Hello World', 'utf8')
* ```
*
* @deprecated since version 6.11. Buffer has been replaced by Uint8Array.This
* will be removed in a future release.
*/
export declare const buffer: {
prototype: Buffer;
poolSize: number;
new (str: string, encoding?: string | undefined): Buffer;
new (size: number): Buffer;
new (array: Uint8Array): Buffer;
new (arrayBuffer: ArrayBuffer): Buffer;
new (array: any[]): Buffer;
new (buffer: Buffer): Buffer;
from(arrayBuffer: ArrayBuffer, byteOffset?: number | undefined, length?: number | undefined): Buffer;
from(data: string | any[] | ArrayBuffer | Buffer): Buffer;
from(str: string, encoding?: string | undefined): Buffer;
isBuffer(obj: any): obj is Buffer;
isEncoding(encoding: string): boolean;
byteLength(string: string | DataView | ArrayBuffer | Buffer, encoding?: string | undefined): number;
concat(list: Buffer[], totalLength?: number | undefined): Buffer;
compare(buf1: Buffer, buf2: Buffer): number;
alloc(size: number, fill?: string | number | Buffer | undefined, encoding?: string | undefined): Buffer;
allocUnsafe(size: number): Buffer;
allocUnsafeSlow(size: number): Buffer;
};
/**
* @module diffusion.errors
*/
/**
* An ErrorReport from the server.
*/
export interface ErrorReport {
/**
* The error message
*/
message: string;
/**
* The line at which the problem was found
*/
line: number;
/**
* The column at which the problem was found
*/
column: number;
}
/**
* @module Session
*/
/**
* A typed array that can be passed as credentials
*/
export declare type TypedArray = Int8Array | Int16Array | Int32Array | Uint8Array | Uint8ClampedArray | Uint16Array | Uint32Array | Float32Array | Float64Array;
/**
* A reconnection strategy
*/
export declare type ReconnectStrategy = (reconnect: () => void, abort: () => void) => void;
/**
* Defines a retry strategy.
*
* A retry strategy will be applied when an initial to attempt to open a session
* fails with a transient session establishment exception.
*
* A retry strategy will be applied when recovering by a
* {@link RecoverableUpdateStream} following a recoverable exception.
*
* The strategy is defined in terms of the number of milliseconds between
* retries and the maximum number of retries to attempt.
*
* If no properties are defined, it means that no retries will be attempted.
*
* If `interval` is defined but `attempts` is not, it means that unlimited retries
* will be attempted.
*
* @since 6.10
*/
export interface RetryStrategy {
/**
* The number of milliseconds before the first retry and between subsequent retries
*/
interval?: number;
/**
* The number of retry attempts
*/
attempts?: number;
}
/**
* Additional options that can be passed to the {@link connect} function affecting
* the underlying TLS configuratio. These options are passed directly to
* `tls.createSecureContext()`. For more information, see the documentation for
* the `tls.createSecureContext()` function in the Node.js documentation.
*/
export interface ExtraTlsOptions {
/**
* Optionally override the trusted CA certificates.
*/
ca?: string | Uint8Array | Array | undefined;
/**
* Cert chains in PEM format.
*/
cert?: string | Uint8Array | Array | undefined;
/**
* Cipher suite specification, replacing the default.
*/
ciphers?: string | undefined;
/**
* Name of an OpenSSL engine which can provide the client certificate.
*/
clientCertEngine?: string | undefined;
/**
* PEM formatted CRLs (Certificate Revocation Lists).
*/
crl?: string | Uint8Array | Array | undefined;
/**
* Diffie Hellman parameters, required for Perfect Forward Secrecy.
*/
dhparam?: string | Uint8Array | undefined;
/**
* A string describing a named curve or a colon separated list of curve
* NIDs or names, for example P-521:P-384:P-256, to use for ECDH key
* agreement.
*/
ecdhCurve?: string | undefined;
/**
* Attempt to use the server's cipher suite preferences instead of the
* client's.
*/
honorCipherOrder?: boolean | undefined;
/**
* Private keys in PEM format.
*/
key?: string | Uint8Array | Uint8Array[] | undefined;
/**
* Shared passphrase used for a single private key and/or a PFX.
*/
passphrase?: string | undefined;
/**
* PFX or PKCS12 encoded private key and certificate chain.
*/
pfx?: string | Uint8Array | Array | undefined;
/**
* Optionally affect the OpenSSL protocol behavior, which is not
* usually necessary.
*/
secureOptions?: number | undefined;
/**
* Legacy mechanism to select the TLS protocol version to use.
*/
secureProtocol?: string | undefined;
/**
* Opaque identifier used by servers to ensure session state is not
* shared between applications.
*/
sessionIdContext?: string | undefined;
/**
* If true the server will reject any connection which is not
* authorized with the list of supplied CAs.
*/
rejectUnauthorized?: boolean | undefined;
}
/**
* Provide Session configuration options.
*
* Connection:
* There are several option values that can be configured to change how
* Diffusion establishes a connection. These options are used to derive a
* connection URL in the format: {protocol}://{host}:{port}/{path}.
* The protocol used is determined by the chosen transports and whether secure
* connections are enabled.
*
*
*
*
* | Option |
* Default value |
* Description |
*
*
*
*
* | host |
* localhost |
* The hostname to connect to. |
*
*
* | port |
* 80 or 443 |
* The port to connect to. The default value is the default secure port if
* secure connections are enabled, otherwise the default value is the default
* insecure port.
*
* In case the client is being run in a page served via https
* (http), the default secure (insecure) port is the port of the
* URI of the current page, otherwise the default secure (insecure) port is
* 443 (80).
* |
*
* | path |
* /diffusion |
* The URL path to apply after the hostname/port. This allows additional context to be provided, such as might be
* used by load balancers. |
*
*
* | secure |
* true |
* Determines if secure transports will be used. If the port is not
* explicitly specified this value defaults to true. If the port is
* explicitly specified the default value is true only if the port is
* equal to the default secure port, otherwise false.
*
* In case the client is being run in a page served via https, the
* default secure port is the port of the URI of the current page, otherwise the
* default secure port is 443. |
*
*
*
*
* Reconnection:
*
* Reconnection is enabled by default. The reconnect key accepts several different option values.
*
*
*
* | Option type |
* Default value |
* Description |
*
*
*
*
* boolean |
* true |
* Enables or disables reconnection. If set to true, reconnection will be enabled using the default
* timeout value and a periodic back-off strategy. |
*
*
* number |
* 60000 |
* Passing a number will enable reconnection with the default strategy and the reconnection timeout set to the
* specified value. The reconnection timeout determines how long, in milliseconds, the client will remain in a
* disconnected state before the client is closed. |
*
*
* function |
*
* function(reconnect, abort) {
* setTimeout(reconnect, 5000);
* } |
* A strategy function that will be called when the client enters a disconnected state, and
* subsequently if attempts to reconnect fail. Two arguments are provided, reconnect and abort
* - these are functions to be called within the strategy. The reconnect argument will initiate a
* reconnect attempt. abort may be called to abort reconnection, in which case the client will be closed.
* |
*
*
*
* {
* timeout : <number>,
* strategy : <function>
* } |
*
* {
* timeout : 60000,
* strategy : function(reconnect, abort) {
* setTimeout(reconnect, 5000);
* }
* } |
* An object containing both the timeout and strategy options as specified above, allowing both to be set together.
* |
*
*
*
*
* Transports:
*
* The transports property configures how the session should connect. It can be set to either a
* string, or an array of strings to provide a transport cascading capability.
*
*
*
*
* | Transport key |
* Description |
*
*
*
*
* ws, WS, WEBSOCKET |
* The WebSocket transport. A single, long-lived WebSocket connection will be used to send and receive data. |
*
*
* xhr, XHR, HTTP_POLLING |
* An XHR-based polling transport. Data will be queued on the client and server, and sent in batches. |
*
*
*
* The client will use the transports in the order provided, for example:
* transports: ['WS', 'XHR'] indicates that the client will attempt to connect with the WebSocket
* transport, and if the connection fails, the client will attempt to connect with the HTTP Polling transport. When no
* transports value is provided the client will default to using the WebSocket transport. Any string values
* that do not have an associated transport will be ignored.
*
* When the diffusion client is run in a browser environment, `transports` will
* default to `['WEBSOCKET', 'XHR']`. When run in Node, `transports` will
* default to `['WEBSOCKET']`.
*
* Properties:
*
* Supplied session properties will be provided to the server when a session
* is created using this session factory. The supplied properties will be
* validated during authentication and may be discarded or changed.
*
* The specified properties will be added to any existing properties set for
* this session factory. If any of the keys have been previously declared
* then they will be overwritten with the new values.
*
* For details of how session properties are used see {@link Session}.
*/
export interface Options {
/**
* The hostname to connect to (default `'localhost'`)
*/
host?: string;
/**
* The port to connect to (default `443`)
*/
port?: number | string;
/**
* The request path used for connections (default `/diffusion`)
*/
path?: string;
/**
* Whether to use secure connections.
*/
secure?: boolean;
/**
* The principal name this session should connect with. Used for authentication.
*/
principal?: string;
/**
* A password string to authenticate with, a buffer containing custom
* credentials in binary format, a typed array, or a regular
* array of octets.
*/
credentials?: string | TypedArray | number[];
/**
* The timeout in milliseconds used when connecting to the server. (default `10000`)
*/
connectionTimeout?: number;
/**
* A retry strategy that defines the behaviour for the initial connection
* attempt.
*
* The default connection strategy will attempt each transport once before
* cascading to the next transport.
*/
retry?: RetryStrategy;
/**
* Reconnection options. (default `true`)
*/
reconnect?: boolean | number | ReconnectStrategy | {
timeout?: number;
strategy?: ReconnectStrategy;
};
/**
* The transports to be used for connection establishment. (default `"WEBSOCKET"`)
*/
transports?: string | string[];
/**
* The maximum size of messages that may be received from the server. (default `2147483647`)
*/
maxMessageSize?: number;
/**
* An object of key-value pairs that define the user-defined session properties.
*
* Property values will be sent as `string` values. Non-string properties must
* implement the `toString()` method to allow conversion.
*
* For details of how session properties are used see {@link Session}.
*/
properties?: {
[key: string]: any;
};
/**
* An optional HTTP/HTTPS proxy agent. (default `undefined`)
*
* If this is set, then the client will attempt to connect to the Diffusion
* server via a proxy server.
*
* The proxy agent will be passed to the WebSocket constructor as the
* `agent` option. See https://www.npmjs.com/package/https-proxy-agent for
* an example of a proxy agent.
*
* This option is used for web socket connections and is intended for Node
* based clients only. Browser based clients will automatically use the
* browser's proxy settings.
*
* **Example:**
* ```
* const HttpsProxyAgent = require('https-proxy-agent');
* const url = require('url');
* const diffusion = require('diffusion');
*
* const agent = new HttpsProxyAgent(url.parse('https://proxy.example.com:80'));
*
* diffusion.connect({
* host: 'https://diffusion.foo.com',
* httpProxyAgent: agent
* }).then((session) => {
* // connected through proxy server
* });
* ```
*/
httpProxyAgent?: any;
/**
* An optional TLS options object. (default `undefined`)
* This option is used for secure web socket connections and is intended for
* Node based clients only. Browser based clients will automatically use the
* browser's TLS settings.
*
* See https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions for
* more information.
*/
tlsOptions?: ExtraTlsOptions;
}
/**
* Alias for the Options interface to keep compatibility with old TypeScript definitions
*/
export declare type SessionOptions = Options;
/**
* @module Session
*/
/**
* A session ID
*/
export interface SessionId {
/**
* Convert the session ID to a string
*
* @return a string representation of the session ID
*/
toString(): string;
}
/**
* A client session to a server or cluster of servers.
*
* A new session can be created by connecting to a server using
* {@link connect diffusion.connect}, specifying the server URL. The session
* factory can be configured to control the behavior the session.
*
* The session provides a variety of operations to the application. These are
* grouped into feature interfaces, such as {@link Topics} and
* {@link Messages}, exposed to the application through properties on the Session
* object.
*
* Session lifecycle
*
* Each session is managed by a server. The server assigns the session a
* {@link Session.sessionId unique identity}, and manages the session's topic
* subscriptions, security details, and session
* properties.
*
* A session can be terminated using {@link close}. A session may also be
* terminated by the server because of an error, a time out, or because it's
* authentication has expired. It can also be terminated by other privileged
* sessions using the {@link ClientControl} feature.
*
* A client can become disconnected from the server, and reconnect to the server
* without loss of the session. Reconnection can be configured using
* {@link Options.reconnect the session options}. The server
* must be configured to allow reconnection.
*
* If a session is connected to a server that belongs to a cluster with session
* replication enabled, and then becomes disconnected, it will attempt to
* reconnect to the original server. A properly configured load balancer can
* detect that the original server is unavailable and re-route the reconnection
* request to a second server in the cluster. The second server can recover
* session data and continue the session. This process is known as "fail over".
* Unlike reconnection, in-flight messages can be lost during failover, and the
* application will be unsubscribed and re-subscribed to topics.
*
* The current state of the session can be retrieved with {@link isClosed} and
* {@link isConnected}. Listeners can be registered with {@link on} which will be
* notified when the session state changes.
*
* Session properties
*
* For each session, the server stores a set of session properties that describe
* various attributes of the session.
*
* There are two types of session property. Fixed properties are assigned by the
* server. User-defined properties are proposed by the application, but may
* be changed during authentication.
*
* Many operations use session filter expressions (see section Session Filters)
* that use session properties to select sessions.
*
* A session may obtain its own session properties using
* {@link Session.getSessionProperties}.
*
* A privileged client can monitor other sessions, including changes to their
* session properties, using a {@link ClientControl.addSessionEventListener
* session event listener}. When registering to receive session properties,
* special key values of {@link PropertyKeys.ALL_FIXED_PROPERTIES
* ALL_FIXED_PROPERTIES} and {@link PropertyKeys.ALL_USER_PROPERTIES
* ALL_USER_PROPERTIES} can be used.
*
* Each property is identified by a key. Most properties have a single string
* value. The exception is the $Roles fixed property which has a set of string
* values.
*
* Fixed properties are identified by keys with a '$' prefix. The available
* fixed session properties are:
*
*
*
* | Key |
* Description |
*
*
* $ClientIP |
* The Internet address of the client in string format. |
*
*
* $ClientType |
* The client type of the session. One of ANDROID, C,
* DOTNET, IOS, JAVA, JAVASCRIPT_BROWSER,
* MQTT, PYTHON, or OTHER. |
*
*
* $Connector |
* The configuration name of the server connector that the client connected
* to. |
*
*
* $Country |
* The country code for the country where the client's Internet address was
* allocated (for example, NZ for New Zealand). If the country code could not
* be determined, this will be a zero length string. |
*
*
*
* $Environment |
* The environment in which the client is running. For possible values see the user manual.
* The browser name and version are determined by the UA-Parser library. |
*
*
* $ExpiryTime |
* The time at which the session is due to expire, specified in milliseconds
* since the epoch. This may be set by authenticators. If not present, the
* session will not expire. |
*
* $GatewayType |
* Gateway client type. Only set for gateway client sessions.
* If present it indicates the type of gateway client (e.g. Kafka). |
*
*
* $GatewayId |
* The identity of a gateway client session.
* Only present if the $GatewayType session property is present. |
*
*
* $Language |
* The language code for the official language of the country where the
* client's Internet address was allocated (for example, en for English). If
* the language could not be determined or is not applicable, this will be a
* zero length string. |
*
*
* $Latitude |
* The client's latitude, if available. This will be the string
* representation of a floating point number and will be NaN if not
* available. |
*
*
* $Longitude |
* The client's longitude, if available. This will be the string
* representation of a floating point number and will be NaN if not
* available. |
*
* $MQTTClientId |
* The MQTT client identifier. Only set for MQTT sessions. If
* present, the value of the $ClientType session property will be
* MQTT. |
*
*
* $Principal |
* The security principal associated with the client session. |
*
*
* $Roles |
* Authorisation roles assigned to the session. This is a set of roles
* represented as quoted strings (for example, `"role1","role2"`). The
* utility method {@link stringToRoles} can be used to parse
* the string value into a set of roles. |
*
*
* $ServerName |
* The name of the server to which the session is connected. |
*
*
* $SessionId |
* The session identifier. Equivalent to {@link Session.sessionId}. |
*
*
* $StartTime |
* The session's start time in milliseconds since the epoch. |
*
*
* $Transport |
* The session transport type. One of WEBSOCKET,
* HTTP_LONG_POLL, TCP, or OTHER. |
*
*
*
* All user-defined property keys are non-empty strings and are case-sensitve.
* The characters ' ', '\t', '\r', '\n', '"', ''', '(', ')' are not allowed.
*
* Session properties are initially associated with a session as follows:
*
* 1. When a client starts a new session or {@link Security.reauthenticate
* re-authenticates}, it can optionally propose
* user-defined session properties (see {@link Options}.properties).
* Session properties proposed in this way must be accepted by the
* authenticator. This safeguard prevents abuse by a rogue, unprivileged client.
* 2. The server allocates all fixed property values.
* 3. The new session is authenticated by registered authenticators. An
* authenticator that accepts a session can veto or change the user-defined
* session properties and add new user-defined session properties. The
* authenticator can also change certain fixed properties, such as the
* expiry time (`EXPIRY_TIME`).
*
* Once a session is established, its user-defined session properties can be
* modified by clients with `VIEW_SESSION` and `MODIFY_SESSION`
* permissions using {@link ClientControl.setSessionProperties}.
* A privileged client can also modify its own session properties.
*
* If a session re-authenticates (see {@link Security.reauthenticate
* reauthenticate}), the authenticator that allows the re-authentication can
* modify the user-defined session properties and a subset of the fixed
* properties as mentioned above.
*
* Session filters
*
* Session filters are a mechanism of addressing a set of sessions by the values
* of their session properties.
*
* Session filters are specified using a Domain Specific Language (DSL). For a full and
* detailed description of the session filters DSL see the
*
* user manual.
*
* Events
*
* disconnect
*
* Emitted when a connected session has lost connection to the server, and
* {@link Options} `reconnect` is enabled. The provided reason will
* contain the specific cause of the session disconnect.
*
* **Parameters:**
*
* `reason`: {@link CloseReason} - the cause of the session disconnect
*
* reconnect
*
* Emitted when a disconnected session has successfully reconnected.
*
* close
*
* Emitted when a session is closed. This can occur because it was closed by the
* user, closed by the server, failed to connect, or the session encountered an
* error. The provided close reason will contain the specific cause of the
* session close.
*
* **Parameters:**
*
* `reason`: {@link CloseReason} - the cause of the session close
*
* error
*
* Emitted when a session error has occurred. A session error occurs when the
* client cannot parse communication from the server. This occurs if a component
* between the two - for example, a proxy or load balancer - alters the
* communication.
*
* **Parameters:**
*
* `error`: any - the error that occurred
*/
export interface Session extends Stream, Topics, Ping {
/**
* The unique id assigned to this session by the server.
*/
readonly sessionId: SessionId;
/**
* The connection options used to establish this session
*/
readonly options: Options;
/**
* Exposes remote servers capabilities via {@link Session.remoteServers}
*/
readonly remoteServers: RemoteServers;
/**
* Exposes system authentication capabilities via a {@link Session.security}
*/
readonly security: Security;
/**
* Exposes session trees capabilities via {@link Session.sessionTrees}
*/
readonly sessionTrees: SessionTrees;
/**
* Exposes topic control capabilities via {@link Session.topics}
*/
readonly topics: TopicControl;
/**
* Exposes topic update capabilities via {@link Session.topicUpdate}
*/
readonly topicUpdate: TopicUpdate;
/**
* Exposes topic views capabilities via {@link Session.topicViews}
*/
readonly topicViews: TopicViews;
/**
* Exposes time series capabilities via {@link Session.timeseries}
*/
readonly timeseries: TimeSeries;
/**
* Exposes messaging capabilities via {@link Session.messages}
*/
readonly messages: Messages;
/**
* Exposes topic notification capabilities via {@link Session.notifications}
*/
readonly notifications: TopicNotifications;
/**
* Exposes client control capabilities via {@link ClientControl}
*/
readonly clients: ClientControl;
/**
* Exposes metric collector management capabilities via {@link Metrics}
*/
readonly metrics: Metrics;
/**
* Close this session's connection to the server.
*
* Calling this repeatedly will have no effect.
*
* @return this session
*/
close(): Session;
/**
* Close this session's connection to the server and return a {@link Promise}
* that will completes when the session is closed.
*
* @return a {@link Promise} that completes with the close reason returned
* by the server. Only the {@link Promise} of the first call to
* `closeSession` is guaranteed to complete. The {@link Promise}
* will not resolve if the session is already closed.
*/
closeSession(): Promise;
/**
* Indicates if this session is currently closed, or in the process of
* closing.
*
* This will not return `true` if the session is disconnected
* but attempting to reconnect.
*
* @return whether the session is currently closed.
*/
isClosed(): boolean;
/**
* Indicates if this session is currently connected.
*
* This is orthogonal to {@link Session.isClosed}, as a session may
* be disconnected and attempting to reconnect.
*
* @return whether the session is currently connected or not.
*/
isConnected(): boolean;
/**
* Returns the principal name that this session is associated with.
*
* @return the principal for this session
*/
getPrincipal(): string;
/**
* Returns the values of the session's fixed session properties.
*
* All current fixed property values are returned, except the value of the
* `ROLES` property. User-defined session properties are not returned.
*
* @return a Promise that resolves when a response is received
* from the server.
*
* If the Promise completes normally, the current
* session properties will be returned (excluding the value of the
* `ROLES` property).
*
* Otherwise, the Promise will be rejected. Common reasons for failure include:
*
*
* - the session is closed.
*
* @since 6.12
*/
getSessionProperties(): Promise;
/**
* Attempt to acquire a {@link SessionLock session lock}.
*
* This method returns a Promise that will resolve normally if
* the server assigns the requested lock to the session. Otherwise, the
* Promise will fail with an error indicating why the lock could not
* be acquired.
*
* @param lockName the name of the session lock
* @param scope preferred scope, defaults to
* `UNLOCK_ON_SESSION_LOSS` . The scope of a lock controls
* when it will be released automatically. If a session
* makes multiple requests for a lock using different
* scopes, and the server assigns the lock to the session
* fulfilling the requests, the lock will be given the
* weakest scope (`UNLOCK_ON_SESSION_LOSS` ).
* @return a Promise that resolves when a response is received
* from the server.
*
* If this session has successfully acquired the session
* lock, or this session already owns the session lock, the
* Promise will resolve normally with a SessionLock result.
*
* If the Promise resolves with an error, this session does
* not own the session lock.
*
* @since 6.2
*/
lock(lockName: string, scope?: SessionLockScope): Promise;
/**
* Updates the session with missing features that may have been loaded
* asynchronously. This method only has an effect when running the client
* as a modular client in the browser.
*/
updateFeatures(): void;
}
/**
* @module diffusion.clients
*/
/**
* A type containing information about the reason for a session being closed
*
* Documentation of the CloseReason values can be found under {@link CloseReasonEnum}.
*/
export interface CloseReason {
/**
* The close reason's id
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
id: number;
/**
* The close reason's description
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
message: string;
}
/**
* Enum representing the reason that the session has been closed.
*
* **Example:**
* ```
* diffusion.connect({...}).then(function(session) {...}, function(err) {
* switch(err) {
* case diffusion.clients.CloseReason.CLOSED_BY_CLIENT:
* // Do something
* case diffusion.clients.CloseReason.ACCESS_DENIED:
* // Do something else
* ...
* }
* });
* ```
*
*/ export declare const CloseReasonEnum: {
[key: string]: CloseReason;
};
/**
* The server's view of why a client session was closed.
*/
export declare enum ClientCloseReason {
/**
* The connection to the client was lost - possibly dropped by the client.
* Recoverable.
*
* A client may be closed for may reasons that are presented as
* CONNECTION_LOST.
*
* During connection the connection can be lost. The server might have
* received a connection or reconnection request from a client already
* connected. The server might have received a reconnection request without
* a client ID. The connection may not have been authorised because the
* credentials are wrong. The maximum number of clients might already be
* connected.
*
* Once connected the connection can be lost for different reasons. If the
* client closes its connection while the server is writing a message to the
* client. With the chunked encoding based connection the HTTP response is
* completed by the server. If the client does not open a new request within
* a timeout the client will be closed. If a poll request times out and the
* server finds that the connection has already been closed by the client.
*/
CONNECTION_LOST = 0,
/**
* An unexpected IO Exception occurred. Recoverable.
*
* While trying to perform an I/O operation an exception was generated. This
* often means that Diffusion attempted to read from a closed TCP
* connection.
*
* When Diffusion is handling SSL connections if there is a problem
* encrypting or decrypting a message the client will be closed for this
* reason.
*/
IO_EXCEPTION = 1,
/**
* The client had become unresponsive. Recoverable.
*
* The client has either failed to respond to a ping message in a timely
* manner or the client has failed to open an HTTP poll for messages. The
* client does not appear to be receiving messages.
*/
CLIENT_UNRESPONSIVE = 2,
/**
* The maximum outbound queue size was reached for the client. Not
* recoverable.
*
* Messages sent to the client are placed in a queue. This queue has a
* maximum allowed size. If the queue limit is reached the client is closed
* and the queue discarded. The queue is intended to protect against slow
* patches, reaching the queue limit is taken to mean that the client cannot
* keep up with the number of messages sent to it.
*/
MESSAGE_QUEUE_LIMIT_REACHED = 3,
/**
* The client requested close. Not recoverable (unless TEST_RECONNECT is
* true).
*/
CLOSED_BY_CLIENT = 4,
/**
* The client sent a message that exceeded the maximum message size.
*
* The server has a maximum message size. If a client sends a message larger
* than this the server is unable to process it. When this happens the
* message is discarded and the client is closed.
*/
MESSAGE_TOO_LARGE = 5,
/**
* An internal error occurred.
*/
INTERNAL_ERROR = 6,
/**
* An inbound message with an invalid format was received.
*
* A message received by the server is not a valid Diffusion message. The
* server is unable to process this and closes the client that sent it.
*/
INVALID_INBOUND_MESSAGE = 7,
/**
* The client connection was aborted by the server, possibly because the
* connection was disallowed.
*
* This may be because the connection was disallowed. Abort messages are
* also sent to clients that have unrecognised client IDs. This may be
* because the server closed the client previously but the client is unaware
* of this and tried to continue interacting with the server.
*/
ABORTED = 8,
/**
* Loss of messages from the client has been detected. For example, whilst
* waiting for the arrival of missing messages in a sequence of messages a
* timeout has occurred.
*
* HTTP based transports use multiple TCP connections. This can cause the
* messages to be received out of order. To reorder the messages those sent
* to the server may contain a sequence number indicating the correct order.
*
* If a message is received out of order there is a short time for the
* earlier messages to be received. If the messages are not received in this
* time the client is closed.
*
* Missing, invalid or duplicate sequence numbers will also close the client
* for this reason.
*
* This cannot be recovered from as the client and the server are in
* inconsistent states.
*/
LOST_MESSAGES = 9,
/**
* A control session initiated the client close.
*/
CLOSED_BY_CONTROLLER = 11,
/**
* The client has failed over to a different server.
*
* The session is still open but is now connected to a different Diffusion
* server. This server has evicted its view of the client from its set of
* local clients.
*/
FAILED_OVER = 12,
/**
* The session had an {@link EXPIRY_TIME} specified which
* expired before the session {@link Security.reauthenticate
* re-authenticated}.
*
* @since 6.12
*/
EXPIRED = 13,
/**
* The session's authentication was revoked by a privileged user.
*
* @since 6.12
*/
REVOKED = 14,
/**
* The session has been closed to make way for a new session.
*
* This is used by MQTT. See MQTT-3.1.4-3.
*
* @since 6.12
*/
SESSION_TAKEN_OVER = 15
}
/**
* @module diffusion.datatypes
*/
///
/**
* Read-only interface for values that are internally represented as binary
* data.
*
* This interface provides access to copies of the binary data, making instances
* effectively immutable. Methods of derived interfaces and classes that relax
* this restriction and expose access to the internal data should be clearly
* documented.
*
* @since 5.7
*/
export interface Bytes {
/**
* Get the number of bytes
*
* @return The length of the data in bytes
*/
length(): number;
/**
* Get a copy of the buffer containing this value.
*
* @return This value in binary form
*
* @deprecated since version 6.11. Buffer has been replaced by Uint8Array. This
* will be removed in a future release.
*/
asBuffer(): Buffer;
/**
* Get a copy of the array containing this value.
*
* @return This value in binary form
*/
asArray(): Uint8Array;
/**
* Copy the binary data to a provided buffer.
*
* @param target the buffer to copy data to
* @param offset the position in the target buffer at which data will be copied
*/
copyTo(target: Uint8Array, offset?: number): void;
}
/**
* @module diffusion.datatypes
*/
///
/**
* A data type is specified for a particular value type. It provides methods to
* convert values to and from binary. Diffusion provides several {@link DataType}
* implementations.
*
* A data type can optionally support incremental changes to values, represented
* by one or more types of delta. A delta is the difference between two
* values. For large or composite values that change in small steps, it is more
* efficient to transmit an initial value followed by a delta for each change
* than to transmit a complete value for each change. The data type provides an
* implementation of {@link DeltaType} for each type of delta it
* supports via {@link DataType.deltaType}.
*
* @since 5.7
*
* @param the value type of the data type
* @param the type(s) from which a value can be constructed
* @param the binary type containing the CBOR data
*/
export interface DataType {
/**
* The external type identifier.
*
* @return the name of this datatype
*/
name(): string;
/**
* Parse a value from binary.
*
* @param input the binary data
* @param offset the offset to start reading from the provided buffer (default = `0`)
* @param length the length of the data to read (default = `input.length`)
* @returns an instance of this data type value
* @throws an {@link InvalidDataError} error if the data is invalid for this type
*/
readValue(input: Uint8Array, offset?: number, length?: number): ValueType | null;
readValue(input: CBORType): ValueType | null;
/**
* Serialise a value to binary
*
* @param value the value to serialise. For primitive and JSON datatypes
* the value can be `undefined` or `null`. In this case a
* `null` value will be serialised.
* @returns the serialised value as a buffer
* @throws an {@link IllegalArgumentError} if the value cannot be serialised
*
* @deprecated since version 6.11. Buffer has been replaced by Uint8Array.
* Use writeValueToArray instead. This will be removed
* in a future release.
*/
writeValue(value: SourceType | undefined | null): Buffer;
/**
* Serialise a value to binary
*
* @param value the value to serialise. For primitive and JSON datatypes
* the value can be `undefined` or `null`. In this case a
* `null` value will be serialised.
* @returns the serialised value as a buffer
* @throws an {@link IllegalArgumentError} if the value cannot be serialised
*/
writeValueToArray(value: SourceType | undefined | null): Uint8Array;
/**
* Test whether this data type is compatible with `valueType`. Compatibility
* with a `valueType` means than any valid binary representation of a
* `value` can be {@link DataType.readAs read as} an
* instance of `valueType`.
*
* Every data type should be compatible with the following:
*
* * `Value Type` – the class corresponding to the data type's value
* type.
*
* For a data type with a value type of `X`, `readAs(X, buffer)` is
* equivalent to `readValue(buffer)`.
*
* @param valueType the type to check
* @return `true` if a binary representation created by this data
* type can read as an instance * of `valueType`
* @since 6.0
*/
canReadAs(valueType: new (...args: any[]) => any): boolean;
/**
* Create a value of a compatible class from binary.
*
* @param valueType the type of the result
* @param buffer the binary data
* @param offset the offset to start reading from the provided buffer (default = `0`)
* @param length the length of the data to read (default = `input.length`)
* @return the value in the form of the specified type
* @throws an {@link InvalidDataError} if `valueType` is incompatible with this data
* type, or `buffer` does not represent a valid value.
* @since 6.0
*/
readAs(valueType: new (...args: any[]) => T, buffer: Uint8Array, offset?: number, length?: number): T | null;
readAs(valueType: new (...args: any[]) => T, buffer: CBORType): T | null;
/**
* Obtain a {@link DeltaType} by name or delta type.
*
* **Example:**
* ```
* // Get by name
* var deltas = datatype.deltaType("binary");
* ```
*
* **Example:**
* ```
* // Get by type
* var deltas = datatype.deltaType(delta);
* ```
*
* @param name the name, as returned by {@link DeltaType.name}
* @returns the delta type
*/
deltaType(name?: string): DeltaType;
}
/**
* A placeholder data type that can represent any of the other datatypes.
*
* The sole purpose of this data type is to allow creating polymorphic streams
* that can accept any data type.
*
* **Example:**
* ```
* // Get the Any datatype and create a stream
* var anyType = diffusion.datatypes.any();
* var stream = session.addStream('some_topic', anyType);
* ```
*/
export interface AnyDataType {
/**
* The external type identifier.
*
* @return the name of this datatype
*/
name(): string;
}
/**
* @module diffusion.datatypes
*/
/**
* Diffusion datatype implementations.
*
* Datatypes are accessed via the `diffusion` singleton.
*
* **Example:**
* ```
* // Get the JSON datatype
* var json = diffusion.datatypes.json();
* ```
*
* **Example:**
* ```
* // Get a datatype via name
* var json = diffusion.datatypes.get('json');
* ```
* @namespace diffusion.datatypes
* @since 5.7
*/
export interface DataTypes {
/**
* Get the binary data type
*
* @return the Binary data type
*/
binary(): BinaryDataType;
/**
* Get the JSON data type
*
* @return the JSON data type
*/
json(): JSONDataType;
/**
* Get the Int64 data type
*
* @return the Int64 data type
*/
int64(): Int64DataType;
/**
* Get the string data type
*
* @return the String data type
*/
string(): StringDataType;
/**
* Get the double data type
*
* @return the Double data type
*/
double(): DoubleDataType;
/**
* Get the record V2 data type
*
* @return the RecordV2 data type
*/
recordv2(): RecordV2DataType;
/**
* Get the Any data type
*
* @return the Any data type
*/
any(): AnyDataType;
/**
* Get the timeseries data type
*
* @param valueType the value type of the timeseries data type
* @return a timeseries data type
*/
timeseries(valueType: DataType): DataType, Event, Bytes>;
/**
* Obtain a {@link DataType} implementation by type
* name, topic type, or value class
*
* @param name the type name as returned by {@link DataType.name}, the value
* or a topic type.
* @return the data type or `null` if no datatype was found
*/
get(name: any): DataType | null;
/**
* Obtain a {@link DataType} implementation by value class.
*
* For {@link DoubleDataType}, the associated value class is `Number`.
*
* @param valueClass the class
* @return the data type
* @throws an {@link IllegalArgumentError} if there is no data type for provided class
*/
getByClass(valueClass: new (...args: any[]) => any): DataType;
}
/**
* @module diffusion.datatypes
*/
///
/**
* Optional extension provided by {@link DataType} implementations that support
* incremental changes to values.
*
* A data type can optionally support incremental changes to values, represented
* by one or more types of delta. A delta is the difference between two values.
* For large or composite values that change in small steps, it is more
* efficient to transmit an initial value followed by a delta for each change
* than to transmit a complete value for each change.
*
* Each implementation specifies a `value` type and a `delta` type.
* Two values, oldValue and new Value, can be compared to produce a delta using
* {@link DeltaType.diff}. The delta can be separately applied to oldValue to
* create newValue using {@link DeltaType.apply}.
*
* Deferred parsing
* Implementations can choose not to fully validate values when they are read,
* but instead defer parsing until it is required. Consequently, all methods
* that accept values may throw an error.
*
* @param the value type of the data type
* @param the type(s) from which a value can be constructed
* @param the binary type containing the CBOR data
*
* @since 5.7
*/ export interface DeltaType {
/**
* The name of this delta type
*
* @returns the name
*/
name(): string;
/**
* Create a delta from two values.
*
* If there are many differences between oldValue and newValue, the result
* might require more bytes to transmit than the new value, or be
* computationally expensive to apply. In this case, it is better to discard
* oldValue and publish newValue in its place. This can be checked using
* {@link DeltaType.isValueCheaper}.
*
* The implementation can return the special constant {@link DeltaType.noChange}
* to indicate the old value and new value are equivalent and there is no change
* to publish.
*
* @param oldValue the old value
* @param newValue the new value
* @return the delta between values
*/
diff(oldValue: SourceType, newValue: SourceType): BinaryDelta;
/**
* Apply a delta to a value.
*
* @param old the old value
* @param delta the delta to apply
* @return the new value generated applying the delta to the old value
* @throws an {@link InvalidDataError} if the value or delta is invalid
*/
apply(oldValue: SourceType, delta: BinaryDelta): ValueType | null;
/**
* Parse a delta from binary.
*
* @param binary the binary data
* @param offset the offset from which to start reading from the buffer
* @param length the length of data to read from the buffer
* @return the delta
* @throws an error if the binary is invalid
*/
readDelta(buffer: Uint8Array, offset?: number, length?: number): BinaryDelta;
/**
* Serialise a delta to binary.
*
* @param delta the delta to serialise
* @return the serialised form of the delta
* @throws an error if the delta cannot be serialised
*
* @deprecated since version 6.11. Buffer has been replaced by Uint8Array.
* Use writeDeltaToArray instead. This will be removed
* in a future release.
*/
writeDelta(delta: BinaryDelta): Buffer;
/**
* Serialise a delta to binary.
*
* @param delta the delta to serialise
* @return the serialised form of the delta
* @throws an error if the delta cannot be serialised
*/
writeDeltaToArray(delta: BinaryDelta): Uint8Array;
/**
* Constant returned by {@link DeltaType.diff} to
* indicate that both values are equivalent.
*
* @return unique object representing no change in value
*/
noChange(): BinaryDelta;
/**
* Calculate if `value` is cheaper than the `delta`. The
* result is typically determined by the length of the serialised form, but may
* also consider the complexity of the delta.
*
* @param value the value to compare
* @param delta the delta to compare
* @return `true` if the value is considered cheaper than the delta
* @throws an error if the value or delta is invalid
*/
isValueCheaper(value: SourceType, delta: BinaryDelta): boolean;
}
/**
* @module diffusion.errors
*/
/**
* A type containing information about the reason that an error occured
*/
export interface ErrorReasonType {
/**
* The error reason's id
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
id: number;
/**
* The error reason's description
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
reason: string;
}
/**
* Enum containing reason codes used to report error conditions.
*
* Some common ErrorReason values are defined as global constants. More specific reasons may be defined by
* individual features.
*
* **Example:**
* ```
* // Handle an error from the server
* session.addStream('foo', diffusion.datatypes.string()).on('error', function(e) {
* if (e == diffusion.errors.ACCESS_DENIED) {
* // Handle authorisation error
* } else {
* // Log the problem
* console.log(e);
* }
* });
* ```
*/ export declare const ErrorReason: {
[key: string]: ErrorReasonType;
};
/**
* Base class for all errors thrown by the diffusion client
*/
export interface DiffusionError {
getType(): string;
}
/**
* An error that signals that a `null` or `undefined` value was encountered.
*/
export declare class NullValueError extends Error implements DiffusionError {
/**
* The `null_value_error` error type
*/
static readonly type = "null_value_error";
/**
* The constructor creates NullValueError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that signals a runtime error.
*/
export declare class RuntimeError extends Error implements DiffusionError {
/**
* The `runtime_error` error type
*/
static readonly type = "runtime_error";
/**
* The cause of the error
*/
readonly cause?: Error | ErrorReasonType;
/**
* The constructor creates RuntimeError objects.
* @param message The error message
*/
constructor(message: string, cause?: Error | ErrorReasonType);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that is not expected to occur.
*/
export declare class AssertionError extends Error implements DiffusionError {
/**
* The `assertion_error` error type
*/
static readonly type = "assertion_error";
/**
* The constructor creates RuntimeError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that signals that invalid data was encountered.
*/
export declare class InvalidDataError extends Error implements DiffusionError {
/**
* The `invalid_data_error` error type
*/
static readonly type = "invalid_data_error";
/**
* The constructor creates InvalidDataError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that signals that an I/O error has occurred.
*/
export declare class IOError extends Error implements DiffusionError {
/**
* The `io_error` error type
*/
static readonly type = "io_error";
/**
* The constructor creates IOError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that is reported from a service call.
*/
export declare class SessionError extends Error implements DiffusionError {
/**
* The `session_error` error type
*/
static readonly type = "session_error";
/**
* The cause of the error
*/
readonly cause?: Error;
/**
* The constructor creates SessionError objects.
* @param message The error message
*/
constructor(message: string, cause?: Error);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates that a function has been called with an illegal or
* inappropriate argument.
*/
export declare class IllegalArgumentError extends Error implements DiffusionError {
/**
* The `illegal_argument_error` error type
*/
static readonly type = "illegal_argument_error";
/**
* The constructor creates IllegalArgumentError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates that the requested index is out of bounds.
*/
export declare class OutOfBoundsError extends Error implements DiffusionError {
/**
* The `out_of_bounds_error` error type
*/
static readonly type = "out_of_bounds_error";
/**
* The constructor creates OutOfBoundsError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates that a filter expression is invalid.
*/
export declare class InvalidFilterError extends Error implements DiffusionError {
/**
* The `invalid_filter_error` error type
*/
static readonly type = "invalid_filter_error";
/**
* The list of errors that caused the filter to be invalid
*/
readonly errors: ErrorReport[];
/**
* The constructor creates InvalidFilterError objects.
* @param message The error message
*/
constructor(message: string, errors: ErrorReport[]);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates that a script is invalid.
*/
export declare class InvalidScriptError extends Error implements DiffusionError {
/**
* The `invalid_script_error` error type
*/
static readonly type = "invalid_script_error";
/**
* The list of errors that caused the script to be invalid
*/
readonly errors: ErrorReport[];
/**
* The constructor creates InvalidScriptError objects.
* @param message The error message
*/
constructor(message: string, errors: ErrorReport[]);
/**
* Get the error type
*/
getType(): string;
}
/**
* Indicates a problem that has occurred when building a schema.
*/
export declare class SchemaViolationError extends Error implements DiffusionError {
/**
* The `schema_violation_error` error type
*/
static readonly type = "schema_violation_error";
/**
* The constructor creates SchemaViolationError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* Indicates a problem that has occurred when parsing a schema.
*/
export declare class SchemaParseError extends Error implements DiffusionError {
/**
* The `schema_parse_error` error type
*/
static readonly type = "schema_parse_error";
/**
* The constructor creates SchemaParseError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates that a retry limit has been reached.
*/
export declare class RetryLimitError extends Error implements DiffusionError {
/**
* The `retry_limit_error` error type
*/
static readonly type = "retry_limit_error";
/**
* The constructor creates RetryLimitError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates that a method has been called at an illegal or
* inappropriate time.
*/
export declare class IllegalStateError extends Error implements DiffusionError {
/**
* The `illegal_state_error` error type
*/
static readonly type = "illegal_state_error";
/**
* The constructor creates IllegalStateError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* An error that indicates an error that is internal to the diffusion client.
*/
export declare class InternalError extends Error implements DiffusionError {
/**
* The `internal_error` error type
*/
static readonly type = "internal_error";
/**
* The constructor creates InternalError objects.
* @param message The error message
*/
constructor(message: string);
/**
* Get the error type
*/
getType(): string;
}
/**
* A reference to a registered handler.
*
* Such a handler reference is provided whenever a handler with a server side
* presence is registered.
*/
export interface Registration {
/**
* Request that the handler is unregistered from the server.
*
* After the handler is unregistered, the handler's `onClose` method
* will be called.
*
* A handler can only be unregistered once. A given instance will return the
* same Promise if this method is called more than once.
*
* @returns a {@link Promise} that completes when a response is received from
* the server
*/
close(): Promise;
}
/**
* @module diffusion.events
*/
/**
* An error callback
*/
export declare type Callback = (error: any) => U;
/**
* A Result represents a promise for the result of an async operation.
*
* It implements the full ES6 Promise specification and is in all respects equivalent to a Promise.
*
* @deprecated since 6.12
*
* Use the native Promise type instead
*/
export declare type Result = Promise;
/**
* @module diffusion.events
*
* @brief A module containing event streams
*
* @preferred
*/
/**
* A callback function type for {@link Stream}s
*/
export declare type StreamCallback = (...args: any[]) => void;
/**
* A type mapping event names to callback functions
*/
export interface CallbackMap {
[event: string]: StreamCallback;
}
/**
* A {@link Stream} provides a series of events that may be consumed by
* arbitrary listeners. The events emitted by a stream are defined by the
* operation that created the stream and can carry event-specific arguments.
*
* A stream is created in an open state, and may immediately emit events. When a
* Stream is closed it will emit a `close`. A closed stream will not
* emit any further events, and will remain closed permanently.
*
* It is possible for a stream to encounter an error. In this case, an `error` event will be emitted, and
* then the stream will be closed.
*
* This is a primitive class that is used to provide common event binding methods to other API components.
*
* @fires [error](../globals.html#error)
* @fires {@link close}
*/
export interface Stream {
/**
* Register listeners against events.
*
* A single listener may be bound to an event by passing the event name and
* listener function.
*
* Multiple listeners may be bound by passing in a {@link CallbackMap},
* mapping event names to listener functions.
*
* **Example:**
* ```
* // Bind a single listener to the 'foo' event
* stream.on('foo', function(arg1, arg2) {
* console.log("Called for 'foo' event", arg1, arg2);
* });
* ```
*
* **Example:**
* ```
* // Bind multiple listeners
* stream.on({
* foo : function() { ... },
* bar : function() { ... },
* baz : function() { ... }
* });
* ```
*
* It is possible to bind multiple listeners to the same event. In this case,
* the listeners will be called in the order they were bound.
*
* @param events the event name or {@link CallbackMap} mapping event names
* to listeners
* @param listener the listener to bind to the event, if passed as string.
* This argument is ignored if the first argument is a
* {@link CallbackMap}.
* @return this stream.
*/
on(events: string | CallbackMap, listener?: StreamCallback): Stream;
/**
* Remove a listener from a specified event.
*
* **Example:**
* ```
* // Bind a single listener to the 'foo' event and then deregister it
* var listener = function() {};
* stream.on('foo', listener);
* stream.off('foo', listener);
* ```
*
* **Example:**
* ```
* // Bind a listener to the 'foo' event and deregister all listeners
* var listener = function() {};
* stream.on('foo', listener);
* stream.off('foo');
* ```
*
* @param event the event name to remove or {@link CallbackMap} mapping
* event names to listeners which will be removed
* @param listener the listener to remove. All listeners for the event are
* removed if this is not specified. This argument is
* ignored if the first argument is a {@link CallbackMap}.
* @return this stream.
*/
off(events: string | CallbackMap, listener?: StreamCallback): Stream;
/**
* Close the stream. This will emit a 'close' event to any assigned listeners.
* No further events will be emitted.
*/
close(): void;
}
/**
* Emitted when an error occurs in the {@link Stream} or in any of its listeners.
* No further events will be emitted after this.
*
* @param error the error that occurred
*
* @event
*/ export declare type error = (err: Error) => void;
/**
* Emitted when the {@link Stream} has been closed through completion or the underlying session has been closed.
* No further events will be emitted after this.
*
* @param error the reason why the stream was closed
*
* @event
*/ export declare type close = (reason?: string) => void;
/**
* @module diffusion.events
*/
/**
* A subscription event
*/
export interface SubscriptionEvent {
/**
* The topic to which the subscription applies
*/
topic: string;
/**
* Instance that contains details about the topic
*/
specification: TopicSpecification;
}
/**
* An unsubscription event
*/
export interface UnsubscriptionEvent {
/**
* The topic to which the unsubscription applies
*/
topic: string;
/**
* Instance that contains details about the topic
*/
specification: TopicSpecification;
}
/**
* Provides a stream of topic events, specific to the topic selector that this ValueStream was created for, with
* topic values provided as instances of the associated {@link DataType}.
*
* ValueStream inherits all functions defined on {@link Stream}.
*
* **Example:**
* ```
* // Create a value stream for topic 'foo'
* session.addStream('foo', datatype).on('value', function(topic, specification, newValue, oldValue) {
* // Receive updates for the topic 'foo'
* });
*
* // Then subscribe to topic 'foo'
* session.select('foo');
* ```
*
* **Example:**
* ```
* // Attach multiple listeners for events
* session.addStream('foo', datatype).on({
* subscribe : function(topic, specification) {
* // Subscribed to a particular topic
* },
* unsubscribe : function(topic, specification, reason) {
* // Unsubscribed from a particular topic
* },
* value : function(topic, specification, newValue, oldValue) {
* // Value from a topic
* }
* });
* ```
*
* Events
*
* open
*
* Emitted when the subscription is initially opened, passing a reference to the
* subscription itself. This will only be fired once.
*
* subscribe
*
* Emitted when a topic that is selected by this ValueStream's topic selector is
* subscribed to by this session. Once subscribed, value update
* events may be received for this topic. The specification is a {@link
* TopicSpecification} instance that contains details about the topic.
*
* **Parameters:**
*
* `topic`: string - The topic to which the subscription applies
*
* `specification`: {@link TopicSpecification} - Instance that contains details about the topic
*
* unsubscribe
*
* Emitted when a topic that was previously subscribed, has been unsubscribed.
* No further update events will be received from this topic until subscribed
* again. Unsubscriptions may occur due to the topic being removed, or through
* calling {@link Session.unsubscribe} - an object containing the reason is
* provided.
*
* **Parameters:**
*
* `topic`: string - The topic to which the unsubscription applies
*
* `specification`: {@link TopicSpecification} - Instance that contains details about the topic
*
* `reason`: {@link UnsubscribeReason} - the reason for the unsubscription
*
* value
*
* Emitted when an update has been received for a topic's value. Values will be
* provided as instances appropriate for the associated {@link DataType} this
* subscription was created for. Both the previous value and the new value are
* provided.
*
* **Parameters:**
*
* `topic`: string - The topic to which the update applies
*
* `specification`: {@link TopicSpecification} - Instance that contains details about the topic
*
* `newValue`: any - the new value of the topic
*
* `oldValue`: any - the old value of the topic
*
* close
*
* Emitted when the subscription has been closed using {@link ValueStream.close}.
*
* error
*
* Emitted when the subscription request fails. No further events will be emitted after this.
*
* **Parameters:**
*
* `error`: {@link ErrorReason} - the error the subscription request failed with
*/
export interface ValueStream extends Stream {
/**
* A static reference to the selector this Subscription was created for.
*/
readonly selector: TopicSelector;
/**
* Close the stream. No further events will be emitted.
*
* This does not unsubscribe the topic. Other streams may still receive
* updates for the same topic selector. To unsubscribe, use {@link
* Session.unsubscribe}
*/
close(): void;
}
/**
* @module diffusion.clients
*/
/**
* Dictionary containing standard session property keys
*/
export interface PropertyKeys {
ALL_FIXED_PROPERTIES: string[];
ALL_USER_PROPERTIES: string[];
ALL_PROPERTIES: string[];
SESSION_ID: string;
PRINCIPAL: string;
CONNECTOR: string;
TRANSPORT: string;
CLIENT_TYPE: string;
COUNTRY: string;
LANGUAGE: string;
SERVER_NAME: string;
CLIENT_IP: string;
LATITUDE: string;
LONGITUDE: string;
START_TIME: string;
EXPIRY_TIME: string;
ROLES: string;
MQTT_CLIENT_ID: string;
GATEWAY_TYPE: string;
GATEWAY_ID: string;
ENVIRONMENT: string;
}
/**
* @hidden
*/
export interface ClientControlOptionsNamespace {
PropertyKeys: PropertyKeys;
ANONYMOUS: string;
CloseReason: typeof CloseReasonEnum;
SessionEventStreamEventType: typeof SessionEventStreamEventType;
SessionState: typeof SessionState;
}
export declare const ClientControlOptions: ClientControlOptionsNamespace;
/**
* @module Session.clients
*/
///
/**
* An object containing session properties
*/
export interface SessionProperties {
[key: string]: string | null;
}
/**
* Event types used within {@link SessionPropertiesListener.onSessionEvent}.
*
* **Example:**
* ```
* session.clients.setSessionPropertiesListener(props, {
* // ...
*
* onSessionEvent : function(sessionID, event, properties, previous) {
* switch (event) {
* case session.clients.SessionEventType.DISCONNECTED :
* console.log(sessionID + " has disconnected");
* break;
* case session.clients.SessionEventType.RECONNECTED :
* console.log(sessionID + " has reconnected");
* break;
* }
* }
*
* // ...
* });
* ```
*
* @deprecated since 6.11
*
* This type is required for the deprecated {@link SessionPropertiesListener}
* which is used with the deprecated {@link ClientControl.setSessionPropertiesListener}.
*
* Use the new {@link ClientControl.addSessionEventListener},
* which provides greater functionality and reports sessions at
* all cluster members. This interface will be removed in a
* future release.
*/
export declare enum SessionEventType {
/**
* One or more relevant session properties have been updated.
*/
UPDATED = 0,
/**
* A session has reconnected.
*/
RECONNECTED = 1,
/**
* A session has failed over from one server to another in a cluster.
*/
FAILED_OVER = 2,
/**
* A session has disconnected.
*/
DISCONNECTED = 3
}
/**
* This feature provides the ability for a client session to control other
* client sessions.
*
* It allows for notifications of client session events as well as the ability
* to manage client sessions (forcibly closing them etc).
*
* It also provides the ability to monitor session locks.
*
* This feature also provides the ability to query the topic selections of
* another session.
*
*
Access control
*
* A session must have
* {@link GlobalPermission.VIEW_SESSION VIEW_SESSION} permission to be able to
* listen for notifications using {@link ClientControl.addSessionEventListener} or
* {@link ClientControl.setSessionPropertiesListener}, or
* {@link ClientControl.getSessionProperties get properties} of sessions.
*
* In addition, {@link GlobalPermission.REGISTER_HANDLER REGISTER_HANDLER}
* permission is required to add a session event listener, a session property
* listener, or queue event handler.
*
* In order to perform operations that change a specific session's state (such
* as conflating, closing sessions, or changing roles),
* {@link GlobalPermission.MODIFY_SESSION MODIFY_SESSION} permission is
* required.
*
* To directly subscribe other sessions to topics, a session must have
* {@link GlobalPermission.MODIFY_SESSION MODIFY_SESSION} permission, and
* {@link PathPermission.SELECT_TOPIC SELECT_TOPIC} permission for the
* the topic selector used for subscription. The subscribed sessions
* will only be subscribed to matching topics for which they have
* {@link PathPermission.READ_TOPIC READ_TOPIC} permission.
*
* To directly unsubscribe other sessions, a session must have
* {@link GlobalPermission.MODIFY_SESSION MODIFY_SESSION} permission, and
* {@link PathPermission.SELECT_TOPIC SELECT_TOPIC} permission for the topic
* selector used for unsubscription.
*
* Getting the topic selections for a specified session requires
* {@link GlobalPermission.VIEW_SESSION VIEW_SESSION} permission.
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
* ```
* var clients = session.clients;
* ```
*/
export interface ClientControl {
/**
* Event types used within {@link SessionPropertiesListener.onSessionEvent}
*
* @deprecated since 6.11
* This property is required for the deprecated {@link SessionPropertiesListener}
* which is used with the deprecated {@link ClientControl.setSessionPropertiesListener}.
*
* Use the new {@link ClientControl.addSessionEventListener},
* which provides greater functionality and reports sessions at
* all cluster members. This interface will be removed in a
* future release.
*/ readonly SessionEventType: typeof SessionEventType;
/**
* Register a listener that will be notified of
* {@link SessionEvent client session events}.
*
* These events may occur when a client session is opened, becomes
* disconnected, reconnects, fails over, or is closed. Events may also occur
* if any of the session properties of the client session change as a result
* of a call to {@link ClientControl.setSessionProperties}.
*
* When a listener is first added, by default, it will be called with
* {@link SessionEventStreamEventType.STATE STATE} events
* for all currently open sessions. The amount of data transferred from the
* server is proportional to the number of connected clients and is
* potentially large, especially if session properties are requested. To
* mitigate this the caller can choose to only receive events for sessions
* started after a specified time (e.g. from now), in which case events will
* only be received for sessions that start after that time.
*
* A control session can register any number of listeners with different
* parameters, but the cost in network traffic should be carefully
* considered.
*
* When a listener is no longer required, it may be closed using the
* {@link Registration} provided by the Promise result.
*
* The `parameters` parameter is used to define the level of event
* detail required.
*
* @param listener the listener to be called with session event
* notifications
*
* @param parameters a {@link SessionEventParameters} object defining the
* level of event detail required.
*
* @return a Promise that completes when the listener has been
* registered, returning a {@link Registration} which can be used to
* unregister the listener.
*
* Otherwise, an error will be returned. Common reasons for
* failure include:
*
*
* - the session is closed;
*
- the session filter specified in the `parameters` was invalid;
*
- the session does not have
* {@link GlobalPermission.REGISTER_HANDLER REGISTER_HANDLER}
* and {@link GlobalPermission.VIEW_SESSION VIEW_SESSION} permissions.
*
*
* @since 6.11
*/
addSessionEventListener(listener: SessionEventStream, parameters: SessionEventParameters): Promise;
/**
* Close one or more client sessions.
*
* **Example:**
* ```
* session.clients.close(otherSessionID).then(function() {
* // Other session has been closed
* }, function(err) {
* // There was an error when trying to close the other session
* });
* ```
*
* @param sessions Either a {@link SessionId} that identifies a single
* client session, or a filter that identifies the set
* of client sessions for which the change will be
* applied. If a string is passed and is a parsable
* `SessionId`, it is treated as a `SessionId`, otherwise
* it assumed to be a filter.
* @return a Promise that resolves to the number of affected
* sessions
*
* If unsuccessful, the promise will be rejected. Common reasons
* for failure include:
*
* - {@link NullValueError} – if the session id is `null` or `undefined`
*/
close(sessions: string | SessionId): Promise;
/**
* Subscribe one or more client sessions to topics.
*
* To subscribe a single known session (anywhere in a cluster), a session id may be provided;
* alternatively, a Session Filter may be used, in which case all sessions (anywhere in a cluster)
* that satisfy the filter will be subscribed.
*
* New subscriptions will be established for existing topics that match the
* provided topic selector and for which the subscribed session has
* {@code READ_TOPIC} permission. The topic selector will be added to the
* topic selections of the subscribed session, and re-evaluated when new
* topics are added or the session's security roles change.
*
* A session that does not have {@code SELECT_TOPIC} permission for a topic
* cannot subscribe directly, but can be subscribed indirectly using this
* method.
*
* The second argument of this function can be a string, a {@link
* TopicSelector}, or a non-empty of strings and {@link TopicSelector}s.
*
* **Example:**
* ```
* // Subscribe a single session via SessionID
* session.clients.subscribe(otherSessionID, ">foo").then(function() {
* // Subscribed 'otherSession' to topic "foo"
* }, function(err) {
* // Subscription failed
* console.log("Failed to subscribe session", err);
* });
* ```
*
* **Example:**
* ```
* // Subscribe multiple sessions via a Session Filter
* session.clients.subscribe("$ClientType IS 'JAVA'", ">foo").then(function(selected) {
* console.log("Subscribed " + selected + " sessions to topic 'foo'");
* }, function(err) {
* // Subscription failed
* console.log("Failed to subscribe sessions", err);
* });
* ```
*
* @param session Either a {@link SessionId} that identifies a single
* client session, or a filter that identifies the set
* of client sessions for which the change will be
* applied. If a string is passed and is a parsable
* `SessionId`, it is treated as a `SessionId`, otherwise
* it assumed to be a filter.
* @param selector the Topic Selector(s) to subscribe to
* @param scope (optional) specifies the scope of the selection. See {@link Topics
* Topic Selection Scopes}. Defaults to {@link
* Topics.DEFAULT_SELECTION_SCOPE DEFAULT_SELECTION_SCOPE}.
* @return a Promise for this operation. If
* subscribing with a session filter, the success callback
* will be given the number of sessions selected by the
* filter.
*
* If unsuccessful, the promise will be rejected. Common reasons
* for failure include:
*
* - {@link IllegalArgumentError} – if the selector could not be parsed
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*/
subscribe(session: string | SessionId, selector: string | TopicSelector | Array, scope?: string): Promise;
/**
* Unsubscribe one or more client sessions from topics.
*
* To unsubscribe a single known session (anywhere in a cluster), a session id may be provided;
* alternatively, a Session Filter may be used, in which case all sessions (anywhere in a cluster)
* that satisfy the filter will be unsubscribed.
*
* The second argument of this function can be a string, a {@link
* TopicSelector}, or a non-empty of strings and {@link TopicSelector}s.
*
* **Example:**
* ```
* // Unsubscribe a single session via SessionID
* session.clients.unsubscribe(otherSessionID, ">foo").then(function() {
* // Unsubscribed 'otherSession' from topic "foo"
* }, function(err) {
* // Unsubscription failed
* console.log("Failed to unsubscribe session", err);
* });
* ```
*
* **Example:**
* ```
* // Unsubscribe multiple sessions via a Session Filter
* session.clients.unsubscribe("$ClientType IS 'JAVA'", ">foo").then(function(selected) {
* console.log("Unsubscribed " + selected + " sessions from topic 'foo'");
* }, function(err) {
* // Unsubscription failed
* console.log("Failed to unsubscribe sessions", err);
* });
* ```
*
* @param session Either a {@link SessionId} that identifies a single
* client session, or a filter that identifies the set
* of client sessions for which the change will be
* applied. If a string is passed and is a parsable
* `SessionId`, it is treated as a `SessionId`, otherwise
* it assumed to be a filter.
* @param selector the Topic Selector to unsubscribe from
* @param scope (optional) specifies the scope of the selection. See {@link Topics
* Topic Selection Scopes}. Defaults to {@link
* Topics.DEFAULT_SELECTION_SCOPE DEFAULT_SELECTION_SCOPE}.
* @return a Promise for this operation. If
* unsubscribing with a session filter, the success
* callback will be given the number of sessions selected
* by the filter
*
* If unsuccessful, the promise will be rejected. Common reasons
* for failure include:
*
* - {@link IllegalArgumentError} – if the selector could not be parsed
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*/
unsubscribe(session: string | SessionId, selector: string | TopicSelector | Array, scope?: string): Promise;
/**
* Unsubscribe topics from all topic selection scopes.
*
* This can be used at any time whilst connected to reduce the set of topics
* to which the session is subscribed or negate earlier subscription
* requests and will apply to all scopes in use.
*
* @param session Either a {@link SessionId} that identifies a single
* client session, or a filter that identifies the set
* of client sessions for which the change will be
* applied. If a string is passed and is a parsable
* `SessionId`, it is treated as a `SessionId`, otherwise
* it assumed to be a filter.
*
* @param topics the Topic Selector to unsubscribe from
*
* @return a Promise for this operation. If
* unsubscribing with a session filter, the success
* callback will be given the number of sessions selected
* by the filter
*
* If unsuccessful, the promise will be rejected. Common reasons
* for failure include:
*
* - {@link IllegalArgumentError} – if the selector could not be parsed
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*
* @since 6.12
*/
unsubscribeAllScopes(session: string | SessionId, topics: string | TopicSelector | Array): Promise;
/**
* Returns a map of the current topic selection state for a specified
* session, keyed on topic selection scope.
*
* Each scope will have an ordered list of selections and/or deselections.
*
* The server conflates selections, so if there has been a selection that is
* later rendered redundant by a deselection it will not be present. A scope
* that has been used but fully deselected will therefore not be present in
* the map and therefore no entry will have an empty list.
*
* If the session has no current selections the map will be empty.
*
* @param sessionId identifies the session to return topic selections for
*
* @return a Promise that completes when a response is received
* from the server with the results of the operation.
*
* If the task completes successfully, the Promise result
* will be a map of an ordered list of
* {@link TopicSelection}s keyed on scope. If the default scope is
* in use the key will be {@link Topics.DEFAULT_SELECTION_SCOPE}.
* If unsuccessful, the promise will be rejected. Common reasons
* for failure include:
*
* - {@link IllegalArgumentError} – if the selector could not be parsed
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*
*
* @since 6.12
*/
getTopicSelections(session: SessionId): Promise<{
[key: string]: TopicSelection[];
}>;
/**
* Query the server for property values of a specified client session.
*
* See {@link PropertyKeys} for a list of the available
* fixed property keys.
*
* To request all fixed properties {@link
* PropertyKeys.ALL_FIXED_PROPERTIES ALL_FIXED_PROPERTIES}
* may be included as the key.
*
* To request all user properties {@link
* PropertyKeys.ALL_USER_PROPERTIES ALL_USER_PROPERTIES}
* may be included as the key.
*
* **Example:**
* ```
* // Get values of all fixed properties for client whose session id is 'id'.
* session.clients.getSessionProperties(id, PropertyKeys.ALL_FIXED_PROPERTIES);
* ```
*
* **Example:**
* ```
* // Get values of the 'FOO' and 'BAR' properties for client whose session id is 'id'.
* session.clients.getSessionProperties(id, ['FOO', 'BAR']).then(function(properties) {
* console.log('Received properties for session', properties);
* }, function(err) {
* console.log('Unable to receive properties: ', err);
* });
* ```
*
* @param sessionID identifies the client session.
* @param properties specifies the keys of the property values required.
* @returns a Promise for this operation
*
* If unsuccessful, the promise will be rejected. Common reasons
* for failure include:
*
* - {@link IllegalArgumentError} – if the session id is invalid
*/
getSessionProperties(session: string | SessionId, properties?: string[]): Promise;
/**
* Send a request to the server to change the user-defined session
* properties for a session.
*
* It is also permissible to change the values of the following fixed
* session properties :-
*
* $Country - will be normalised to upper case
* $Language - will be normalised to lower case
* $Latitude - Invalid value will be set to "NaN"
* $Longitude - Invalid value will be set to "NaN"
*
* If values are provided for any other fixed session properties they will
* be ignored.
*
* **Example:**
* ```
* // Add a new session property for client whose session id is 'id'.
* session.clients.setSessionProperties(id, { 'foo': 'bar' });
*
* // Remove a session property for client whose session id is 'id'.
* session.clients.setSessionProperties(id, { 'foo': null }).then(function(properties) {
* console.log('Properties changed ', properties);
* }, function(err) {
* console.log('Unable to change properties: ', err);
* });
* ```
*
* @param session identifies the client session
* @param properties the properties to change. Each entry in the map is a
* property name and the new value. If the value is
* `null` , any existing property with that
* name will be removed (unless it is a fixed property).
* Otherwise if the property name does not match any existing
* property, that entry will be added as a new property
* (although properties starting $ will be ignored).
* @returns a Promise for this operation. If the session properties
* were updated, the result type is a map of properties that
* changed with their previous values. If no properties were
* changed, the map will be empty. If any new properties were
* added, the values in the map will be `null` to indicate that
* they do not have an old value.
*
* Otherwise, an error will be returned. Common reasons for
* failure include:
*
*
* - {@link ErrorReason.ACCESS_DENIED} if the calling session
* does not have sufficient permission.
*
- {@link ErrorReason.NO_SUCH_SESSION} if the calling session
* is closed before the response was delivered.
*
- {@link ErrorReason.SESSION_CLOSED} if the calling session
* is closed.
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*
*/
setSessionProperties(session: string | SessionId, properties: SessionProperties | Map): Promise;
/**
* Send a request to the server to set all sessions that satisfy a session
* filter with the new user-defined session properties.
*
* It is also permissible to change the values of the following fixed
* session properties :-
*
* $Country - will be normalised to upper case
* $Language - will be normalised to lower case
* $Latitude - Invalid value will be set to "NaN"
* $Longitude - Invalid value will be set to "NaN"
*
* If values are provided for any other fixed session properties they will
* be ignored.
*
* **Example:**
* ```
* // Remove session property {job=employee}
* session.clients.setSessionPropertiesByFilter("job is 'employee'", { 'job': null }).then(function () {
* // All sessions satisfied the filter have updated their properties
* }, function (err) {
* console.log("Failed to update properties ", err);
* });
* ```
* @param filter session filter
* @param properties the properties to change. Each entry in the map is a
* property name and the new value. If the value is
* `null` , any existing property with that
* name will be removed (unless it is a fixed property).
* Otherwise if the property name does not match any existing
* property, that entry will be added as a new property
* (although properties starting $ will be ignored).
*
* @returns a Promise that resolves when session properties have been changed.
*
* If successful, the result resolves with an integer value which
* represents a number of sessions that have matched the filter and
* for which the specified properties changes have been applied.
*
The operation can fail,
* common reasons for failure include:
*
* - {@link ErrorReason.ACCESS_DENIED} if the calling session
* does not have sufficient permission.
* - {@link ErrorReason.NO_SUCH_SESSION} if the calling
* session is closed before the response was delivered.
*
- {@link ErrorReason.SESSION_CLOSED} if the calling
* session is closed.
*
- a filter string was supplied that could not be parsed
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*
*/
setSessionPropertiesByFilter(filter: string, properties: SessionProperties | Map): Promise;
/**
* Register a listener that will be notified when client sessions are
* opened, disconnected, reconnected, closed or when selected session
* property values are updated.
*
* This only notifies sessions connecting to the same server as the current
* session and therefore if the Diffusion system is operating as a cluster
* then the only way to receive notifications for sessions at all cluster
* members would be to connect separate sessions (and listeners) to each
* cluster member. When connecting to a cluster it is recommended that the
* {@link ClientControl.addSessionEventListener addSessionEventListener}
* method is used instead.
*
* When a listener is first set, it will be called with the required
* properties of all currently open client sessions. The amount of data
* transferred from the server is proportional to the number of connected
* clients and is potentially large. The amount of data can be reduced
* using the requiredProperties parameter.
*
* The requested property set controls the level of detail provided and
* whether the listener is called for updates to sessions. If no
* properties are requested then the listener is not called when session
* properties are updated.
*
* To request all fixed properties {@link
* PropertyKeys.ALL_FIXED_PROPERTIES ALL_FIXED_PROPERTIES}
* should be included as a key and any other fixed property keys would be
* ignored. To request all user properties {@link
* PropertyKeys.ALL_USER_PROPERTIES ALL_USER_PROPERTIES}
* should be included as a key and any other user property keys supplied
* would be ignored.
*
* **Example:**
* ```
* // Specify desired properties to listen to
* var props = diffusion.clients.PropertyKeys.ALL_FIXED_PROPERTIES;
*
* // Create the listener
* var listener = {
* onActive : function(deregister) {
* // Listener is active
* },
* onSessionOpen : function(sessionID, properties) {
* // A session has been opened
* },
* onSessionEvent : function(sessionID, event, properties, previous) {
* // A session's properties have changed (specified by 'event')
* },
* onSessionClose : function(sessionID, properties, reason) {
* // A session has closed
* },
* onClose : function() {
* // Listener is closed
* }
* }
* session.clients.setSessionPropertiesListener(props, listener).then(function() {
* // Registration was succesful
* }, function(err) {
* // There was an error registering the session listener
* });
* ```
*
* @param properties a set of required property keys.
* @param listener the listener to register
* @returns a Promise for this operation.
*
* @deprecated since 6.11
*
* Use the new {@link ClientControl.addSessionEventListener addSessionEventListener},
* which provides greater functionality and reports on sessions at
* all cluster members. This method will be removed in a future release.
*/ setSessionPropertiesListener(properties: string[], listener: SessionPropertiesListener): Promise;
/**
* Changes the assigned roles of one or more sessions.
*
* Initially a session has a set of roles assigned during authentication.
* The set of assigned roles can be obtained from the session's `$Roles`
* {@link Session session} property.
*
* When a session's assigned roles change, its `$Roles` property changes
* accordingly. Changing the assigned roles can change the `READ_TOPIC`
* permissions granted to the session. The session's subscriptions will be
* updated accordingly.
*
* The same role must not occur in both `rolesToRemove` and
* `rolesToAdd` sets. Either set can be an empty set but not both.
*
* @param sessions Either a {@link SessionId} that identifies a single
* client session, or a filter that identifies the set
* of client sessions for which the change will be
* applied. If a string is passed and is a parsable
* `SessionId`, it is treated as a `SessionId`, otherwise
* it assumed to be a filter.
* @param rolesToRemove a set of roles to be removed from the session. If
* one or more roles from the list are not currently
* assigned, they are ignored.
* @param rolesToAdd a set of roles to be added to the session. If one or
* more roles from the list are already assigned, they
* are ignored.
* @return a Promise that resolves when session roles have been changed.
*
* If successful, the result resolves with an integer value which
* represents a number of sessions that have matched the filter and
* for which the specified role changes have been applied.
*
* Otherwise, the Promise fails with an Error. Common reasons for
* failure include:
*
* - the calling session does not have `MODIFY_SESSION` permission;
*
- a `SessionId` was supplied and there is no session with
* the given `sessionId`;
*
- a filter string was supplied that could not be parsed
*
- the calling session is closed.
*
- {@link IllegalArgumentError} – if both `rolesToRemove` and `rolesToAdd`
* are empty sets.
*
- {@link NullValueError} – if sessions `null` or `undefined`
*
*
* @since 6.3
*/
changeRoles(sessions: SessionId | string, rolesToRemove: string[] | Set, rolesToAdd: string[] | Set): Promise;
/**
* Returns details of the session (if any) that holds a named session lock.
*
* @param lockName the lock name
*
* @return a Promise that resolves with details of the named lock.
*
* If the Promise resolves normally then it returns the
* details of the session that currently holds the lock, or null if
* no session holds the named lock.
*
* Otherwise, the Promise will reject with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
* - {@link PermissionsException} – if the calling session
* does not have {@code VIEW_SERVER} permissions;
*
- {@link SessionClosedException} – if the calling session
* is closed.
*
* @since 6.12
*/
getSessionLock(lockName: string): Promise;
/**
* Returns details of all session locks currently held.
*
* @return a Promise that resolves with details of all session locks that are
* currently held.
*
* If the Promise resolves normally then it returns a map
* of session locks keyed on the lock name where the value
* identifies the session currently holding the lock. If there are
* no session locks currently held by anybody this will return an
* empty map.
*
* Otherwise, the Promise will reject with
* a {@link CompletionException}. Common reasons for failure, listed
* by the exception reported as the
* {@link CompletionException#getCause() cause}, include:
*
* - {@link PermissionsException} – if the calling session
* does not have {@code VIEW_SERVER} permissions;
*
- {@link SessionClosedException} – if the calling session
* is closed.
*
* @since 6.12
*/
getSessionLocks(): Promise<{
[key: string]: SessionLockDetails;
}>;
/**
* Control client queue conflation.
*
* Each session begins with conflation enabled or disabled based on the
* queue configuration of the connector it is using. This method allows
* conflation to be enabled or disabled for specific sessions at runtime.
*
* Conflation is the process of merging or discarding topic updates queued
* for a session to reduce the server memory footprint and network data.
* Conflation needs to be enabled for a session and a policy configured for
* the topic to have an effect. Policies are configured on a per-topic
* basis using the {@link CONFLATION topic property CONFLATION}.
*
* @param sessions Either a {@link SessionId} that identifies a single
* client session, or a filter that identifies the set
* of client sessions for which the change will be
* applied. If a string is passed and is a parsable
* `SessionId`, it is treated as a `SessionId`, otherwise
* it assumed to be a filter.
*
* @param conflate `true` to enable conflation, `false` to disable conflation
*
* @return a Promise that resolves to the number of affected
* sessions
*
* If the conflation policy was updated for the identified session,
* the Promise will resolve successfully.
*
* Otherwise, the Promise fails with an Error. Common reasons for
* failure include:
*
* - the identified session was closed before the response was
* delivered;
*
- the calling session does not have `MODIFY_SESSION` permission;
*
- the calling session is closed.
*
- {@link NullValueError} – if sessions is `null` or `undefined`
*
*
* @since 6.5
*/
setConflated(sessions: SessionId | string, conflated: boolean): Promise;
}
/**
* The Session Properties Listener interface for receiving session property
* events. This interface must be implemented by the user, to be registered via
* {@link ClientControl.setSessionPropertiesListener}.
*
* A session properties listener has a lifecycle that reflects the registration
* state on the server. This is expressed through the callback methods. Once
* {@link SessionPropertiesListener.onClose onClose} has been
* called, no further interactions will occur.
*
* @deprecated since 6.11
*
* Use the new {@link ClientControl.addSessionEventListener},
* which provides greater functionality and reports sessions at
* all cluster members. This interface will be removed in a
* future release.
*/
export interface SessionPropertiesListener {
/**
* Called when the listener has been registered at the server and is now
* active.
*
* @param deregister a function to call that will deregister and close this
* handler. The function will resolve when the handler
* has been deregistered.
*/
onActive(deregister: () => Promise): void;
/**
* Called when the listener is deregistered, or the session is closed.
*/
onClose(): void;
/**
* Notification of a contextual error related to this handler. This is
* analogous to an unchecked exception being raised. Situations in which
* onError is called include the session being closed before the
* handler is registered, a communication timeout, or a problem with the
* provided parameters. No further calls will be made to this handler.
*
* @param error the error
*
* @since 5.9
*/
onError(error: any): void;
/**
* Notification that a new client session has been opened.
*
* When the listener is registered, this will be called for all existing
* sessions. It will then be called for every client session that opens
* whilst the listener is registered.
*
* This will be called for client session regardless of requested session
* properties.
*
* @param session the session identifier
* @param properties the map of requested session property values.
*/
onSessionOpen(session: SessionId, properties: SessionProperties): void;
/**
* Notification of a session event that can result in a change of properties.
*
* @param session the session identifier
* @param type the type of event
* @param properties the map of requested property values
* @param previous a map of previous values for keys that have changed.
* This will only contain changed values and not the
* whole required property set.
*/
onSessionEvent(session: SessionId, type: SessionEventType, properties: SessionProperties, previous: SessionProperties): void;
/**
* Notification that a client session has closed.
*
* This will be called for every client that closes whilst the listener is
* registered, regardless of requested session properties.
*
* @param session the session identifier
* @param properties the map of requested property values
* @param reason the reason why the session was closed
*/
onSessionClose(session: SessionId, properties: SessionProperties, reason: ClientCloseReason): void;
}
/**
* The stream to receive for session event listener notifications.
*
* This is used along with {@link ClientControl.addSessionEventListener
* addSessionEventListener} to obtain notifications for client sessions.
*
* @since 6.11
*/
export interface SessionEventStream {
/**
* Notification of a session event.
*
* @param event the session event
*/
onSessionEvent(event: SessionEvent): void;
/**
* Notification that a stream context was closed normally.
*
* No further calls will be made for the stream context.
*/
onClose(): void;
/**
* Notification of a contextual error related to this callback. This is
* analogous to an exception being raised. Situations in which
* `onError` is called include the session being closed, a
* communication timeout, or a problem with the provided parameters. No
* further calls will be made to this callback for the call context.
*
* @param errorReason a value representing the error; this can be one of
* constants defined in {@link ErrorReason}, or a feature-specific
* reason
*/
onError(errorReason: ErrorReasonType): void;
}
/**
* The type of a {@link SessionEvent}.
*/
export declare enum SessionEventStreamEventType {
/**
* The event indicates a change of state of the identified
* session, including the opening of a new session.
*/
STATE = 0,
/**
* The event indicates a change to the session properties of the
* identified session.
*/
PROPERTIES = 1
}
/**
* The session state as given by a {@link SessionEvent}.
*/
export declare enum SessionState {
/**
* The session is connected and active.
*/
ACTIVE = 0,
/**
* The session is disconnected.
*/
DISCONNECTED = 1,
/**
* The session has reconnected to the same server after a
* disconnection.
*/
RECONNECTED = 2,
/**
* The session has failed over to a different server in the
* cluster after a disconnection.
*/
FAILED_OVER = 3,
/**
* The session has closed.
*/
CLOSED = 4
}
/**
* The interface for an event delivered by a {@link SessionEventStream}.
*/
export interface SessionEvent {
/**
* Provides the session identifier of the client session that the
* event relates to.
*
* @return the client session id
*/
readonly sessionId: SessionId;
/**
* Provides the event type.
*
* @return the event type
*/
readonly type: SessionEventStreamEventType;
/**
* Provides the current state of the session.
*
* @return the session state
*/
readonly state: SessionState;
/**
* Provides the session's properties.
*
* Only those properties requested when registering the listener
* will be present in the map.
*
* If no properties were requested or {@link SessionEvent.state} is
* {@link SessionState.CLOSED CLOSED} the map will be empty.
*
* @return the map of session properties
*/
readonly properties: SessionProperties;
/**
* Provides a map of the previous values of session properties that
* have changed.
*
* This map will be empty if no session properties were requested or
* the event did not result in a change of any properties.
*
* This map will only be populated if {@link SessionEvent.type} is
* {@link SessionEventStreamEventType.PROPERTIES PROPERTIES} or {@link SessionEvent.state} is
* {@link SessionState.RECONNECTED RECONNECTED}, {@link SessionState.FAILED_OVER
* FAILED_OVER}, or {@link SessionState.DISCONNECTED DISCONNECTED}.
*
* This will only contain keys that have changed and not the whole
* required property set.
*
* When a new property is added the value in this map will be
* `null`.
*
* When a property is removed there will be a value in this map but
* not in {@link SessionEvent.properties}.
*
* @return the changed session properties
*/
readonly changedProperties: SessionProperties;
/**
* Provides the reason a session was closed.
*
* If {@link SessionEvent.state} is {@link SessionState.CLOSED CLOSED} this contains the
* reason the session was closed.
*
* @return the reason for session closure or null if {@link SessionEvent.state}
* is not {@link SessionState.CLOSED CLOSED}.
*/
readonly closeReason?: ClientCloseReason;
/**
* Convenience method to determine whether the event notifies the
* opening of a new session.
*
* This is equivalent to:
*
*
* event.type == Type.STATE && event.state == State.ACTIVE
*
*
* @return true if the type is `STATE` and the state is `ACTIVE`,
* otherwise false
*/
isOpenEvent(): boolean;
}
/**
* A builder for {@link SessionEventParameters}.
*
* An instance of such a builder is created using {@link newSessionEventParametersBuilder}.
*/
export interface SessionEventParametersBuilder {
/**
* Sets a session filter which will determine which sessions events
* will be notified for.
*
* See {@link Session} for a full description of how to specify
* session filters.
*
* If no filter is specified then notifications will be provided for
* all sessions that satisfy any other specified requirements.
*
* Specifying `null` will remove any current filter from the
* builder.
*
* @param filter the session filter
*
* @return this builder
*/
filter(filter: string): SessionEventParametersBuilder;
/**
* Specifies the session property keys of all session properties to
* be returned with events.
*
* See {@link Session} for a full list of available fixed property
* keys.
*
* To request all fixed properties include
* {@link PropertyKeys.ALL_FIXED_PROPERTIES} as a key. In this case any
* other fixed property keys would be ignored.
*
* To request all user properties include
* {@link PropertyKeys.ALL_USER_PROPERTIES} as a key. In this case any
* other user properties are ignored.
*
* If this is not specified (or no property keys are provided) then
* no session property values will be returned with the events and
* events of type
* {@link SessionEventStreamEventType.PROPERTIES
* PROPERTIES} will not be notified.
*
* @param properties a list of required property keys
*
* @return this builder
*/
properties(properties: string[]): SessionEventParametersBuilder;
properties(...properties: string[]): SessionEventParametersBuilder;
/**
* Used to indicate that events are only to be reported for sessions
* that start after a specified time.
*
* If this is not set, the default is to notify events for all
* current sessions, even if they started before registration of the
* listener. This could potentially result in a large number of
* events for all current sessions.
*
* If the user is only interested in new sessions
* `after(Date.now())` could be used.
*
* @param time only sessions starting after the specified time will
* be notified. Specifying null will remove any previously
* specified time from the builder. The time can be specified
* as a Unix timestamp in milliseconds or as a Date object.
*
* @return this builder
*/
after(time: number | Date): SessionEventParametersBuilder;
/**
* Builds a new {@link SessionEventParameters} instance with the current settings of the
* builder.
*
* @return a new {@link SessionEventParameters} instance
*/
build(): SessionEventParameters;
}
/**
* Provides parameters which specify the level of detail required by a
* {@link SessionEventStream} registered using
* {@link ClientControl.addSessionEventListener addSessionEventListener}.
*
* Parameters may be built using the {@link SessionEventParametersBuilder}.
*
* @since 6.11
*/
export interface SessionEventParameters {
/**
* Indicates the session filter or `undefined` if one has not been set
*/
readonly filter?: string;
/**
* Indicates the requested properties or `undefined` if none have been set
*/
readonly properties?: Set;
/**
* Indicates a session start time after which session events should be
* notified or `undefined` if one has not been set.
*/
readonly after?: number;
}
/**
* Provides details of a session lock.
*
* @since 6.12
*/
export interface SessionLockDetails {
/**
* Returns the name of the server that the session holding the lock is
* connected to.
*
* @return the server name
*/
readonly serverName: string;
/**
* Returns the session identifier of the session that holds the lock.
*
* @return the session holding the lock
*/
readonly sessionId: SessionId;
/**
* Returns the lock sequence number.
*
* @return lock sequence number
*/
readonly sequence: Long;
}
/**
* @module Session.messages
*/
/**
* Messages Feature.
*
* This feature provides a client session with request-response messaging
* capabilities that can be used to implement application services.
*
* Request-response messaging allows a session to send requests to other
* sessions. Each receiving session provides a corresponding response, which is
* returned to the sending session. Each request and response carries an
* application provided value.
*
* The method used to send a request determines which sessions will receive it.
* Each request is routed using the provided *message path* – an application
* provided string. Two addressing schemes are provided: *unaddressed requests*
* and *addressed requests*.
*
* ### Unaddressed requests
*
* A session can provide an application service by implementing a handler and
* registering it with the server. This is somewhat similar to implementing a
* REST service, except that interactions between the sender and receiver are
* asynchronous.
*
* Unaddressed requests sent using {@link Messages.sendRequest sendRequest} are
* routed by the server to a handler that has been pre-registered by another
* session, and matches the message path.
*
* Handlers are registered with {@link Messages.addRequestHandler}. Each session
* may register at most one handler for a given message path. Optionally, one or
* more session property names can be provided (see {@link Session} for a full
* description of session properties), in which case the values of the session
* properties for each recipient session will be returned along with its
* response. To add a request handler, the control client session must have
* {@link GlobalPermission.REGISTER_HANDLER REGISTER_HANDLER} permission. If
* registering to receive session property values, the session must also have
* {@link GlobalPermission.VIEW_SESSION VIEW_SESSION} permission.
*
* Routing works as follows:
*
*
* - The session {@link Messages.sendRequest sends} the request, providing the
* message path, the request value and data type, and the expected response
* type.
*
- The server uses the message path to apply access control. The sender must
* have the {@link PathPermission.SEND_TO_MESSAGE_HANDLER
* SEND_TO_MESSAGE_HANDLER} path permission for the message path, or the request
* will be rejected.
*
- The server uses the message path to select a pre-registered handler and
* route the request to the appropriate recipient session. The server will
* consider all registered handlers and select one registered for the most
* specific path. If multiple sessions have registered a handler registered for
* a path, one will be chosen arbitrarily. If there is no registered handler
* matching the message path, the request will be rejected.
*
- Otherwise, the server forwards the request to one of the sessions
* registered to handle the message path. The message path is also passed to the
* recipient session, providing a hierarchical context.
*
- The recipient session processes the request and returns a response to the
* server, which forwards the response to the sending session.
*
*
* Registration works across a cluster of servers. If no matching handler is
* registered on the server to which the sending session is connected, the
* request will be routed to another server in the cluster that has one.
*
* ### Addressed requests
*
* Addressed requests provide a way to perform actions on a group of sessions,
* or to notify sessions of one-off events (for repeating streams of events, use
* a topic instead).
*
* An addressed request can be sent to a set of sessions using {@link
* Messages.sendRequestToFilter sendRequestToFilter}. For the details of session
* filters, see {@link Session}. Sending a request to a filter will match zero
* or more sessions. Each response received will be passed to the provided
* {@link FilteredResponseHandler callback}. As a convenience, an addressed
* request can be sent a specific session using the overloaded variant of {@link
* Messages.sendRequest sendRequest} that accepts a session id.
*
* Sending an addressed request requires {@link PathPermission.SEND_TO_SESSION
* SEND_TO_SESSION} permission.
*
* If the sending session is connected to a server belonging to a cluster, the
* recipient sessions can be connected to other servers in the cluster. The
* filter will be evaluated against all sessions hosted by the cluster.
*
* To receive addressed requests, a session must set up a local request stream
* to handle the specific message path, using {@link Messages.setRequestStream
* setRequestStream}. When a request is received for the message path, the
* {@link RequestStream.onRequest onRequest} method on the stream is triggered.
* The session should respond using the provided {@link Responder
* responder}. Streams receive an {@link RequestStream.onClose onClose} callback when
* unregistered and an {@link RequestStream.onError onError} callback if the session is
* closed.
*
* If a request is sent to a session that does not have a matching stream for
* the message path, an error will be returned to the sending session.
*
* ### Accessing the feature
*
* Obtain this feature from a {@link Session session} as follows:
*
* **Example:**
* ```
* // Get a reference to messaging feature
* var messages = session.messages;
* ```
*/
export interface Messages {
/**
* Register a request handler to handle requests from other client sessions
* for a branch of the message path hierarchy.
*
* Each control session may register a single handler for a branch. When the
* handler is no longer required, it may be closed using the {@link
* Registration} provided by the result. To change the handler for a
* particular branch the previous handler must first be closed.
*
* **Example:**
* ```
* // Create a request handler that handles strings
* var handler = {
* onRequest: function(request, context, responder) {
* console.log(request); // Log the request
* responder.respond('something');
* },
* onError: function() {},
* onClose: function() {}
* };
*
* // Register the handler
* control.messages.addRequestHandler('test/path', handler).then(function() {
* // Registration happened successfully
* }, function(error) {
* // Registration failed
* });
* ```
*
* @param path the request path to handle
* @param handler request handler to be registered at the server
* @param sessionProperties an optional array of keys of session properties
* that should be supplied with each request. See {@link Session} for
* a full list of available fixed property keys. To request all fixed
* properties include {@link PropertyKeys.ALL_FIXED_PROPERTIES} as a
* key. In this case any other fixed property keys would be ignored.
* To request all user properties include {@link
* PropertyKeys.ALL_USER_PROPERTIES} as a key. In this case any other
* user properties are ignored.
* @param requestType an optional request data type
* @returns the registration {@link Promise} that resolves
* when the handler has been registered, returning a {@link
* Registration} which can be used to unregister the handler.
*
* Otherwise, the Promise will fail with an error. Common reasons for
* failure include:
*
* - the session is closed;
*
- the session has already registered a handler for this message
* path;
*
- the session does not have `REGISTER_HANDLER` permission to
* register a request handler on the server;
*
- the session does not have `VIEW_SESSION` permission to access
* the client's session properties.
*
- {@link NullValueError} – if any of the required arguments are
* `null` or `undefined`
*
*/
addRequestHandler(path: string, handler: RequestHandler, sessionProperties?: string[], requestType?: DataType): Promise;
/**
* Send a request. If a `target` is supplied, the request will be sent to
* the target session only.
*
* A response is returned when the {Promise} is complete.
*
* **Example:**
* ```
* // Send a string request to be received by the server and passed to a
* // {Session.messages.RequestHandler} registered on the supplied path
* session.messages.sendRequest('test/path', 'string request');
* ```
*
* **Example:**
* ```
* // Send a JSON request to be received by the server and passed to a
* // {Session.messages.RequestHandler} registered on the supplied path
* session.messages.sendRequest('test/path', diffusion.datatypes.json()
* .from({ 'foo': 'bar'}), diffusion.datatypes.json());
* ```
*
* **Example:**
* ```
* // Send an implicit JSON request to be received by the server and passed to a
* // {Session.messages.RequestHandler} registered on the supplied path
* session.messages.sendRequest('test/path', {
* dwarfs: ['sneezy', 'sleepy','dopey',
* 'doc', 'happy', 'bashful',
* 'grumpy']
* });
* ```
*
* @param path the path to send the request to
* @param request the request to send
* @param target the target recipient's session ID (as a string or Session ID object)
* @param requestType an optional request {@link DataType DataType}
* @param responseType an optional response {@link DataType DataType}
* @return A {@link Promise} that resolves with the response when a response
* has been received by the session if the task completes
* successfully.
*
* Otherwise, the Promise will fail with an Error. Common reasons for
* failure include:
*
* - the session does not exist on the server;
*
- the recipient session does not have a local request stream
* registered for this path;
*
- the request is not compatible with the datatype bound to the
* handler's message path;
*
- the response is not compatible with the specified response
* type;
*
- the request has been rejected by the recipient session
* calling `Responder.reject(message)`;
*
- the session is closed;
*
- the session does not have `SEND_TO_SESSION` permission;
*
- {@link IllegalArgumentError} – the request could not be parsed by
* the calling client;
*
- {@link InvalidDataError} – the response could not be parsed;
*
- {@link NullValueError} – if any of the required arguments are
* `null` or `undefined`
*
*/
sendRequest(path: string, request: any, target: SessionId | string, requestType?: DataType | TopicType | (new (...args: any[]) => any) | string, responseType?: DataType | TopicType | (new (...args: any[]) => any) | string): Promise;
sendRequest(path: string, request: any, requestType?: DataType | TopicType | (new (...args: any[]) => any) | string, responseType?: DataType | TopicType | (new (...args: any[]) => any) | string): Promise;
/**
* Send a request to all sessions that satisfy a given session filter.
*
* **Example:**
* ```
* // Send a string request to be received by the server and passed to sessions matching the filter.
* session.messages.sendRequestToFilter('$Principal NE 'control'', 'test/path', 'string request',
* {
* onResponse: (sessionID, response) => {
* console.log(response); // Log the response
* },
* onResponseError : () => {}
* });
* ```
*
* **Example:**
* ```
* // Send a JSON request to be received by the server and passed to sessions matching the filter.
* session.messages.sendRequestToFilter('$Principal NE 'control'', 'test/path',
* { dwarfs: ['sneezy', 'sleepy','dopey' ] },
* {
* onResponse: (sessionID, response) => {
* console.log(response.get()); // Log the response
* },
* onResponseError: () => {}
* }, diffusion.datatypes.json(), diffusion.datatypes.json());
* ```
*
* @param filter the session filter expression. See {@link Session}
* for a full description of filter expressions.
* @param path message path used by the recipient to select an
* appropriate handler
* @param request the request to send
* @param callback the handler to receive notification of responses
* (or errors) from sessions
* @param requestType an optional request {@link DataType DataType}
* @param responseType an optional response {@link DataType DataType}
* @return a Promise that resolves when the server has dispatched all the
* requests.
*
* If the server successfully evaluated the filter, the result of
* this contains the number of sessions the request was sent to.
* Failure to send a request to a particular matching session is
* reported to the `callback`.
*
* Otherwise, the Promise will fail with an Error. Common reasons for
* failure include:
*
* - the `filter` parameter could not be parsed;
*
- the calling session does not have `SEND_TO_SESSION` permission;
*
- the calling session is closed.
*
- {@link IllegalArgumentError} – the request could not be parsed by
* the calling client;
*
- {@link NullValueError} – if any of the required arguments are
* `null` or `undefined`
*
*/
sendRequestToFilter(filter: string, path: string, request: any, callback: FilteredResponseHandler, requestType?: DataType | TopicType | (new (...args: any[]) => any), responseType?: DataType | TopicType | (new (...args: any[]) => any)): Promise;
/**
* Set a request stream to handle requests to a specified path.
*
* **Example:**
* ```
* // Set a request stream handler to handle string requests to 'test/path'
* var handler = {
* onRequest: function (path, request, responder) {
* console.log(request);
* responder.respond('hello');
* },
* onError: function() {}
* };
*
* control.messages.setRequestStream('test/path', handler,
* diffusion.datatypes.string(), diffusion.datatypes.string());
* ```
*
* @param path the path to receive request on
* @param stream the request stream to handle requests to this path
* @param requestType an optional request {@link DataType DataType}
* @param responseType an optional response {@link DataType DataType}
* @returns `undefined` if the request stream is the first stream
* to be set to the path, otherwise this method will
* return the previously set request stream.
*/
setRequestStream(path: string, stream: RequestStream, requestType?: DataType | TopicType | (new (...args: any[]) => any), responseType?: DataType | TopicType | (new (...args: any[]) => any)): RequestStream | undefined;
/**
* Remove the request stream at a particular path.
*
* @param path the path at which to remove the request stream
* @returns the request stream that was removed from the path. If
* the path does not have a request stream assigned (or the
* path does not exist), `undefined` will be returned instead.
*/
removeRequestStream(path: string): RequestStream | undefined;
}
/**
* Interface which specifies a request stream to receive request notifications.
*/
export interface RequestStream {
/**
* Called to indicate a request has been received.
*
* @param path the path the request was sent on
* @param request the request that was received
* @param responder the responder to dispatch a response back to the requester
*/
onRequest(path: string, request: any, responder: Responder): void;
/**
* Notification of a contextual error related to this stream. This is
* analogous to an Error being thrown. Situations in which
* `onError` is called include being unable to parse the request
* with the data type the stream was registered with. No further calls will
* be made to this stream.
*
* @param error the error
*/
onError(error: ErrorReasonType): void;
/**
* Called when the request stream is removed, or the session is closed.
*/
onClose(): void;
}
/**
* Interface which specifies a request handler to receive request notifications.
*
* @class Session.messages.RequestHandler
*/
export interface RequestHandler {
/**
* Called to indicate a request has been received.
*
* @param {Object} request - The request that was received
* @param {Session.messages.RequestContext} context - Context object that provides the session id
* (session that sent the request), path and session properties
* @param {Session.messages.Responder} responder - The responder to dispatch a response back to the requester
* @function Session.messages.RequestHandler.onRequest
*/
onRequest(request: any, context: RequestContext, responder: Responder): void;
/**
* Notification of a contextual error related to this handler. This is
* analogous to an Error being thrown. Situations in which
* `onError` is called include the session being closed before the
* handler is registered, a communication timeout, or a problem with the
* provided parameters. No further calls will be made to this handler.
*
* @param error the error
*/
onError(error: any): void;
/**
* Called when the request handler is unregistered, or the session is closed.
*/
onClose(): void;
}
/**
* Interface which specifies a response handler for requests dispatched through
* a filter.
*/
export interface FilteredResponseHandler {
/**
* Called to indicate a response has been received.
*
* @param sessionId session ID of the session that sent the response
* @param response response object
* @function Session.messages.FilteredResponseHandler.onResponse
*/
onResponse(sessionId: SessionId, response: any): void;
/**
* Called when a response from a session results in an error.
*
* @param sessionId sessionID of the session in error
* @param errorReason the error reason
*/
onResponseError(sessionId: SessionId, error: Error): void;
}
/**
* Responder interface to dispatch responses to requests.
*/
export interface Responder {
/**
* Dispatch a response to a request.
*
* @param response the response to send
* @param dataType the datatype of the response
* @throws an {@link IllegalArgumentError} if the response cannot be serialised
*/
respond(response: any, dataType?: DataType | TopicType | (new (...args: any[]) => any)): void;
/**
* Reject a message
*
* @param message the message indicating the failure
*/
reject(message: string): void;
}
/**
* A message request context
*/
export interface RequestContext {
/**
* SessionId of the session that sent the request
*/
sessionId: SessionId;
/**
* The message path of the request
*/
path: string;
/**
* The session properties
*/
properties: {
[key: string]: string;
};
}
/**
* This feature allows a client to configure metric collectors.
*
* Diffusion servers provide metrics which are made available in several ways:
*
* - Java Management Extensions (JMX) MBeans.
*
- Through the Diffusion Management Console.
*
- As endpoints for Prometheus.
*
*
* Metric collectors allow custom aggregation of metrics that are relevant to
* your application. There are no default metric collectors, only the ones that
* you create.
*
* There are two types of metric collector: Session Metric Collectors and Topic
* Metric Collectors.
*
* For full details regarding the configuration and operation of metric
* collectors see the user manual.
*
* Session Metric Collectors.
*
* These can be configured to record metric data for a subset of all sessions,
* specified with a session filter.
*
* The set of metrics recorded by each session metric collector is the same as
* those recorded for the whole server. For full details of session metrics, see
* the table in the user manual.
*
* If the session filters of two different session metric collectors select the
* same session, both will record metrics for that session. It is only valid to
* add the metrics of different session metric collectors if their session
* filters select distinct sets of sessions.
*
* You can optionally group the sessions within a collector by session
* properties.
*
* Topic Metric Collectors
*
* These can be configured to record metric data for a subset of all topics,
* specified with a topic selector.
*
* You can optionally group the topics within a collector by topic type.
*
* The set of metrics recorded by each topic metric collector is the same as
* those recorded for the whole server. For full details of topic metrics, see
* the table in the user manual.
*
* If the topic selectors of two different topic metric collectors select the
* same topic, both will record metrics for that topic. It is only valid to add
* the metrics of different topic metric collectors if their topic selectors
* select distinct sets of topics.
*
* Access control
*
* The following access control restrictions are applied:
*
* - To {@link Metrics.putSessionMetricCollector put} or
* {@link Metrics.removeSessionMetricCollector remove} a session metric collector, a
* session needs the {@link GlobalPermission.CONTROL_SERVER CONTROL_SERVER}
* global permission.
*
- To {@link Metrics.putTopicMetricCollector put} or
* {@link Metrics.removeTopicMetricCollector remove} a topic metric collector, a
* session needs the {@link GlobalPermission.CONTROL_SERVER CONTROL_SERVER}
* global permission.
*
- To list {@link Metrics.listSessionMetricCollectors session metric collectors} or
* {@link Metrics.listTopicMetricCollectors topic metric collectors}, a session needs
* the {@link GlobalPermission.VIEW_SERVER VIEW_SERVER} global permission.
*
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
*
* const metrics = session.metrics;
*
*
* @author DiffusionData Limited
*
* @since 6.7
*/
export interface Metrics {
/**
* Add a session metric collector, replacing any with the same name.
*
* A {@link SessionMetricCollector} instance can be created using
* {@link newSessionMetricCollectorBuilder}.
*
* @param collector the session metric collector
*
* @return a Promise that resolves when a response is received
* from the server.
*
* If the task completes successfully, the result will be null. The
* result type is `any` rather than `void` to provide forward
* compatibility with future iterations of this API that may provide
* a non-null result with a more specific result type.
*
* Otherwise, the Promise will reject with an Error. Common reasons
* for failure include:
*
* - if the metric collector session filter is invalid;
*
- if the calling session does not have {@link
* GlobalPermission.CONTROL_SERVER CONTROL_SERVER} permission;
*
- if the operation failed due to a transient cluster error;
*
- if the session is closed.
*
- {@link NullValueError} – if the collector is `null` or `undefined`
*
*/
putSessionMetricCollector(collector: SessionMetricCollector): Promise;
/**
* Retrieves the current session metric collectors.
*
* @return a Promise that completes when a response is received
* from the server.
*
* If the task completes successfully, the result will be a list of
* current session metric collectors.
*
* Otherwise, the Promise will reject with an Error. Common reasons
* for failure include:
*
* - if the calling session does not have {@link
* GlobalPermission.VIEW_SERVER VIEW_SERVER} permission;
*
- if the session is closed.
*
*/
listSessionMetricCollectors(): Promise;
/**
* Removes any session metric collector with the given name, if it exists.
*
* @param name the session metric collector name
*
* @return a Promise that resolves when a response is received
* from the server.
*
* If the task completes successfully, the result will be null. The
* result type is `any` rather than `void` to provide forward
* compatibility with future iterations of this API that may provide
* a non-null result with a more specific result type.
*
* Otherwise, the Promise will reject with an Error. Common reasons
* for failure include:
*
* - if the calling session does not have {@link
* GlobalPermission.CONTROL_SERVER CONTROL_SERVER} permission;
*
- if the operation failed due to a transient cluster error;
*
- if the session is closed.
*
- {@link NullValueError} – if the name is `null` or `undefined`
*
*/
removeSessionMetricCollector(name: string): Promise;
/**
* Add a topic metric collector, replacing any with the same name.
*
* A {@link TopicMetricCollector} instance can be created using
* {@link newTopicMetricCollectorBuilder}.
*
* @param collector the topic metric collector
*
* @return a Promise that resolves when a response is received from the
* server.
*
* If the task completes successfully, the result will be null. The
* result type is `any` rather than `void` to provide forward
* compatibility with future iterations of this API that may provide
* a non-null result with a more specific result type.
*
* Otherwise, the Promise will reject with an Error. Common reasons
* for failure include:
*
* - if the metric collector session filter is invalid;
*
- if the calling session does not have {@link
* GlobalPermission.CONTROL_SERVER CONTROL_SERVER} permission;
*
- if the operation failed due to a transient cluster error;
*
- if the session is closed.
*
- {@link NullValueError} – if the collector is `null` or `undefined`
*
*/
putTopicMetricCollector(collector: TopicMetricCollector): Promise;
/**
* Retrieves the current topic metric collectors.
*
* @return a Promise that completes when a response is received
* from the server.
*
* If the task completes successfully, the result will be a list of
* current topic metric collectors.
*
* Otherwise, the Promise will reject with an Error. Common reasons
* for failure include:
*
* - if the calling session does not have {@link
* GlobalPermission.VIEW_SERVER VIEW_SERVER} permission;
*
- if the session is closed.
*
*/
listTopicMetricCollectors(): Promise;
/**
* Removes any topic metric collector with the given name, if it exists.
*
* @param name the topic metric collector name
*
* @return a Promise that resolves when a response is received from the
* server.
*
* If the task completes successfully, the result will be null. The
* result type is `any` rather than `void` to provide forward
* compatibility with future iterations of this API that may provide
* a non-null result with a more specific result type.
*
* Otherwise, the Promise will reject with an Error. Common reasons
* for failure include:
*
* - if the calling session does not have {@link
* GlobalPermission.CONTROL_SERVER CONTROL_SERVER} permission;
*
- if the operation failed due to a transient cluster error;
*
- if the session is closed.
*
- {@link NullValueError} – if the collector is `null` or `undefined`
*
*/
removeTopicMetricCollector(name: string): Promise;
/**
* Creates an unconfigured {@link MetricsRequest}. The request can be invoked using
* {@link MetricsRequest.fetch} to retrieve metrics for the server or cluster.
*
* See {@link MetricsRequest} for more information.
*
* @return a new {@link MetricsRequest}
*
* @since 6.10
*/
metricsRequest(): MetricsRequest;
/**
* Set or update a metric alert with a given name and specification.
*
* This method creates or updates a metric alert. If an alert with the
* specified name already exists, it will be overwritten with the new
* specification.
*
* @param name the name of the metric alert. This name is used to uniquely
* identify the alert.
* @param specification the specification
* of the metric alert. This defines the conditions under which the
* alert is triggered and the actions to be taken.
* @return a Promise that resolves when a response is received
* from the server. If the operation is successful, the Promise
* resolves normally.
*
* If the task fails, the Promise will reject with an Error. Common
* reasons for failure, listed by the exception, include:
*
*
* - {@link ScriptException} – if {@code specification} is
* invalid;
*
- {@link ClusterRoutingException} – if the operation
* failed due to a transient cluster error;
*
- {@link PermissionsException} – if the calling session
* does not have CONTROL_SERVER permission;
*
- {@link SessionClosedException} – if the session is
* closed;
*
*
* @since 6.12
*/
setMetricAlert(name: string, specification: string): Promise;
/**
* List all metric alerts that have been created.
*
* @return a Promise that resolves when a response is received
* from the server, returning a list of metric alerts sorted by their
* creation order.
*
* If the task fails, the Promise will reject with an Error. Common
* reasons for failure, listed by the exception, include:
*
*
* - {@link ClusterRoutingException} – if the operation
* failed due to a transient cluster error;
*
- {@link PermissionsException} – if the calling session
* does not have CONTROL_SERVER permission;
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @since 6.12
*/
listMetricAlerts(): Promise;
/**
* Remove a named metric alert if it exists.
*
* If the named alert does not exist, the Promise will complete
* successfully.
*
* @param name the name of the metric alert
* @return a Promise that resolves when a response is received
* from the server.
*
* If the task fails, the Promise will reject with an Error. Common
* reasons for failure, listed by the exception, include:
*
*
* - {@link ClusterRoutingException} – if the operation
* failed due to a transient cluster error;
*
- {@link PermissionsException} – if the calling session
* does not have CONTROL_SERVER permission;
*
- {@link SessionClosedException} – if the session is
* closed.
*
*
* @since 6.12
*/
removeMetricAlert(name: string): Promise;
}
/**
* A list of session metric collectors
*/
export interface SessionMetricCollectorList {
/**
* The collectors.
*/
readonly collectors: SessionMetricCollector[];
}
/**
* A list of session metric collectors
*/
export interface TopicMetricCollectorList {
/**
* The collectors.
*/
readonly collectors: TopicMetricCollector[];
}
/**
* The common base interface for metric collectors.
*/
export interface MetricCollector {
/**
* the name of the metric collector
*/
readonly name: string;
/**
* Indicates whether the metric collector exports to Prometheus.
*/
readonly exportToPrometheus: boolean;
/**
* Limit on the number of groups maintained by this metric collector.
*
* Session metric collectors can
* {@link SessionMetricCollector.groupByProperties group metrics by
* property}. Topic metric collectors can
* {@link TopicMetricCollector.groupByTopicType group metrics by
* topic type}. This property places an upper limit on the number of
* groups that will be maintained for the metric collector.
*
* For example, if a session metric collector groups by `$SessionId` and
* maximumGroups is 10, then metrics will only be collected for the
* first 10 sessions.
*
* @since 6.8
*/
readonly maximumGroups: number;
}
/**
* The definition of a session metric collector.
*
* These can be configured to record metric data for a subset of all
* sessions, specified with a session filter.
*/
export interface SessionMetricCollector extends MetricCollector {
/**
* the session filter
*/
readonly sessionFilter: string;
/**
* list of properties to group by
*/
readonly groupByProperties: string[];
/**
* Indicates whether metrics with no matches should be removed.
*/
readonly removeMetricsWithNoMatches: boolean;
}
/**
* A session metric collector builder.
*
* A builder of this type may be created using
* {@link newSessionMetricCollectorBuilder} and used to create instances of
* {@link SessionMetricCollector} that can be supplied to
* {@link Metrics.putSessionMetricCollector putSessionMetricCollector}.
*/
export interface SessionMetricCollectorBuilder {
/**
* Specifies whether the metric collector should export metrics to
* Prometheus or not.
*
* The default is that metrics are not exported to Prometheus.
*
* @param export true to export metrics to Prometheus
*
* @return this builder
*/
exportToPrometheus(exportMetrics: boolean): SessionMetricCollectorBuilder;
/**
* Set the maximum number of groups maintained by the metric collector.
*
* By default, the number of groups is not limited.
*
* @param limit a positive integer
* @see {@link MetricCollector.maximumGroups}
*/
maximumGroups(limit: number): SessionMetricCollectorBuilder;
/**
* Adds the name of a session property to group by to the list known
* to this builder.
*
* By default a builder will initially have no session properties to
* group by set.
*
* @param propertyName the name of the session property. See
* {@link Session} for details of session properties
*
* @return this builder
* @throws a {@link NullValueError} if the propertyName is `null` or `undefined`
*/
groupByProperty(propertyName: string): SessionMetricCollectorBuilder;
/**
* Specifies a list of session property names to group by, replacing
* any current list known to this builder.
*
* @param propertyNames a list of session property names. See
* {@link Session} for details of session properties
*
* @return this builder
* @throws a {@link NullValueError} if propertyNames is `null` or `undefined`
*/
groupByProperties(propertyNames: string[]): SessionMetricCollectorBuilder;
/**
* Specifies whether the metric collector should remove any metrics
* that have no matches.
*
* The default is that the metric collector will not remove metrics
* with no matches.
*
* @param remove true to indicate that metrics with no matches
* should be removed
*
* @return this builder
*/
removeMetricsWithNoMatches(remove: boolean): SessionMetricCollectorBuilder;
/**
* Reset the builder.
*
* @return this Builder
*/
reset(): SessionMetricCollectorBuilder;
/**
* Create a new {@link SessionMetricCollector} using the values
* currently known to this builder.
*
* @param name the name of the {@link SessionMetricCollector}
*
* @param sessionFilter the session filter indicating the sessions
* this collector should apply to. The format of a session
* property filter is documented in {@link Session}
*
* @return a new {@link SessionMetricCollector} with all of the
* current settings of this builder
* @throws an {@link IllegalArgumentError} if the name is empty or
* the maximum number of groups is not positive
* @throws a {@link NullValueError} if name or sessionFilter is `null` or `undefined`
*/
create(name: string, sessionFilter: string): SessionMetricCollector;
}
/**
* The definition of a topic metric collector.
*
* These can be configured to record metric data for a subset of all topics,
* specified with a topic selector.
*/
export interface TopicMetricCollector extends MetricCollector {
/**
* the topic selector
*/
readonly topicSelector: string;
/**
* Indicates whether the collector groups by topic type.
*/
readonly groupByTopicType: boolean;
/**
* Indicates whether the collector groups by topic view.
*
* @since 6.9
*/
readonly groupByTopicView: boolean;
/**
* The number of leading parts of the topic path to group by, or
* 0 if the collector does not group by path prefix
*
* @since 6.8
*/
readonly groupByPathPrefixParts: number;
}
/**
* A topic metric collector builder.
*
* A builder of this type may be created using
* {@link newTopicMetricCollectorBuilder} and
* used to create instances of {@link TopicMetricCollector} that can be supplied
* to {@link Metrics.putTopicMetricCollector putTopicMetricCollector}.
*/
export interface TopicMetricCollectorBuilder {
/**
* Specifies whether the metric collector should export metrics to
* Prometheus or not.
*
* The default is that metrics are not exported to Prometheus.
*
* @param export true to export metrics to Prometheus
*
* @return this builder
*/
exportToPrometheus(exportMetrics: boolean): TopicMetricCollectorBuilder;
/**
* Set the maximum number of groups maintained by the metric collector.
*
* By default, the number of groups is not limited.
*
* @param limit a positive integer
* @see {@link MetricCollector.maximumGroups}
*/
maximumGroups(limit: number): TopicMetricCollectorBuilder;
/**
* Specifies whether the metric collector should group by topic
* type.
*
* By default a topic metric collector does not group by topic type.
*
* @param groupByTopicType true to indicate that the collector
* should group by topic type
*
* @return this builder
*/
groupByTopicType(groupByTopicType: boolean): TopicMetricCollectorBuilder;
/**
* Specifies whether the metric collector should group by topic
* view.
*
* By default a topic metric collector does not group by topic view.
*
* @param groupByTopicView true to indicate that the collector
* should group by topic view.
*
* @return this builder.
*/
groupByTopicView(groupByTopicView: boolean): TopicMetricCollectorBuilder;
/**
* Specifies the number of leading parts of the topic path the
* metric collector should use to group results.
*
* By default a topic metric collector does not group by the topic
* path prefix. If a positive number of parts is specified, it
* will enable grouping.
*
* @param parts the number of leading parts of the topic path to
* group by; set to 0 to disable grouping by path
* @return this builder
* @since 6.8
*/
groupByPathPrefixParts(parts: number): TopicMetricCollectorBuilder;
/**
* Reset the builder.
*
* @return this Builder
*/
reset(): TopicMetricCollectorBuilder;
/**
* Create a new {@link TopicMetricCollector} using the values
* currently known to this builder.
*
* @param name the name of the {@link TopicMetricCollector}
*
* @param topicSelector the selector pattern that specifies the
* topics for which metrics are to be collected
*
* @return a new {@link TopicMetricCollector} with all of the
* current settings of this builder
* @throws an {@link IllegalArgumentError} if the name is empty or
* the maximum number of groups is not positive
* @throws a {@link NullValueError} if name or topicSelector is `null` or `undefined`
*/
create(name: string, topicSelector: string | TopicSelector): TopicMetricCollector;
}
/**
* A parameterized query that can be used to fetch metrics from the server.
*
* A new request can be created with {@link Metrics.metricsRequest}}.
* Requests are immutable. The {@link MetricsRequest.server}, {@link
* MetricsRequest.currentServer} and {@link MetricsRequest.filter} methods
* can be used to create a configured request that either limits the
* metrics to a specific server or filters the metrics returned.
*
* By default, the request will fetch metrics from all servers and will
* not filter the metrics.
*
* The metrics are the same as those exposed by the Prometheus endpoint
* when requesting metrics in the OpenMetrics format.
*
* @since 6.10
*/
export interface MetricsRequest {
/**
* Allows specifying a set of filters to limit the metrics returned.
*
* The filter may not be null. If the filter is empty then all metrics are returned.
*
* The filter is a set of strings. The filter matches a String if the String equals
* any member of the filter.
*
* Metrics are included only if:
*
* -
* The filter matches a {@link MetricSampleCollection} name, in which case the entire collection
* and its samples are returned.
*
* -
* The filter doesn't match a {@link MetricSampleCollection} name but matches at least one of its
* {@link MetricSample} children. In this case, the {@link MetricSampleCollection} is
* returned with only the matching child {@link MetricSample}s.
*
*
*
* @param filters the set of filters to use
* @return a new request derived from this fetch request but with the specified filters
* @throws a {@link NullValueError} if the filter is null
*/
filter(filters: string[] | Set): MetricsRequest;
/**
* Allows specifying a regular expression to filter the metrics returned.
*
* The filter may not be null.
*
* Similarly to calling {@link MetricsRequest.filter filter} with a set, metrics are included only if:
*
* -
* The regular expression matches a {@link MetricSampleCollection} name, in which case the
* entire collection and its samples are returned.
*
* -
* The regular expression doesn't match a {@link MetricSampleCollection} name but matches at
* least one of its {@link MetricSample} children. In this case, the {@link MetricSampleCollection} is
* returned with only the matching child {@link MetricSample}s.
*
*
*
* Only the last filter set by this method will be applied.
*
* @param filter a regular expression to use to filter the metrics. When using a string to
* specify a regular expression, the string should not contain the surrounding slashes
* nor any flags.
* @return a new request derived from this fetch request but with the specified filter
* @throws a {@link NullValueError} if the filter is null
*/
filter(filter: string | RegExp): MetricsRequest;
/**
* Specifies the name of the server to fetch metrics from. This is the configured server name.
*
* @param server the name of the server to fetch metrics from
* @return a new request derived from this fetch request but with the specified server
* @throws an {@link IllegalArgumentError} if the server name is empty
* @throws a {@link NullValueError} if the filter is null
*/
server(server: string): MetricsRequest;
/**
* Specifies that metrics should be fetched from the server to which the current
* session is connected.
*
* @return a new request derived from this fetch request but which will collect
* metrics from the current server
*/
currentServer(): MetricsRequest;
/**
* Fetches the metrics from the server.
*
* If the fetch operation completes successfully, the Promise result
* will contain a {@link MetricsResult} that can be used to access the metrics.
*
* Otherwise, the Promise will reject with an error. Common reasons for failure
* include:
*
*
* - the calling session does not have
* {@link GlobalPermission.VIEW_SERVER} permission;
*
- the operation failed due to a transient cluster error;
*
- the session is closed.
*
*
* If all metrics for a server are filtered out then the result will still contain
* an empty entry for that server.
*
* If either {@link MetricsRequest.server} or {@link MetricsRequest.currentServer}
* has been called then the result will contain an entry for that server only.
* Otherwise, it will contain an entry for each server in the cluster.
*
* @return a Promise that will complete with the metrics
*/
fetch(): Promise;
}
/**
* The result of a fetch metrics operation, initiated by a {@link MetricsRequest}.
*
* @since 6.10
*/
export interface MetricsResult {
/**
* Returns a list of server names for which the result has metrics.
* The names may be used with {@link MetricsResult.getMetrics}.
*
* @return a set of server names
*/
getServerNames(): Set;
/**
* Returns the metrics for a server.
*
* @param serverName the name of the server
* @return the metrics for the server
*/
getMetrics(serverName: string): MetricSampleCollection[];
}
/**
* Represents a collection of metric samples.
* @since 6.10
*/
export interface MetricSampleCollection {
/**
* the name of the metric sample collection
*/
readonly name: string;
/**
* the MetricType for the samples in the collection
*/
readonly type: MetricType;
/**
* the unit of measurement for the metric samples
*/
readonly unit: string;
/**
* the list of metric samples
*/
samples: MetricSample[];
}
/**
* Enumeration defining the metric types available. These match the types defined in the
*
* OpenMetrics specification.
*
*
* @since 6.10
*/
export declare enum MetricType {
/**
* Counters measure discrete events. Common examples are the number of HTTP requests received, CPU seconds
* spent, or bytes sent. Counters are always monotonic, and are typically used to count events.
*/
COUNTER = 0,
/**
* Gauges are current measurements, such as bytes of memory currently used or the number of items in a queue.
*/
GAUGE = 1,
/**
* Info metrics are used to expose textual information which SHOULD NOT change during process lifetime.
* Common examples are an application's version, revision control commit, and the version of a compiler.
*/
INFO = 2,
/**
* Histograms measure distributions of discrete events. Common examples are the latency of HTTP requests,
* function runtimes, or I/O request sizes.
*/
HISTOGRAM = 3,
/**
* GaugeHistograms measure current distributions. Common examples are how long items have been waiting in a
* queue, or size of the requests in a queue.
*/
GAUGE_HISTOGRAM = 4,
/**
* StateSets represent a series of related boolean values, also called a bitset.
*/
STATE_SET = 5,
/**
* Like Histograms, Summaries measure distributions of discrete events and MAY be used when
* Histograms are too expensive and/or an average event size is sufficient.
*/
SUMMARY = 6,
/**
* An unknown metric type.
*/
UNKNOWN = 7
}
/**
* Represents a single metric sample.
* @since 6.10
*/
export interface MetricSample {
/**
* the name of the metric sample
*/
readonly name: string;
/**
* the list of label names
*/
readonly labelNames: string[];
/**
* the list of label values for the metric sample. The nth label value corresponds to the nth label
* name.
*/
readonly labelValues: string[];
/**
* optional timestamp for the metric sample if present
*/
readonly timestamp?: Long;
/**
* the value of the metric sample
*/
readonly value: number;
}
/**
* Description of a metric alert.
*
* @since 6.12
*/
export interface MetricAlert {
/**
* The name of the metric alert.
*/
name: string;
/**
* The specification
* of the metric alert.
*/
specification: string;
/**
* The principal associated with the metric alert.
*/
principal: string;
}
/**
* This feature provides a client session with the ability to test its
* connection to the server.
*
* The main purpose of a ping is to test, at a very basic level, the current
* network conditions that exist between the client session and the server
* it is connected to. The ping response includes the time taken to make a
* round-trip call to the server.
*
* There are no permission requirements associated with this feature.
*/
export interface Ping {
/**
* Send a ping request to the server.
*
* **Example:**
* ```
* session.pingServer().then(function(pingDetails) {
* console.log("Round-trip call to server took: " + pingDetails.rtt + " milliseconds");
* });
* ```
*
* @return a result that completes when a response is received from the server.
*/
pingServer(): Promise;
}
/**
* Details of a successful ping response
*/
export interface PingDetails {
/**
* The timestamp when the ping was sent, represented as milliseconds since
* epoch
*/
readonly timestamp: number;
/**
* The round-trip time in milliseconds from when the ping was sent to the
* time the response was received
*/
readonly rtt: number;
}
/**
* @module Session.remoteServers
*/
/**
* Connection options for use with {@link SecondaryServer}s.
*/
export declare enum ConnectionOption {
/**
* Specifies the connection timeout session attribute value (in milliseconds).
*
* If a value is not specified the session's default connection timeout is used.
*/
CONNECTION_TIMEOUT = 1,
/**
* Specifies the input buffer size session attribute.
*
* This is the size of the input buffer to use for the connection with the remote server.
* It is used to receive messages from the remote server.
* This should be set to the same size as the output buffer used at the remote server.
*
* If not specified, a default of 1024k is used.
*/
INPUT_BUFFER_SIZE = 2,
/**
* Specifies the maximum queue size session attribute.
*
* This is the maximum number of messages that can be queued to send to the remote server.
* If this number is exceeded, the connection will be closed.
* This must be sufficient to cater for messages that may be queued whilst disconnected (awaiting reconnect).
*
* The default value is 10,000 messages.
*/
MAXIMUM_QUEUE_SIZE = 3,
/**
* Specifies the output buffer size session attribute.
*
* This is the size of the output buffer to use for the connection with the remote server.
* It is used to send messages to the remote server.
* This should be set to the same size as the input buffer used by the remote server.
*
* If not specified, a default of 1024k is used.
*/
OUTPUT_BUFFER_SIZE = 4,
/**
* Specifies the reconnection timeout session attribute.
*
* This is the total time in milliseconds that will be allowed to reconnect a failed connection.
*
* For reconnection to work the remote server connector must have been configured to support reconnection.
*
* If a value is not specified the session's default reconnection timeout is used.
*
* This value cannot be supplied for a
* {@link RemoteServerType.SECONDARY_ACCEPTOR SECONDARY_ACCEPTOR} server.
*/
RECONNECTION_TIMEOUT = 5,
/**
* Specifies the recovery buffer size session attribute.
*
* If the remote server is configured to support reconnection, a session established with a non-zero
* reconnect-timeout retains a buffer of sent messages.
* If the session disconnects and reconnects, this buffer is used to re-send messages that the server
* has not received.
*
* The default value is 10,000 messages. If reconnect-timeout is 0 then this value is ignored.
*
* This value cannot be supplied for a
* {@link RemoteServerType.SECONDARY_ACCEPTOR SECONDARY_ACCEPTOR} server.
*/
RECOVERY_BUFFER_SIZE = 6,
/**
* Specifies the delay after losing a connection before attempting a reconnection.
*
* The value is specified in milliseconds. Default 1000 (1 second).
*
* This value cannot be supplied for a
* {@link RemoteServerType.SECONDARY_ACCEPTOR SECONDARY_ACCEPTOR} server.
*/
RETRY_DELAY = 7,
/**
* Specifies the write timeout session attribute value (in milliseconds).
*
* If a value is not specified the session's default write timeout is used.
*/
WRITE_TIMEOUT = 8
}
/**
* Represents the current connection state of a remote server.
*/
export declare enum ConnectionState {
/**
* The connection is inactive.
*
* This means that the remote server can successfully connect but a
* physical connection is not being maintained as there are no
* components that require the remote server.
*
* If in an inactive or failed state, a test connection will have
* been tried to check that the connection can be made and the
* connection will then have been closed.
*/
INACTIVE = 1,
/**
* The remote server is connected and actively in use by components
* that require it.
*/
CONNECTED = 2,
/**
* The connection has failed but a retry is scheduled.
*
* In this case {@link RemoteServerStatus.failureMessage}
* will provide details of the failure that resulted in a retry.
*/
RETRYING = 3,
/**
* The connection failed to establish.
*
* If the connection was in an inactive or failed state, a
* test connection was tried and failed.
*
* In this case {@link RemoteServerStatus.failureMessage}
* will provide more detail.
*/
FAILED = 4,
/**
* The named remote server did not exist.
*/
MISSING = 5
}
/**
* A complete map of {@link ConnectionOption ConnectionOption}s to values.
*/
export declare type ConnectionOptions = {
[key in ConnectionOption]: string;
};
/**
* The remote server type.
*/
export declare enum RemoteServerType {
/**
* Secondary initiator remote server.
*
* Defined on secondary servers.
*
* This type will initiate connection from a secondary server
* (cluster) to a primary server (cluster member).
*/
SECONDARY_INITIATOR = 1,
/**
* Primary initiator.
*
* Defined on primary servers.
*
* This type will connect to an inbound remote server of the same
* name configured at the secondary server (cluster).
*/
PRIMARY_INITIATOR = 2,
/**
* Secondary acceptor remote server.
*
* Defined on secondary servers.
*
* This type will accept a primary remote server connection and
* support remote topic views.
*/
SECONDARY_ACCEPTOR = 3
}
/**
* Base interface for a remote server definition.
*
* @since 6.5
*/
export interface RemoteServer {
/**
* The remote server type.
*
* A {@link RemoteServer} can be cast to the corresponding sub-type to
* access all methods, as follows:
*
*
*
* | Type |
* Type class |
*
*
* | {@link RemoteServerType.SECONDARY_INITIATOR
* SECONDARY_INITIATOR} |
* {@link SecondaryInitiator} |
*
*
* | {@link RemoteServerType.PRIMARY_INITIATOR
* PRIMARY_INITIATOR} |
* {@link PrimaryInitiator} |
*
*
* | {@link RemoteServerType.SECONDARY_ACCEPTOR
* SECONDARY_ACCEPTOR} |
* {@link SecondaryAcceptor} |
*
*
*/
readonly type: RemoteServerType;
/**
* The name of the remote server.
*/
readonly name: string;
/**
* The url used for connection to the remote server.
*
* @deprecated since 6.9
*
* For backwards compatibility this property is retained for
* secondary initiator compatibility but will be removed at
* a future release.
*/
readonly url: string;
/**
* The principal used for connection to the remote server.
*
* @deprecated since 6.9
*
* For backwards compatibility this property is retained for
* secondary initiator compatibility but will be removed at
* a future release.
*/
readonly principal: string;
/**
* Options used for connection to the remote server.
*
* @deprecated since 6.9
*
* For backwards compatibility this property is retained for
* secondary initiator compatibility but will be removed at
* a future release.
*/
readonly connectionOptions: ConnectionOptions;
/**
* The missing topic notification filter expression or `undefined` if one
* has not been specified.
*
* @deprecated since 6.9
*
* For backwards compatibility this property is retained for
* secondary initiator compatibility but will be removed at
* a future release.
*/
readonly missingTopicNotificationFilter?: string;
}
/**
* The base class for remote server definitions.
*/
export interface RemoteServerDefinitionBase {
/**
* The name of the remote server.
*/
readonly name: string;
}
/**
* A primary initiator definition.
*
* This type makes a connection from a primary server (cluster) to a
* secondary server (or all secondary cluster members) with a
* {@link SecondaryAcceptor} of the same name.
*
* Use a {@link PrimaryInitiatorBuilder} to create an instance of this type.
*/
export interface PrimaryInitiatorDefinition extends RemoteServerDefinitionBase {
/**
* The urls for connection to secondary servers.
*/
readonly urls: string[];
/**
* The connector that the primary initiator will use to
* establish a connection between the secondary server and the primary
* server.
*/
readonly connector?: string;
/**
* The interval in milliseconds between connection retries.
*
* If a primary initiator cannot connect to a secondary server, or loses
* the connection, this is the amount of time before it will try to
* connect again.
*/
readonly retryDelay: number;
}
/**
* Base interface for a secondary remote server definition.
*/
export interface SecondaryServerDefinition extends RemoteServerDefinitionBase {
/**
* The principal used for connection.
*/
readonly principal: string;
/**
* The remote server connection options.
*/
readonly connectionOptions: Partial;
/**
* The missing topic notification filter expression.
*/
readonly missingTopicNotificationFilter?: string;
}
/**
* Definition of a secondary remote server that accepts a connection from
* a primary server.
*
* This type accepts a connection from a {@link PrimaryInitiator} with the
* same name configured at the primary server (cluster).
*
* Use a {@link SecondaryAcceptorBuilder} to create an instance of this
* type.
*/
export interface SecondaryAcceptorDefinition extends SecondaryServerDefinition {
/**
* The hostname of the expected primary server, for secure WebSocket validation.
*/
readonly primaryHostName: string;
}
/**
* Definition of a secondary remote server that initiates a connection to
* a primary server.
*
* This type makes a connection from a secondary server (or each secondary
* cluster member) to a primary server. No remote server definition is
* required at the primary server.
*
* Use a {@link SecondaryInitiatorBuilder} to create an instance of this
* type.
*/
export interface SecondaryInitiatorDefinition extends SecondaryServerDefinition {
/**
* The url used for connection to the primary server.
*/
readonly url: string;
}
/**
* Definition of a remote server that should be created.
*
* @since 6.7
*/
export interface RemoteServerDefinition extends PrimaryInitiatorDefinition, SecondaryInitiatorDefinition, SecondaryAcceptorDefinition {
/**
* The credentials used for connection to the remote server.
*/
readonly credentials: Credentials;
}
/**
* The base interface for all remote server builders.
*
* A builder of this type cannot be instantiated.
*
* @param the remote server type.
*/
export interface RemoteServerBuilderBase {
/**
* Reset the builder to its default values.
*
* @return this Builder
*/
reset(): B;
}
/**
* A remote server builder.
*
* A builder of this type may be created using {@link newRemoteServerBuilder}
* and used to create instances of {@link RemoteServer} that can be supplied
* to {@link RemoteServers.createRemoteServer createRemoteServer(RemoteServer)}.
*
* @since 6.7
*
* @deprecated since 6.9
*
* This builder is retained for backwards compatibility
* only. It can only be used to create a secondary
* initiator. {@link SecondaryInitiatorBuilder}
* should be used in preference. This builder will be
* removed in a future release.
*/
export interface RemoteServerBuilder {
/**
* Specifies the name of a principal used by the remote server to
* connect to the primary server.
*
* The default, if not specified, is the anonymous principal.
*
* @param principal principal name or a zero length string to
* indicate an anonymous connection
*
* @return this builder
* @throws a {@link NullValueError} if the principal is null
*/ principal(principal: string): RemoteServerBuilder;
/**
* Specifies the credentials to use when connecting to the primary
* server.
*
* The default, if not specified, is `undefined`.
*
* @param credentials the credentials to use
*
* @return this builder
*/ credentials(credentials: Credentials): RemoteServerBuilder;
/**
* Specifies a map of {@link ConnectionOption} settings.
*
* This will replace any options currently set for the builder.
*
* Any options not supplied will take their default values.
*
* If no connection options are specified, either using this method
* or {@link RemoteServerBuilder.connectionOption connectionOption}
* then all options will take their default value.
*
* @param connectionOptions map of options
*
* @return this builder
*
* @throws a {@link NullValueError} if the connectionOptions are null
*/ connectionOptions(connectionOptions: Partial): RemoteServerBuilder;
/**
* Specifies a single connection option.
*
* This will add to the options currently specified to the builder,
* or replace a value if it has already been specified.
*
* @param connectionOption the connection option
*
* @param value the connection option value. If argument is omitted or `null`
* the option is removed
*
* @return this builder
*
* @throws a {@link NullValueError} if the connectionOption is null
*/ connectionOption(connectionOption: ConnectionOption, value?: string | null): RemoteServerBuilder;
/**
* Specifies a topic selector expression which will filter missing
* topic notifications propagated from secondary to primary server.
*
* {@link MissingTopicNotification}s are notified when a client
* subscribes using a topic selector that matches no existing
* topics. By specifying a missing topic notification filter all
* notifications that match the filter on the secondary server will
* be propagated to the primary server.
*
* A match occurs if the path prefix of the subscription selector
* matches the path prefix of the specified selector. If the
* selector is a {@link Prefix.SELECTOR_SET selector
* set} then the notification will be propagated if it matches any
* selector in the set.
*
* If no filter is specified then no missing topic notifications
* will be propagated.
*
* The special selector expression "*.*" may be used to indicate
* that all missing topic notifications should be propagated.
*
* Only the path prefix of the specified selector(s) is considered
* when matching therefore any use of regular expressions would be
* ignored.
*
* @param filter a topic selector expression specifying the filter
* to apply or null to remove any existing filter
*
* @return this builder
*
* @throws an {@link IllegalArgumentError} if the filter is not a valid topic selector
*/ missingTopicNotificationFilter(filter: string | null): RemoteServerBuilder;
/**
* Reset the builder.
*
* @return this Builder
*/ reset(): RemoteServerBuilder;
/**
* Creates a remote server object using the current values known to
* this builder.
*
* @param name the name of the remote server
*
* @param url the URL to use to connect to the primary server
*
* @return a new remote server instance
*
* @throws an {@link IllegalArgumentError} if the name or URL is empty
* @throws a {@link NullValueError} if the name or URL is null
*/
create(name: string, url: string): RemoteServerDefinition;
}
/**
* A primary initiator.
*
* This type makes a connection from a primary server (cluster) to a
* secondary server (or all secondary cluster members) with a
* {@link SecondaryAcceptor} of the same name.
*
* Use a {@link PrimaryInitiatorBuilder} to create an instance of this type.
*/
export interface PrimaryInitiator extends RemoteServer {
/**
* The urls for connection to secondary servers.
*/
readonly urls: string[];
/**
* The connector that the primary initiator will use to
* establish a connection between the secondary server and the primary
* server.
*/
readonly connector?: string;
/**
* Gets the interval in milliseconds between connection retries.
*
* If a primary initiator cannot connect to a secondary server, or loses
* the connection, this is the amount of time before it will try to
* connect again.
*/
getRetryDelay(): number;
}
/**
* Builder for a {@link PrimaryInitiator}.
*
* A builder of this type may be created using
* {@link newRemoteServerBuilder} specifying
* {@code RemoteServerType.PRIMARY_INITIATOR} as the parameter.
*/
export interface PrimaryInitiatorBuilder extends RemoteServerBuilderBase {
/**
* Specifies the delay after losing a connection before attempting a
* reconnection.
*
* The value is specified in milliseconds. Default 1000 (1 second).
*
* @throws an {@link IllegalArgumentError} if the delay is less than 0
* @throws a {@link NullValueError} if the delay is null
*/
retryDelay(delay: number): PrimaryInitiatorBuilder;
/**
* Builds a primary initiator using the current values known to this
* builder.
*
* @param name the name of a primary initiator which must
* correspond too the name of a {@link SecondaryAcceptor}
* defined on the secondary server.
*
* @param urls the list of URLs to use to initiate connections to
* the secondary servers.
*
* @param connector the name of the connector used to establish the
* connection with the secondary server.
*
* @return a new primary initiator instance.
*
* @throws an {@link IllegalArgumentError} if the name, urls, or connector is empty or the
* urls are invalid
* @throws a {@link NullValueError} if any of the arguments are null
*/
build(name: string, urls: string[], connector: string): RemoteServerDefinition;
}
/**
* Base interface for a secondary remote server.
*/
export interface SecondaryServer extends RemoteServer {
/**
* The principal used for connection.
*/
readonly principal: string;
/**
* The remote server connection options.
*/
readonly connectionOptions: ConnectionOptions;
/**
* The missing topic notification filter expression.
*/
readonly missingTopicNotificationFilter?: string;
}
/**
* Base builder interface for {@link SecondaryServer}.
*
* A builder of this type cannot be instantiated.
*
* @param the builder type.
*/
export interface SecondaryBuilder extends RemoteServerBuilderBase {
/**
* Specifies the name of a principal to use for the connection.
*
* This specifies the principal for the connection to the primary
* server and is authenticated at the primary server.
*
* The default, if not specified is the anonymous principal.
*
* @param principal principal name or a zero length string to
* indicate an anonymous connection.
*
* @return this builder.
*/
principal(principal: string): B;
/**
* Specifies the credentials to use to authenticate the connection.
*
* The default, if not specified, is `null`.
*
* This is used along with the specified principal.
*
* @param credentials the credentials to use.
*
* @return this builder.
*/
credentials(credentials: Credentials): B;
/**
* Specifies a map of {@link ConnectionOption} settings.
*
* This will replace any options currently set for the builder.
*
* Any options not supplied will take their default values.
*
* If no connection options are specified, either using this method
* or {@link SecondaryBuilder.connectionOption} then all options will take their
* default value.
*
* Not all remote server types support all options. See
* {@link ConnectionOption} for details.
*
* @param connectionOptions map of options.
*
* @return this builder.
*
* @throws an {@link IllegalArgumentError} if any of the connectionOptions are invalid
*/
connectionOptions(connectionOptions: Partial): B;
/**
* Specifies a single connection option.
*
* This will add to the options currently specified to the builder,
* or replace a value if it has already been specified.
*
* Not all remote server types support all options. See
* {@link ConnectionOption} for details.
*
* @param connectionOption the connection option
*
* @param value the connection option value or null to remove the
* option
*
* @return this builder
*
* @throws an {@link IllegalArgumentError} if the connectionOption is invalid
* @throws a {@link NullValueError} if the connectionOption is null
*/
connectionOption(connectionOption: ConnectionOption, value?: string): B;
/**
* Specifies a topic selector expression which will filter missing
* topic notifications propagated from secondary to primary server.
*
* {@link MissingTopicNotification}s are notified when a client
* subscribes using a topic selector that matches no existing
* topics. By specifying a missing topic notification filter all
* notifications that match the filter on the secondary server will
* be propagated to the primary server.
*
* A match occurs if the path prefix of the subscription selector
* matches the path prefix of the specified selector. If the
* selector is a {@link Prefix.SELECTOR_SET selector
* set} then the notification will be propagated if it matches any
* selector in the set.
*
* If no filter is specified then no missing topic notifications
* will be propagated.
*
* The special selector expression "*.*" may be used to indicate
* that all missing topic notifications should be propagated.
*
* Only the path prefix of the specified selector(s) is considered
* when matching therefore any use of regular expressions would be
* ignored.
*
* @param filter a topic selector expression specifying the filter
* to apply or null to remove any existing filter
*
* @return this builder
*
* @throws an {@link IllegalArgumentError} if the filter is not a valid topic selector
*/
missingTopicNotificationFilter(filter?: string): B;
}
/**
* Secondary remote server that initiates a connection to a primary server.
*
* This type makes a connection from a secondary server (or each secondary
* cluster member) to a primary server. No remote server definition is
* required at the primary server.
*
* Use a {@link SecondaryInitiatorBuilder} to create an instance of this
* type.
*/
export interface SecondaryInitiator extends SecondaryServer {
/**
* The url used for connection to the primary server.
*/
readonly url: string;
}
/**
* Builder for a {@link SecondaryInitiator}.
*
* A builder of this type may be created using
* {@link newRemoteServerBuilder} specifying
* {@code RemoteServerType.SECONDARY_INITIATOR} as the parameter.
*/
export interface SecondaryInitiatorBuilder extends SecondaryBuilder {
/**
* Builds a secondary initiator instance using the current values
* known to this builder.
*
* @param name the remote server name. This is the name that will be
* specified in topic views
*
* @param url the URL to use to connect to the primary server
*
* @return a new secondary initiator instance
* @throws an {@link IllegalArgumentError} if the name or URL is empty or cannot be parsed
* @throws a {@link NullValueError} if the name or URL is null
*/
build(name: string, url: string): RemoteServerDefinition;
}
/**
* Secondary remote server that accepts a connection from a primary server.
*
* This type accepts a connection from a {@link PrimaryInitiator} with the
* same name configured at the primary server (cluster).
*
* Use a {@link SecondaryAcceptorBuilder} to create an instance of this
* type.
*/
export interface SecondaryAcceptor extends SecondaryServer {
/**
* The hostname of the expected primary server, for secure WebSocket validation.
*/
readonly primaryHostName: string;
}
/**
* Builder for a {@link SecondaryAcceptor}.
*
* A builder of this type may be created using
* {@link newRemoteServerBuilder} specifying
* {@code RemoteServerType.SECONDARY_ACCEPTOR} as the parameter.
*/
export interface SecondaryAcceptorBuilder extends SecondaryBuilder {
/**
* Builds a secondary acceptor using the current values known to
* this builder.
*
* @param name the remote server name. A primary initiator of the
* same name will be able to connect to this acceptor. This
* is the name that will be specified in topic views
*
* @param primaryHostName the hostname of the the primary server. This will
* be used for secure WebSocket validation purposes
*
* @return a new secondary acceptor instance
*
* @throws an {@link IllegalArgumentError} if the name is empty
* @throws a {@link NullValueError} if any of the arguments are null
*/
build(name: string, primaryHostName: string): RemoteServerDefinition;
}
/**
* Promise returned from a {@link RemoteServers.checkRemoteServer} invocation.
*/
export interface RemoteServerStatus {
/**
* The connection state of the remote server.
*/
readonly connectionState: ConnectionState;
/**
* The failure message, if there is one, otherwise an empty string
*/
readonly failureMessage: string;
}
/**
* This feature allows a client session to manage remote servers.
*
* This feature provides the ability to configure the various modes of operation
* for the use of remote topic views. This is the ability for a topic view
* specification to indicate that the source topics for the view are to come
* from another server in a different Diffusion cluster. The server where the
* topic views are configured is referred to as the 'secondary server' and the
* server where the actual topics are is referred to as the 'primary server'.
*
* Outbound Connection from the Secondary Server
*
* The typical configuration for a remote server is that there is only
* configuration at the secondary server (the configuration is automatically
* distributed to all members of the secondary cluster). In this case, each
* secondary server connects to a server in the primary cluster (typically via a
* load-balancer).
*
* Remote topic views can specify the use of such remote servers by name. The
* connection and disconnection is handled automatically by the server (or
* servers in the same cluster) where the remote servers are defined.
*
* A component can specify a remote server by name even if it does not exist
* (has not yet been created) and when the remote server is created the
* connection will take place automatically.
*
* If a remote server is removed and there are topic views that depend upon it,
* those topic views will be disabled.
*
* This form of connection is provided by a {@link RemoteServer} of type
* {@link RemoteServerType.SECONDARY_INITIATOR SECONDARY_INITIATOR} and
* represented by the sub-type {@link SecondaryInitiator}.
*
* Such a remote server can be built using a
* {@link SecondaryInitiatorBuilder} created using
* {@link newRemoteServerBuilder}. It may then be added to the
* server (cluster) using {@link createRemoteServer}.
*
* In this mode a connection from secondary to primary server is only maintained
* when there is a topic view that depends upon it. There will be no connections
* if there are no topic views that specify the remote server.
*
* Outbound Connection from the Primary Server
*
* In some cases it may be preferred that the connection is initiated by the
* primary server, connecting to the secondary server cluster. In this case a
* single primary server will connect to all members of the secondary cluster.
*
* This form of connection is provided by a {@link RemoteServer} of type
* {@link RemoteServerType.PRIMARY_INITIATOR PRIMARY_INITIATOR} and represented
* by the sub-type {@link PrimaryInitiator}. This
* can be built using a
* {@link PrimaryInitiatorBuilder} created using
* {@link newRemoteServerBuilder}. It may then be added to the
* primary server (cluster) using {@link createRemoteServer}. Secondly a
* {@link RemoteServer} of type {@link RemoteServerType.SECONDARY_ACCEPTOR
* SECONDARY_ACCEPTOR} and represented by the sub-type
* {@link SecondaryAcceptor} should be created
* in the secondary server (cluster) with the same name as the primary
* initiator. Such a remote server can be built using a
* {@link SecondaryAcceptorBuilder} created using
* {@link newRemoteServerBuilder}. It may then be added to the
* secondary server (cluster) using {@link createRemoteServer}.
*
* Unlike the secondary initiator mode, this mode of connection will establish
* connections even if there are no topic views in the secondary server
* (cluster) that name the remote server. If the connection is lost any topic
* views that depend upon it will be disabled and the primary initiator will
* attempt to re-establish the connection(s). Topic views depending upon the
* remote server will only be enabled when the connection is re-established.
*
* Remote Server persistence and replication
*
* Remote server configurations created through this feature are replicated
* across a cluster and persisted to disk.
*
* Access control
*
* The following access control restrictions are applied:
*
*
* - To {@link RemoteServers.createRemoteServer create},
* {@link RemoteServers.removeRemoteServer remove}
* or {@link RemoteServers.checkRemoteServer check} a remote server, a session needs the
* {@link GlobalPermission.CONTROL_SERVER CONTROL_SERVER} global permission. To
* {@link RemoteServers.listRemoteServers list} remote servers, a session needs the
* {@link GlobalPermission.VIEW_SERVER VIEW_SERVER} global permission.
*
*
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
*
* RemoteServers remoteServers = session.feature(RemoteServers.class);
*
*
* @since 6.5
*/
export interface RemoteServers {
/**
* Create a new remote server instance at the server.
*
* If a remote server with the same name already exists an error will be
* returned.
*
* @param remoteServer a remote server definition created using the
* appropriate sub-type of {@link RemoteServerBuilder}.
*
* @return a Promise that completes when a response is received from the
* server, returning the definition of the remote server created by
* the operation.
*
* If the task fails, the Promise will resolve with an error. Common
* reasons for failure include:
*
* - a remote server with the given name already exists;
*
- one or more connection options are invalid;
*
- the operation failed due to a transient cluster error;
*
- the calling session does not have CONTROL_SERVER permission;
*
- the session is closed;
*
- the feature is not licensed.
*
- {@link NullValueError} – if any of the required arguments are
* `null` or `undefined`
*
*/
createRemoteServer(remoteServer: RemoteServerDefinition): Promise;
/**
* Check the current state of a named remote server.
*
* This will report back the current state of the remote server, but also can be used to forcibly retry a failed
* remote server connection.
*
* Currently this only reports the state of the remote server at the server
* the session is connected to. In a cluster the state of the remote
* server on other cluster members is not reported.
*
* @param name the name of the remote server
*
* @return a Promise that completes when a response is received from the server, returning details of the remote
* server state.
*
* If the task fails, the Promise will resolve with an error. Common reasons for failure include:
*
* - the calling session does not have CONTROL_SERVER permission;
*
- the session is closed.
*
*/
checkRemoteServer(name: string): Promise;
/**
* List all the remote servers that have been created.
*
* @return a Promise that resolves when a response is received from the
* server, returning a list of remote servers.
*
* If the task fails, the Promise will resolve with an Error. Common
* reasons for failure include:
*
* - the calling session does not have CONTROL_SERVER permission;
*
- the session is closed.
*
*/
listRemoteServers(): Promise;
/**
* Remove a named remote server if it exists.
*
* When a named remote server is removed, any topic views that specify it
* would be disabled.
*
* If the named remote server does not exist the completable future will
* complete successfully.
*
*
* @param name the name of the remote server
* @return a Promise that resolves when a response is received from the
* server.
*
* If the task fails, the Promise will resolve with an Error. Common
* reasons for failure include:
*
* - the cluster was repartitioning;
*
- the calling session does not have CONTROL_SERVER permission;
*
- the session is closed.
*
*/
removeRemoteServer(name: string): Promise;
}
/**
* @module Session.security
*
* Access to the [[Security]] feature
* @preferred
*/
/**
* Permissions that are applied globally
*/
export declare enum GlobalPermission {
/**
* Add an authentication handler
*/
AUTHENTICATE = "AUTHENTICATE",
/**
* List or listen to client sessions
*/
VIEW_SESSION = "VIEW_SESSION",
/**
* Alter a client session
*/
MODIFY_SESSION = "MODIFY_SESSION",
/**
* Required to register any server-side handler
*/
REGISTER_HANDLER = "REGISTER_HANDLER",
/**
* View the server's runtime state
*/
VIEW_SERVER = "VIEW_SERVER",
/**
* Change the server's runtime state
*/
CONTROL_SERVER = "CONTROL_SERVER",
/**
* Read the security configuration
*/
VIEW_SECURITY = "VIEW_SECURITY",
/**
* Change the security configuration
*/
MODIFY_SECURITY = "MODIFY_SECURITY",
/**
* A permission that is unsupported by the session
*/
UNKNOWN_GLOBAL_PERMISSION = "UNKNOWN_GLOBAL_PERMISSION",
/**
* List topic views
*/
READ_TOPIC_VIEWS = "READ_TOPIC_VIEWS",
/**
* Modify topic views
*/
MODIFY_TOPIC_VIEWS = "MODIFY_TOPIC_VIEWS"
}
/**
* Permissions that are applied on a path
*/
export declare enum PathPermission {
/**
* Required to receive information from a topic.
*
* If a session does not have read_path permission for a topic, the topic
* will be excluded from the results of subscription or fetch operations for
* the session, and the topic's details cannot be retrieved by the session.
*/
READ_TOPIC = "READ_TOPIC",
/**
* Update topics
*/
UPDATE_TOPIC = "UPDATE_TOPIC",
/**
* Add or remove topics
*/
MODIFY_TOPIC = "MODIFY_TOPIC",
/**
* Send a message to a handler registered with the server
*/
SEND_TO_MESSAGE_HANDLER = "SEND_TO_MESSAGE_HANDLER",
/**
* Send a message another session
*/
SEND_TO_SESSION = "SEND_TO_SESSION",
/**
* Use a topic selector that selects a topic path.
*
* To fetch or subscribe using a topic selector, a session must have
* SELECT_TOPIC permission for each individual path that the selector may
* match. This allows SELECT_TOPIC to be granted to a branch of the topic
* tree and explicitly revoked for specific sub-branches.
*
* For full path pattern topic selectors, the model is even more
* restrictive: SELECT_TOPIC permission is required for all paths, at and
* below the path prefix of the selector. This is necessary to prevent
* circumvention using advanced regular expressions.
*
* When the subscription or fetch request completes, the resulting topics
* are further filtered based on the {@link PathPermission.READ_TOPIC} permission.
*
* A session that has `READ_TOPIC` but not `SELECT_TOPIC` for a
* particular topic path cannot subscribe directly to topics belonging to
* the path. However, the session can be independently subscribed by a
* control session that has {@link GlobalPermission.MODIFY_SESSION}
* permission in addition to the appropriate `SELECT_TOPIC`
* permission.
*
* @since 5.7
*/
SELECT_TOPIC = "SELECT_TOPIC",
/**
* Evaluate queries that return a non-current view of a time series topic.
*
*
* The `READ_TOPIC` permission is required to evaluate any type of
* `Query` for a time series topic. This permission is additionally
* required for queries that potentially return a non-current view of all or
* part of a time series. Such queries include value range queries that
* specify an edit range, and all types of edit range query.
*/
QUERY_OBSOLETE_TIME_SERIES_EVENTS = "QUERY_OBSOLETE_TIME_SERIES_EVENTS",
EDIT_TIME_SERIES_EVENTS = "EDIT_TIME_SERIES_EVENTS",
/**
* Submit edits to time series topic events which have an author which is
* the same as the principal of the calling session.
*
*
This permission is a more restrictive alternative to
* `EDIT_TIME_SERIES_EVENTS`.
*
*
* The `UPDATE_TOPIC` permission is required to update a time series
* topic. This permission is additionally required to submit
* edits to a time series topic where the event
* author is the same as the principal of the calling session.
*/
EDIT_OWN_TIME_SERIES_EVENTS = "EDIT_OWN_TIME_SERIES_EVENTS",
/**
* Acquire a session lock.
*/
ACQUIRE_LOCK = "ACQUIRE_LOCK",
/**
* Expose a branch of the topic tree as a virtual session tree.
*
* The `EXPOSE_BRANCH` path permission is powerful since it allows a
* session to expose a whole branch of the topic tree under a different set
* of path permissions.
*
* A session granted `EXPOSE_BRANCH` for a particular path effectively
* has the permission for all descendant paths. From a security perspective,
* if a role grants `EXPOSE_BRANCH` at branch `X` it is
* ineffectual for it also to deny `EXPOSE_BRANCH` at a child branch
* `X/Y` because a branch mapping to `X` can still expose paths
* below `X/Y`.
*/
EXPOSE_BRANCH = "EXPOSE_BRANCH",
/**
* A permission that is unsupported by the session
*/
UNKNOWN_PATH_PERMISSION = "UNKNOWN_PATH_PERMISSION"
}
/**
* The credentials that a session uses to authenticate itself.
*/
export declare type Credentials = string | Uint8Array | null | undefined;
/**
* Details for the permissions contained by a single role.
*/
export interface Role {
/**
* The name of the role
*/
readonly name: string;
/**
* The list of global permissions
*/
readonly global: GlobalPermission[];
/**
* The list of default path permissions
*/
readonly default: PathPermission[];
/**
* The map of paths to sets of Path
* permissions
*/
readonly topic: {
[key: string]: PathPermission[];
};
/**
* Additional roles
*/
readonly roles: string[];
/**
* If the role is locked this will contain the name of the principal that
* can update the role.
*
* @since 6.4
*/
readonly lockingPrincipal?: string;
}
/**
* A snapshot of information from the security store
*/
export interface SecurityConfiguration {
/**
* The list of default roles for named sessions
*/
readonly named: string[];
/**
* The list of default roles for anonymous sessions
*/
readonly anonymous: string[];
/**
* The list of all defined roles
*/
readonly roles: Role[];
/**
* The list of isolated paths
*/
readonly isolatedPaths: string[];
}
/**
* A principal in the system authentication store.
*/
export interface SystemPrincipal {
/**
* The principal name
*/
readonly name: string;
/**
* The principal's assigned roles
*/
readonly roles: string[];
/**
* If the principal is locked this will contain the name of the principal that
* can update the role.
*
* @since 6.4
*/
readonly lockingPrincipal?: string;
}
/**
* Type of a SessionPropertyValidation for a correspondent client proposed property.
*/
export declare enum ValidationType {
REGEX = 0,
VALUES = 1
}
/**
* Defines the validation for a trusted client proposed session property.
* The subtypes define specific types of validation.
*
* @since 6.5
*/
export interface SessionPropertyValidation {
/**
* Subtype of property validation
*/
readonly type: ValidationType;
}
/**
* Defines regular expression based validation for a trusted client proposed session property.
* Such validation defines a
* regular expression which supplied values must match against.
*
* @since 6.5
*/
export interface MatchesSessionPropertyValidation {
/**
* The regular expression
*/
readonly regex: string;
}
/**
* Defines values based validation for a trusted client proposed session property.
* Such validation defines a set of values to which the supplied session property value must belong.
*
* @since 6.5
*/
export interface ValuesSessionPropertyValidation {
/**
* The sef of permitted values
*/
readonly values: string[];
}
/**
* Action to be taken by the system authentication handler for connection
* attempts that do not provide a principal name and credentials.
*/
export declare type AnonymousConnectionAction = 'deny' | 'allow' | 'abstain';
/**
* Configuration for anonymous connections
*/
export interface SystemAuthenticationAnonymousConfiguration {
/**
* The action to take for anonymous connection attempts.
*
* May be one of:
*
* * `deny` - Deny anonymous connection attempts.
* * `allow` - Accept anonymous connection attempts.
* * `abstain` - Defer authentication for anonymous connection
* attempts to subsequent authentication handlers
*
*/
readonly action: AnonymousConnectionAction;
/**
* The roles the system authentication handler will assign to
* anonymous sessions. Applicable only if anonymous connections are
* {@link AnonymousConnectionAction allowed}.
*/
readonly roles: string[];
}
/**
* A snapshot of information from the system authentication store.
*/
export interface SystemAuthenticationConfiguration {
/**
* The system principals stored on the server.
*/
readonly principals: SystemPrincipal[];
/**
* The configuration that is applied for anonymous connections
*/
readonly anonymous: SystemAuthenticationAnonymousConfiguration;
/**
* The map of trusted client proposed properties,
* where the key is the permitted property name and the value
* defines the validation applied to the property.
*/
readonly trustedClientProposedProperties: {
[key: string]: SessionPropertyValidation;
};
}
/**
* A builder that can be used to create scripts for use with
* {@link Security.updateSecurityStore updateSecurityStore}.
*
* Facilitates producing scripts that control the assignment of permissions to
* roles.
* From Diffusion 6.5, script builders are no longer immutable. Each builder
* operation mutates this script builder and returns it.
*/
export interface SecurityScriptBuilder {
/**
* Create the script string.
*
* @return the script
*/
build(): string;
/**
* Sets the roles to be assigned by default to all anonymous sessions.
*
* @param (roles?: string[]): SecurityScriptBuilder;the roles to be
* assigned. An empty array (the default), or no argument,
* will result in anonymous sessions being assigned no roles
* by default.
* @return the builder to allow chaining
* @throws a {@link NullValueError} if roles is null or undefined
*/
setRolesForAnonymousSessions(roles?: string[]): SecurityScriptBuilder;
/**
* Sets the roles to be assigned by default to all sessions that authenticate with a principal.
*
* @param roles the roles to be assigned. Any empty array (the default), or
* no argument, will result in named sessions being assigned
* no roles by default.
*
* @return the builder to allow chaining
* @throws a {@link NullValueError} if roles is null or undefined
*/
setRolesForNamedSessions(roles?: string[]): SecurityScriptBuilder;
/**
* Set the global permissions assigned to a particular role.
*
* @param role the role to set global permissions for.
* @param permissions the permissions to assign globally for a role,
* default `= []`.
*
* @return the builder to allow chaining
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
setGlobalPermissions(role: string, permissions?: string[]): SecurityScriptBuilder;
/**
* Set the default permissions that a particular role will have for paths.
*
* @param role the role to set path permissions for.
* @param permissions the path permissions to assign for the role,
* default `= []`.
*
* @return the builder to allow chaining
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
setDefaultPathPermissions(role: string, permissions?: string[]): SecurityScriptBuilder;
/**
* Remove any previously assigned permissions from a particular path for a
* given role.
*
* This is different from setting no permissions to a path. By removing
* permissions set for a path, permissions will be inherited from the
* nearest set of permissions that have been assigned higher in the
* path hierarchy or from the default path permissions if no more specific
* permissions are found.
*
* @param role the role to remove path permissions from.
* @param path the path path to remove permissions from.
*
* @return the builder to allow chaining
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
removePathPermissions(role: string, path: string): SecurityScriptBuilder;
/**
* Sets specific path permissions for a named role.
*
* When permissions are assigned to a role for a path they will apply
* to the path and any paths below the specified path. Path-scoped
* permissions are assigned to roles for specific paths. The
* permission assignment applies to all descendant paths, unless there is a
* more specific assignment.
*
* To evaluate whether a session has permission for a path, the server
* starts at that path and searches up the tree to find the nearest
* permissions assignment. The first assignment is the only one considered,
* even if the session has roles involved in assignments further up the
* hierarchy.
*
* @param role the role to assign permissions for.
* @param path the path to assign permissions.
* @param permissions the permissions to assign to the role for the
* specified path. Any empty array (the default) or no
* argument would specify that the role has no
* permissions at this path, which differs from there
* being no permissions assigned for that path (see
* {@link
* SecurityScriptBuilder.removePathPermissions}).
*
* @return the builder to allow chaining
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
setPathPermissions(role: string, path: string, permissions?: string[]): SecurityScriptBuilder;
/**
* Set a path not to inherit path permissions from its parent paths or
* the default path permissions.
*
*
* By default, a path without specific
* {@link SecurityScriptBuilder.setPathPermissions} path permission
* assignments inherits the permission assignments from the first
* parent path that has them. If neither the path nor any of its parent
* paths have permission assignments, the
* {@link SecurityScriptBuilder.setDefaultPathPermissions default path permissions}
* are used.
*
* @param path the path
*
* @return this builder, modified to isolate the given path
* in the path hierarchy
* @throws a {@link NullValueError} if path is null or undefined
*
* @since 6.5
*/
isolatePath(path: string): SecurityScriptBuilder;
/**
* Re-instate inheritance of path permission assignments from parents of
* the given path.
*
* @param path the path
*
* @return this builder, modified to re-instate the
* inheritance of path permission assignments from parents of
* the given path
* @throws a {@link NullValueError} if path is null or undefined
* @see {@link SecurityScriptBuilder.isolatePath}
* @since 6.5
*/
deisolatePath(path: string): SecurityScriptBuilder;
/**
* Specify a set of a roles that another role should inherit permissions from.
*
* @param role the role
* @param roles the set of roles to inherit from.
*
* @return the builder to allow chaining
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
setRoleIncludes(role: string, roles: string[]): SecurityScriptBuilder;
/**
* Restrict a role so it can only be edited by a specific principal.
*
* @param role the role
* @param lockingPrincipal the locking principal
*
* @return this builder, modified to lock a role to a single
* principal that can edit it
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*
* @since 6.4
*/
setRoleLockedByPrincipal(role: string, lockingPrincipal: string): SecurityScriptBuilder;
}
/**
* A builder that can be used to create scripts for use with {@link
* Security.updateAuthenticationStore updateAuthenticationStore}.
*
* Facilitates producing scripts that contain the mapping of roles to specific
* principals/passwords.
* From Diffusion 6.5, script builders are no longer immutable. Each builder
* operation mutates this script builder and returns it.
*/
export interface SystemAuthenticationScriptBuilder {
/**
* Create the script string.
*
* @return the script
*/
build(): string;
/**
* Change a principal's assigned roles.
*
* @param principal the principal name.
* @param roles an array of roles
* @return this builder, modified to contain the changed roles
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
assignRoles(principal: string, roles: string[]): SystemAuthenticationScriptBuilder;
/**
* Add a principal.
*
* If `lockingPrincipal` is defined, the new principal can only be edited
* by the principal defined in the lock.
*
* The script will fail if the principal is already defined at the server.
*
* @param principal the principal name
* @param password the principal's password
* @param roles the assigned roles for the principal, default `= []`
* @param lockingPrincipal the name of the principal that can edit this
* principal
* @return this builder, modified to contain the new principal
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
addPrincipal(principal: string, password: string, roles?: string[], lockingPrincipal?: string): SystemAuthenticationScriptBuilder;
/**
* Set a principal's password.
*
* @param principal the principal name
* @param password the principal's password
* @return this builder, modified to contain the changed password
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
setPassword(principal: string, password: string): SystemAuthenticationScriptBuilder;
/**
* Assert that a principal's password is `password`.
*
* This command doesn't update the store. It can be used in conjunction with
* {@link SystemAuthenticationScriptBuilder.setPassword setPassword} to
* create a script that updates a password only if the previous password is
* supplied.
*
* @param principal the principal name
* @param password the principal's password
* @return this builder, modified to verify the password
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*/
verifyPassword(principal: string, password: string): SystemAuthenticationScriptBuilder;
/**
* Remove a principal.
*
* @param principal the principal name
* @return this builder, modified to remove the principal
* @throws a {@link NullValueError} if principal is null or undefined
*/
removePrincipal(principal: string): SystemAuthenticationScriptBuilder;
/**
* Instruct the system authentication to allow anonymous connections.
*
* @param roles the roles to assign to anonymous sessions, default `= []`
* @return this builder, modified to contain the allow anonymous connections
* command.
* @throws a {@link NullValueError} if roles is null or undefined
*/
allowAnonymousConnections(roles?: string[]): SystemAuthenticationScriptBuilder;
/**
* Instruct the system authentication to deny anonymous connections.
*
* @return this builder, modified to contain the deny anonymous connections command.
*/
denyAnonymousConnections(): SystemAuthenticationScriptBuilder;
/**
* Instruct the system authentication handler to defer authentication
* decisions for anonymous connections to subsequent handlers.
*
* @return this builder, modified to contain the abstain anonymous connections
* command.
*/
abstainAnonymousConnections(): SystemAuthenticationScriptBuilder;
/**
* Specifies the name of a client proposed session property that should be
* allowed by the system authenticator along with a set of permissible values.
* The property will only be allowed if the supplied value matches one of those
* in the set of values specified.
*
* @param propertyName specifies the name of the client proposed property to be allowed
* @param allowedValues specifies a set of allowed values for the client proposed property
*
* @return this builder, modified to allow the specified client
* proposed property if its value matches one of those supplied
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*
* @since 6.5
*/
trustClientProposedPropertyIn(propertyName: string, allowedValues: string[]): SystemAuthenticationScriptBuilder;
/**
* Specifies the name of a client proposed session property that should be
* allowed by the system authenticator along with a regular expression to
* validate the property value.
* The property will only be allowed if the supplied value matches with the regular expression.
*
* @param propertyName specifies the name of the client proposed property to be allowed
* @param regex
* regular expression which will be matched against
* supplied values to determine whether they are valid
*
* @return this builder, modified to allow the specified client
* proposed property if its value matches the given regular expression
* @throws a {@link NullValueError} if any of the arguments are null or undefined
*
* @since 6.5
*/
trustClientProposedPropertyMatches(propertyName: string, regex: string): SystemAuthenticationScriptBuilder;
/**
* Specifies the name of a client proposed session property that should
* now be ignored by the system authenticator.
*
* This removes the effect of a previous request to trust the named property.
*
* @param propertyName specifies the name of the client proposed property to be ignored
*
* @return this builder, modified to ignore the specified client proposed property
* @throws a {@link NullValueError} if propertyName is null or undefined
*
* @since 6.5
*/
ignoreClientProposedProperty(propertyName: string): SystemAuthenticationScriptBuilder;
}
/**
* Single-use callback provided to the {@link Authenticator.authenticate
* authenticate} call.
*/
export interface AuthenticatorCallback {
/**
* Authentication passed - allow the authentication request with
* modifications to the session properties.
*
* @param properties this can include all allowed user-defined session
* properties, as well as a subset of fixed session
* properties see {@link Authenticator.authenticate
* authenticate}.
* @throws an error if another method has already been
* invoked on this callback
*/
allow(properties: SessionProperties): void;
/**
* Authentication passed - allow the authentication request with fixed
* properties as supplied but no user-defined properties.
*
* @throws an error if another method has already been
* invoked on this callback
*/
allow(): void;
/**
* The authentication has neither passed nor failed.
*
* @throws an error if another method has already been
* invoked on this callback
*/
abstain(): void;
/**
* Authentication failed - deny the authentication request.
*
* @throws an error if another method has already been
* invoked on this callback
*/
deny(): void;
}
/**
* An authentication handler that processes authentication requests from the
* server.
*
* Instances can be registered with the server using the
* {@link Security.setAuthenticator AuthenticationControl} feature.
*
* The server calls an authentication handler when a client application creates
* a session, or changes the principal associated with a session, allowing the
* handler to veto individual requests.
*
* Authentication handlers are configured in precedence order. Authentication
* will succeed if a handler responds by calling {@link
* AuthenticatorCallback.allow allow()} or {@link AuthenticatorCallback.allow
* allow(map)} and handlers with higher precedence respond by calling {@link
* AuthenticatorCallback.abstain abstain()}.
*
* Authentication will fail if a handler responds by calling {@link
* AuthenticatorCallback.deny deny()} and all higher precedence handlers respond
* by calling {@link AuthenticatorCallback.abstain abstain()}.
*
* If all authentication handlers respond by calling {@link
* AuthenticatorCallback.abstain abstain()}, the request will be denied. Once
* the outcome is known, the server may choose not to call any remaining
* authentication handlers.
*
* @since 6.3
*/
export interface Authenticator {
/**
* Processes an authentication request.
*
* This method will be called to authenticate new sessions, and when a
* session requests that the session principal is changed (for example,
* using {@link Security.changePrincipal changePrincipal}).
*
* For each call to `authenticate`, the handler should respond by calling
* one of the methods of the provided {@link AuthenticatorCallback
* callback}. The handler may return immediately and process the
* authentication request asynchronously. The authentication will not
* proceed until a callback method is called.
*
* The content of the `sessionProperties` parameter depends upon
* whether the authentication handler is being called on initial
* authentication of a session or as a result of a session re-authenticating
* using {@link Security.changePrincipal changePrincipal}, as shown
* below:
*
*
*
* |
* Initial Authentication |
* changePrincipal |
*
*
* | Fixed Properties |
*
* A full set of fixed session properties as defined in {@link Session}.
*
* $Principal will be the same as the supplied
* principal.
*
* $Roles will contain the configured default roles for the
* principal.
* |
*
* A full set of fixed session properties as defined in {@link Session}.
*
* $Principal will be the principal from the previously
* authenticated session which may differ from the supplied
* principal.
*
* $Roles will contain the configured default roles for the new
* principal. |
*
*
* | User-defined Properties |
* None |
* Existing user-defined properties |
*
*
*
* On initial authentication the `proposedProperties` parameter will
* provide any user-defined properties that the client supplied when opening
* the client session, but on re-authentication it will be empty
*
* The handler can choose to call {@link AuthenticatorCallback.allow
* allow()} to accept the authentication request with default behavior or
* {@link AuthenticatorCallback.allow allow(map)} to accept the
* authentication request with modifications to the session properties.
* Alternatively it may call {@link AuthenticatorCallback.deny deny()} to
* deny the request or {@link AuthenticatorCallback.abstain abstain()} to
* abstain from authentication, in which case the request will be passed on
* to the next configured authentication handler.
*
* If the handler calls {@link AuthenticatorCallback.allow allow()} then the
* resulting session properties for the session will be as follows:
*
*
*
* |
* Initial Authentication |
* changePrincipal |
*
*
* | Fixed Properties |
* As supplied plus those assigned by the server on connection. |
* As supplied but with $Principal replaced by the supplied
* principal. |
*
*
* | User-defined Properties |
* None |
* None |
*
*
*
* If the handler calls {@link AuthenticatorCallback.allow allow(map)} then the map
* may contain values for any fixed properties that can be changed/supplied
* (see below) and/or all user-defined properties to assign to the session.
* The user-defined properties may be those proposed by the client or they
* can be any set of user-defined properties that the handler chooses.
*
* Permitted fixed property adjustments
*
* An authentication handler can set values for any of the following fixed
* properties to {@link AuthenticatorCallback.allow allow(map)}:
*
* * {@link PropertyKeys.COUNTRY $Country}
* * {@link PropertyKeys.LANGUAGE $Language}
* * {@link PropertyKeys.LATITUDE $Latitude}
* * {@link PropertyKeys.LONGITUDE $Longitude}
* * {@link PropertyKeys.PRINCIPAL $Principal}
* * {@link PropertyKeys.ROLES $Roles}
*
* An authentication handler can only set values of these fixed properties.
* Other fixed properties provided by the handler will be ignored. If the
* handler does not set a fixed property, the value will be as supplied, or
* as assigned by the server.
*
* Handling the $Roles property
*
* The $Roles property is formatted as a quoted list of
* strings. To make the handling of this property value easier there are
* methods in the global `diffusion` namespace. Using these methods an
* authenticator can adjust roles as follows:
*
* ```
* const roles = diffusion.stringToRoles(
* sessionProperties.get(diffusion.clients.PropertyKeys.ROLES));
*
* ... changes roles are required ...
*
* sessionProperties.put(diffusion.clients.PropertyKeys.ROLES,
* diffusion.rolesToString(roles));
* callback.allow(sessionProperties);
* ```
*
* @param principal the name of the proposed principal, or
* {@link ClientControlOptions.ANONYMOUS ANONYMOUS}
* if none was supplied
* @param credentials authenticating the principal; for example, a password
* @param sessionProperties supplies the currently known session properties
* for the client. On initial authentication this
* will be the known fixed property values. If the
* session is re-authenticating using {@link
* Security.changePrincipal changePrincipal}, this
* will be the full set of fixed property values
* plus any user-defined properties from the
* existing session.
* @param proposedProperties provides any user-defined properties proposed
* by the client. The handler may choose to pass
* on these properties as they are, veto some
* properties, or add more properties before
* passing them to the result. The client can
* provide arbitrary keys and values. Supplied
* properties should be checked and
* filtered/constrained to ensure they do not
* affect the integrity of the application.
* Authentication handlers should not blindly pass
* proposed properties to {@link
* AuthenticatorCallback.allow allow}.
* @param callback single use callback
*/
authenticate(principal: string, credentials: Credentials, sessionProperties: SessionProperties, proposedProperties: SessionProperties, callback: AuthenticatorCallback): void;
/**
* Notification that the authenticator was closed normally.
*
* No further calls to this authenticator will be made.
*/
onClose(): void;
/**
* Notification of an error
*
* No further calls to this authenticator will be made.
*
* @param error the error that occurred
*/
onError(error: any): void;
}
/**
* This feature allows a client session to query and update the security store
* and to authenticate the credentials of other sessions.
*
* Authentication Control
*
* Sessions are authenticated by a chain of authenticators. A client session can
* participate in the authentication process by creating an authenticator and
* registering it with the server.
*
* Each authenticator is registered under a particular authenticator name. For
* registration to succeed, the server's security configuration must include a
* matching `control-authentication-handler` entry for the name, otherwise
* registration will fail and the authenticator will be closed immediately.
*
* Each client session can register a single authenticator for a given
* authenticator name.
*
* For each authentication event, the server will use its configuration to
* determine the authenticator priority order. The server may call
* authenticators in serial or parallel. The server may stop the authentication
* process as soon as it has an allow or deny response from an authenticator and
* all higher priority authenticators have abstained.
*
* For a configured control authenticator, the server will select a single
* authenticator from those registered for the authenticator name. If no
* authenticators are currently registered, the server will consult the next
* configured authenticator in priority order.
*
* Access control
*
* In order to register an authenticator a session needs both
* {@link GlobalPermission.REGISTER_HANDLER REGISTER_HANDLER} and
* {@link GlobalPermission.AUTHENTICATE AUTHENTICATE} permissions.
*
* In order to revoke a session's authentication a session needs both
* {@link GlobalPermission.MODIFY_SESSION MODIFY_SESSION} and
* {@link GlobalPermission.AUTHENTICATE AUTHENTICATE} permissions.
*
*
Security Control
*
* The security store is a persistent database maintained by the server
* containing authorisation rules that control what sessions can do.
*
* Access rights to read and write data and to perform actions on the server are
* controlled by a fixed set of permissions. When a session is opened, the
* server assigns it a set of roles based on the principal used to authenticate.
* The rules in the security store assign each role to a set of permissions.
* Each role can be assigned zero, one, or many permissions. The same permission
* can be assigned to multiple roles. Roles can also include other roles to form
* a role hierarchy, and so inherit permissions from the other roles. Roles are
* defined implicitly by specifying them in permission assignments or inclusion
* relationships; there is no need to explicitly create roles in the security
* store.
*
* Permissions either have 'path' or 'global' scope. {@link GlobalPermission
* Global permissions} apply to actions that are server-wide and not specific to
* a particular path. {@link PathPermission Path permissions} apply to
* hierarchical context, such as a branch of the topic tree or a branch of the
* message path hierarchy.
*
* Evaluation of global permissions
*
* A session has a global permission if any of its roles are assigned the
* permission.
*
* Evaluation of path permissions
*
* A session has a permission for a path if any of its roles have the permission
* for the path.
*
* {@link SecurityScriptBuilder.setPathPermissions Path permissions} can be assigned to
* a role for a path. The permissions are inherited by all descendant paths for
* the role, except paths that have a separate permission assignment for the
* role or that are {@link SecurityScriptBuilder.isolatePath isolated} and their
* descendant paths.
*
*
* {@link SecurityScriptBuilder.setDefaultPathPermissions Default path permissions} can
* be assigned to a role to set permissions at the root of the path hierarchy. A
* default permission assignment applies to all paths without direct or
* inherited path permission assignments, except paths that are
* {@link SecurityScriptBuilder.isolatePath isolated} and their descendant
* paths.
*
* The permissions a session has for a path are determined as follows:
*
*
* - If the path has permission assignments for one or more of the sessions
* roles, the applicable permissions are the union of all of the assigned
* permissions.
*
- Otherwise, if the path is not isolated, and its parent path has
* permission assignments for one or more of the sessions roles, the applicable
* permissions are the union of all of the permissions assigned to the parent
* path. This rule is applied recursively, for each remaining parent path.
*
- Otherwise, if the neither the path nor any of its parent paths have
* permission assignments for one of the sessions role or are isolated, the
* applicable permissions are the union of the default permissions assigned to
* each role.
*
- If no applicable permissions are found, the session has no permissions
* for that path.
*
*
* Access control
*
* To query the store the session needs {@link GlobalPermission.VIEW_SECURITY
* VIEW_SECURITY} permission and to update the store it needs
* {@link GlobalPermission.MODIFY_SECURITY MODIFY_SECURITY} permission.
*
* In order to register an authentication handler a session needs both
* {@link GlobalPermission.REGISTER_HANDLER REGISTER_HANDLER} and
* {@link GlobalPermission.AUTHENTICATE AUTHENTICATE} permissions.
*
* Accessing the feature
*
* This feature can be obtained from a {@link Session session} as follows:
*
* **Example:**
* ```
* // Get a reference to the security feature
* var security = session.security;
* ```
*
*/
export interface Security {
/**
* The global permission enum
*/ readonly GlobalPermission: typeof GlobalPermission;
/**
* The path permission enum
*/ readonly PathPermission: typeof PathPermission;
/**
* Get the principal that the session is currently authenticated as.
*
* @returns the session's principal
*/
getPrincipal(): string;
/**
* Re-authenticate the session.
*
* This may be used to change the principal for the session, or to
* re-authenticate the session before it expires.
*
* A session may determine when it is due to expire by querying the value of
* the `EXPIRY_TIME` session property using
* {@link Session.getSessionProperties}. If this property is not present
* the session will not expire and there is no need to re-authenticate
* unless the principal in use is to be changed.
*
* @param principal the principal name. This may be the same principal as
* supplied when the session was originally opened, or it may be an
* entirely different principal.
*
* @param credentials the credentials authenticating the principal
*
* @param properties a map of the proposed user session properties. The
* supplied properties will be validated during authentication and
* may be discarded or changed. If no user properties are required,
* an empty object should be supplied.
*
* @return a Promise that resolves when a response is received
* from the server.
*
* If authentication succeeded, the Promise will resolve with `true`.
*
* If authentication failed because the {@code principal} was
* unknown or the {@code credentials} were invalid, the session will
* not have been re-authenticated and the Promise will resolve
* with `false`.
*
* Otherwise, the Promise will be rejected with an error.
*
* Common reasons for failure include:
*
* - the session is closed.
*
*
* @since 6.12
*/
reauthenticate(principal: string, credentials: Credentials, properties: SessionProperties): Promise;
/**
* Change the principal associated with this session.
*
* Allows a session to authenticate as a different principal. If the
* authentication fails, the current principal remains valid.
*
* @param principal the new principal to use.
* @param credentials credentials to authenticate the principal with.
* @returns a {@link Promise}
*
* **Example:**
* ```
* session.security.changePrincipal('foo', 'password');
* ```
*
* @deprecated since 6.12
* Use the new {@link Security.reauthenticate reauthenticate}
* in preference, which allows user proposed session properties
* to be supplied. This method will be removed in a future release.
*/
changePrincipal(principal: string, credentials: string): Promise;
/**
* Obtain the current contents of the server's security store.
*
* If the request is successful, the result will complete with a {@link SecurityConfiguration}.
*
* **Example:**
* ```
* session.security.getSecurityConfiguration().then(function(configuration) {
* console.log('Got security configuration', configuration);
* }, function(err) {
* console.log('Error getting security configuration', err);
* });
* ```
*
* @returns a {@link Promise} that completes with the security configuration
*
*/
getSecurityConfiguration(): Promise;
/**
* Obtain the current contents of the server's authentication store.
*
* If the request is successful, the success callback will be called with a
* {@link SystemAuthenticationConfiguration} object.
*
* **Example:**
* ```
* session.security.getSystemAuthenticationConfiguration().then(function(configuration) {
* // Display principals/roles
* configuration.principals.forEach(function(principal) {
* console.log(principal.name, principal.roles);
* });
*
* // Check the authentication action applied to anonymous connections
* console.log(configuration.anonymous.action);
*
* // Check the default roles assigned to anonymous connections
* console.log(configuration.anonymous.roles);
* }, function(err) {
* // Error retrieving configuration
* console.log(err);
* });
* ```
*
* @returns a {@link Promise} that completes with the server's authentication store
*
*/
getSystemAuthenticationConfiguration(): Promise;
/**
* Send a command script to the server to update the security store. The
* script may be produced by the builder {@link SecurityScriptBuilder}.
*
* If the script is applied without error to the server, the operation
* result will complete successfully.
*
* If any command in the script fails, none of the changes will be applied,
* and the result will be failed with an error object.
*
* If the server is configured for path replication then the changes will
* be replicated to all members of the cluster.
*
* **Example:**
* ```
* session.security.updateSecurityStore(script).then(function() {
* console.log('Security configuration updated');
* }, function(err) {
* console.log('Failed to update security configuration', err);
* });
* ```
*
* @param script the command script
* @returns a {@link Promise}
*/
updateSecurityStore(script: string): Promise;
/**
* Send a command script to the server to update the authentication store.
* The script may be produced by the builder {@link
* SystemAuthenticationScriptBuilder}.
*
* If the script is applied without error to the server, the operation
* result will complete successfully.
*
* If any command in the script fails, none of the changes will be applied,
* and the result will be failed with an error object.
*
* If the server is configured for path replication then the changes will
* be replicated to all members of the cluster.
*
* **Example:**
* ```
* session.security.updateAuthenticationStore(script).then(function() {
* console.log('Authentication configuration updated');
* }, function(err) {
* console.log('Failed to update security configuration', err);
* });
* ```
*
* @param script the command script
* @returns a {@link Promise}
*/
updateAuthenticationStore(script: string): Promise;
/**
* Returns a {@link SecurityScriptBuilder} that can be used to modify the
* server's {@link SecurityConfiguration}.
*
* @return a script builder
*/
securityScriptBuilder(): SecurityScriptBuilder;
/**
* Returns a {@link SystemAuthenticationScriptBuilder} that can be used to
* modify the server's {@link SystemAuthenticationConfiguration}.
*
* @return a script builder
*/
authenticationScriptBuilder(): SystemAuthenticationScriptBuilder;
/**
* Register an authenticator for client authentication events.
*
* @param handlerName the handler name which must match an entry in the
* server's security configuration
* @param authenticator specifies the authentication handler
* @return a {@link Promise} that completes when the authentication
* handler has been registered, returning a {@link Registration}
* which can be used to unregister the authentication handler.
*
* Otherwise, the Promise will resolve with an error. Common reasons
* for failure include:
*
* - the session is closed;
*
- the session does not have `REGISTER_HANDLER` or `AUTHENTICATE`
* permission;
*
- the server configuration does not contain a
* `control-authentication-handler` element with the given name.
*
- {@link NullValueError} – if any of the arguments are
* `null` or `undefined`
*
*
* @since 6.3
*/
setAuthenticator(handlerName: string, authenticator: Authenticator): Promise;
/**
* Returns the set of global permissions assigned to the role.
*
* @return the set of global permissions. This may be empty indicating
* that the role has no global permissions assigned.
*
* @since 6.3
*/
getGlobalPermissions(): Promise;
/**
* Returns a list of path permissions assigned to the calling session on a given
* path.
*
* @param path the path to query for permissions
* @return a {@link Promise} which completes when the response is received
* from the server.
*
* If the request was successful, the {@link Promise} will
* complete successfully with a list of {@link PathPermission}.
*
* @since 6.5
*/
getPathPermissions(path: string): Promise;
/**
* Revokes a session's authentication.
*
* This will immediately close the specified client session.
*
* @param sessionId identifies the client session to revoke
*
* @return a {@link Promise} which completes when the response is received
* from the server.
*
* @since 6.12
*/
revokeAuthentication(sessionId: SessionId): Promise;
}
/**
* @module diffusion.locks
*
* Provide access to {@link SessionLockScope}
*
* **Example:**
* ```
* // Get a reference to the security feature
* var locks = diffusion.locks;
* ```
*/
/**
* Enum containing scope parameter of {@link Session.lock}
*
* **Example:**
* ```
* // Get the ALL_FIXED_PROPERTIES key
* var scope = diffusion.locks.SessionLockScope.UNLOCK_ON_SESSION_LOSS;
* ```
*
* @since 6.2
*/
export declare enum SessionLockScope {
/**
* The lock will be released when the acquiring session is closed.
*/
UNLOCK_ON_SESSION_LOSS = 0,
/**
* The lock will be released when the acquiring session loses its
* current connection to the server.
*/
UNLOCK_ON_CONNECTION_LOSS = 1
}
/**
* @hidden
*/
export interface SessionLockOptionsNamespace {
SessionLockScope: typeof SessionLockScope;
}
export declare const SessionLockOptions: SessionLockOptionsNamespace;
/**
* @module Session.lock
*/
///
/**
* A session lock is a server-managed resource that can be used to
* coordinate exclusive access to shared resources across sessions. For
* example, to ensure a single session has the right to update a topic; to
* ensure at most one session responds to an event; or to select a single
* session to perform a housekeeping task. Session locks support general
* collaborative locking schemes. The application architect is responsible
* for designing a suitable locking scheme and for ensuring each application
* component follows the scheme appropriately.
*
* Session locks are identified by a lock name. Lock names are arbitrary and
* chosen at will to suit the application. Each lock is owned by at most one
* session. Locks are established on demand; there is no separate operation
* to create or destroy a lock.
*
* A session lock is acquired using the {@link Session.lock} method.
* If no other session owns the lock, the server will assign the lock to the
* calling session immediately. Otherwise, the server will record that the
* session is waiting to acquire the lock. A session can call `lock`
* more than once for a given session lock – if the lock is acquired,
* all calls will complete successfully with equal SessionLocks.
*
* If a session closes, the session locks it owns are automatically
* released. A session can also {@link SessionLock.unlock release a lock}.
* When a session lock is released and other sessions are waiting to acquire
* the lock, the server will arbitrarily select one of the waiting sessions
* and notify it that it has acquired the lock. All of the newly selected
* session's pending `lock` calls will complete normally. Other
* sessions will continue to wait.
*
* The {@link Session.lock} method takes an optional scope parameter that
* provides the further option of automatically releasing the lock when the
* session loses its connection to the server.
*
* Race conditions
*
* This session lock API has inherent race conditions. Even if an
* application is coded correctly to protect a shared resource using session
* locks, there may be a period where two or more sessions concurrently
* access the resource. The races arise for several reasons including
*
* * due to the check-then-act approach of polling
* {@link isOwned}, the lock can be lost after the check has succeeded but
* before the resource is accessed;
* * the server can detect a session is disconnected and assign the lock
* to another session before the original session has detected the
* disconnection.
*
* Despite this imprecision, session locks provide a useful way to
* coordinate session actions.
*
*/
export interface SessionLock {
/**
* Get the name of the lock
* @return the name of the session lock
*/
getName(): string;
/**
* A value that identifies the acquisition of the lock with the
* given {@link getName name}. SessionLocks that are acquired
* later are guaranteed to have bigger sequence values, allowing the
* sequence number to be used as a fencing token.
*
* @return a value that identifies the acquisition of this lock
*/
getSequence(): Long;
/**
* Test whether the session lock is still owned.
*
* @return `true` if the session lock is still owned by the session
*/
isOwned(): boolean;
/**
* The scope of the lock.
*
* The scope determines when the lock will be released automatically.
*
* If a session makes multiple
* {@link Session.lock requests for a lock}
* using different scopes, and the server assigns the lock to the session
* fulfilling the requests, the lock will be given the weakest scope
* (`UNLOCK_ON_CONNECTION_LOSS`). Consequently, an individual request can
* complete with a lock that has a different scope to that requested.
*
* @return the lock scope
*
* @see {@link Session.lock}
*/
getScope(): SessionLockScope;
/**
* Release a session lock, if owned.
*
* @return a Promise that resolves when a response is received
* from the server.
*
* On completion, this session will no longer own the named session
* lock. If Promise completes normally, a true value indicates this
* session previously owned the lock and a false value indicates
* it did not.
*
* If the Promise resolves with an error, this session
* does not own the session lock.
*
* @see {@link Session.lock}
*/
unlock(): Promise;
}
/**
* A session tree branch mapping.
*
* Branch mappings belong to {@link BranchMappingTable branch mapping tables}.
* Each branch mapping is a pair of a {@link Session session filter} and the
* topic tree branch that applies to sessions matching the filter.
*
* @author DiffusionData Limited
* @since 6.7
* @see SessionTrees
*/
export interface BranchMapping {
/**
* the session filter
*/
readonly sessionFilter: string;
/**
* the topic tree branch in the topic tree for sessions matching the session
* filter
*/
readonly topicTreeBranch: string;
}
/**
* A session tree branch mapping table.
*
* A branch mapping table is a list of {@link BranchMapping branch mappings}
* assigned to a session tree branch.
*
* To create a branch mapping table, obtain a new builder instance using
* {@link newBranchMappingTableBuilder}, call
* {@link BranchMappingTableBuilder.addBranchMapping} for each branch mapping,
* then {@link BranchMappingTableBuilder.create}. The result can then be sent to the
* server using {@link SessionTrees.putBranchMappingTable}.
*
* @author DiffusionData Limited
* @since 6.7
* @see SessionTrees
*/
export interface BranchMappingTable {
/**
* @return the branch of the session tree to which this table is bound
*/
getSessionTreeBranch(): string;
/**
* @return the branch mappings
*/
getBranchMappings(): BranchMapping[];
}
/**
* Builder for {@link BranchMappingTable} instances.
*
* @author DiffusionData Limited
* @since 6.7
* @see SessionTrees
* @see Diffusion.newBranchMappingTableBuilder()
*/
export interface BranchMappingTableBuilder {
/**
* Reset the builder.
*
* @return this Builder
*/
reset(): BranchMappingTableBuilder;
/**
* Add a new branch mapping.
*
* @return this Builder
*/
addBranchMapping(sessionFilter: string, topicTreeBranch: string): BranchMappingTableBuilder;
/**
* Create a new BranchMappingTable.
*
* @param sessionTreeBranch the session tree branch
*/
create(sessionTreeBranch: string): BranchMappingTable;
}
/**
* This feature allows a client session to configure session trees.
*
* A session tree is a virtual view of the topic tree presented to a session by
* fetch and subscription operations. Custom session trees for different
* sessions can be configured using declarative rules maintained by the server
* to meet data security, data optimisation, or personalisation and localisation
* requirements. Each session can be presented with a unique session tree based
* on its session properties.
*
* A session tree is produced by applying branch mappings to the topic
* tree. Branch mappings are organised into branch mapping tables. Each
* branch mapping table is assigned to a unique path – the session tree
* branch.
*
* A session tree is composed of session paths. Each session path is
* mapped via the branch mapping tables to a unique topic path.
*
* A branch mapping table is an ordered list of (session filter, topic tree
* branch) pairs. For example, the branch mapping table for the session tree
* branch `market/prices` might be:
*
*
* Session filter Topic tree branch
* ========= =============
* USER_TIER is '1' or $Country is 'DE' backend/discounted_prices
* USER_TIER is '2' backend/standard_prices
* $Principal is '' backend/delayed_prices
*
*
* With this configuration, if an unauthenticated session (one that matches the
* `$Principal is ''` session filter) subscribes to the session path
* `market/prices/X`, and there is a topic bound to the topic path
* `backend/delayed_prices/X`, the subscription will complete. The session
* will receive a subscription notification under the session path
* `market/prices/X`, together with the topic properties and the value of
* the topic. The session is unaware that the data originates from a topic bound
* to a different topic path. If no topic is bound to
* `backend/delayed_prices/X`, the subscription will not resolve and the
* session will receive no data, even if there is a topic bound to
* `market/prices/X`.
*
* Session trees complement the data transformation capabilities of
* {@link TopicViews topic views}. In our example, the time delayed time feed at
* `backend/delayed_prices` could be maintained by a topic view using the
* delay by clause.
*
* Branch mappings are persisted by the server and shared across a cluster, in a
* similar manner to topic views, security stores, and metric collectors. Branch
* mappings are editable using this feature, and via the management console.
*
* For a given session and session path, at most one branch mapping applies. The
* applicable branch mapping is chosen as follows:
*
* - Each branch mapping table with session tree branch that is a prefix of the
* session path is considered. For a given table, the first branch mapping with
* a condition that matches the session's properties is the one that applies. A
* branch mapping table may have no applicable branch mappings for a session.
*
- If there are several such branch mapping tables with a branch mapping
* that for the session, the one with the longest prefix of the session path
* applies.
*
- If no branch mapping table has a branch mapping for the session, the
* session path is translated to the identical topic path.
*
*
* Access control
*
* To subscribe to or fetch from a session path, a session must be granted the
* appropriate path permission to the session path for the operation
* ({@link PathPermission.SELECT_TOPIC SELECT_TOPIC}, or
* {@link PathPermission.READ_TOPIC READ_TOPIC}). The session doesn't require
* any permissions to the topic path of the topic providing the data.
*
* To create or replace branch mappings, a session needs the
* {@link PathPermission.MODIFY_TOPIC MODIFY_TOPIC} path permission for the
* session tree branch of the branch mapping table,
* {@link PathPermission.EXPOSE_BRANCH EXPOSE_BRANCH} path permission for the
* topic tree branch of each branch mapping, and (if an existing table with the same
* session tree branch is being replaced) {@link PathPermission.EXPOSE_BRANCH
* EXPOSE_BRANCH} permission for each branch mapping of existing table.
*
* To retrieve a branch mapping table, a session needs the
* {@link PathPermission.READ_TOPIC READ_TOPIC} path permission for its session tree
* branch.
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
*
* const sessionTrees = session.sessionTrees;
*
*
* @author DiffusionData Limited
*
* @since 6.7
*/
export interface SessionTrees {
/**
* Create or replace a branch mapping table.
*
* The server ensures that a session tree branch has at most one branch mapping
* table. Putting a new branch mapping table will replace any previous
* branch mapping table with the same session tree branch. To remove all branch
* mappings for a session tree branch, put an empty branch mapping table.
*
* @param branchMappingTable the new table
*
* @return a Promise that resolves when a response is received
* from the server.
*
* If the task completes successfully, the CompletableFuture result
* will be null. The result type is `any` rather than `void` to provide
* forward compatibility with future iterations of this API that may
* provide a non-null result with a more specific result type.
*
* Otherwise, the Promise will be rejected with an error. Common
* reasons for failure include:
*
* - the branchMappingTable or one of its branch mappings is
* invalid;
*
- the calling session does not have the {@link
* PathPermission.MODIFY_TOPIC MODIFY_TOPIC} permission for the
* session tree branch of the branch mapping table, {@link
* PathPermission.EXPOSE_BRANCH EXPOSE_BRANCH} permission for each
* branch mapping of branchMappingTable, and (if there is an
* existing table for the session tree branch) {@link
* PathPermission.EXPOSE_BRANCH EXPOSE_BRANCH} permission for each
* branch mapping of existing table;
*
- the operation failed due to a transient cluster error;
*
- the session is closed.
*
- {@link NullValueError} – if branchMappingTable is `null` or `undefined`
*
*/
putBranchMappingTable(branchMappingTable: BranchMappingTable): Promise;
/**
* Retrieve the session tree branches of the server's branch mapping tables. The
* results will only include the session tree branches of branch mapping tables
* that have at last one branch mapping and for which the calling session
* has {@link PathPermission.READ_TOPIC READ_TOPIC} path permission for
* the session tree branch.
*
* Individual branch mapping tables can be retrieved using
* {@link getBranchMappingTable}.
*
* @return a Promise that resolves when a response is received
* from the server, returning a list of session tree branches in path
* order.
*
* If the task fails, the the Promise will be rejected with an error.
* Common reasons for failure include:
*
* - the session is closed.
*
*/
getSessionTreeBranchesWithMappings(): Promise;
/**
* Retrieve a branch mapping table from the server.
*
* If there is no branch mapping table at the given session tree branch, this
* method will return an empty branch mapping table.
*
* @param sessionTreeBranch the session tree branch that identifies the branch mapping
* table
*
* @return a Promise that resolves when a response is received
* from the server, returning the branch mapping table for
* sessionTreeBranch.
*
* If the task fails, the Promise will be rejected with an error. Common
* reasons for failure include:
*
* - the calling session does not have the {@link
* PathPermission.READ_TOPIC READ_TOPIC} permission for
* sessionTreeBranch;
*
- the session is closed.
*
- {@link NullValueError} – if sessionTreeBranch `null` or `undefined`
*
*/
getBranchMappingTable(sessionTreeBranch: string): Promise;
}
/**
* @module diffusion.timeseries
*/
/**
* Time series event metadata.
*/
export interface EventMetadata {
/**
* Sequence number identifying this event within its time series.
* Assigned by the server when the event is created.
*
* Sequence numbers are unique within a time series. Each event appended
* to a time series is assigned a sequence number that is is equal to
* the sequence number of the preceding event plus one.
*/
readonly sequence: number;
/**
* Event timestamp. Assigned by the server when the event is created.
*
* Events do not have unique timestamps. Events with different sequence
* numbers may have the same timestamp.
*
* Subsequent events in a time series usually have timestamps that are
* greater or equal to the timestamps of earlier events, but this is not
* guaranteed due to changes to the time source used by the server.
*
* Timestamps represent the difference, measured in milliseconds, between
* the time the server added the event to the time series and midnight,
* January 1, 1970 UTC
*/
readonly timestamp: number;
/**
* Server-authenticated identity of the session that created the event.
*
* If the session that created the event was not authenticated, the author
* will be an empty string.
*/
readonly author: string;
/**
* Check if the EventMetadata is equal to another object
*
* @return `true` if the two objects are equal
*/
equals(other: any): boolean;
}
/**
* An event in a time series.
*
* Two instances are {@link Event.equals equal} if and only if they have identical
* attributes. Typically, two Event instances that have the same sequence number will
* be equal, but this may not be true if the event has changed on the server –
* see Changes to a time series made outside the API in the
* {@link Session.timeseries TimeSeries} documentation.
*/
export interface Event extends EventMetadata {
/**
* The value associated with the event.
*/
readonly value: V;
/**
* If this is an edit event, returns the metadata of the original event that this
* event replaces; otherwise returns this event.
*
* The result is always the metadata of an original event, never that of an edit event.
*/
readonly originalEvent: EventMetadata;
/**
* Flag indicating whether this is an edit event.
*
* `x.isEditEvent` is equivalent to `x.originalEvent != x`.
*/
readonly isEditEvent: boolean;
}
/**
* @module Session.timeseries
*/
///
/**
* Timeseries stream structure
*/
export interface StreamStructure {
/**
* The id of the stream structure
*/
readonly id: number;
/**
* The name of the stream structure
*/
readonly name: string;
/**
* Convert object to string
*
* @return a string representation of the CloseClientRequest
*/
toString(): string;
}
/**
* This feature allows a session to update and query time series topics.
*
* Time series topics
*
* A time series is a sequence of events. Each event contains a value
* and has server-assigned metadata comprised of a sequence number, timestamp,
* and author. Events in a time series are ordered by increasing sequence
* number. Sequence numbers have values between `0` and
* `Number.MAX_INTEGER` and are contiguous: an event with sequence number
* `n` will be followed by one with sequence number `n + 1` . Two
* events with the same sequence number will be equal – having the same
* timestamp, author, and value.
*
* A time series topic allows sessions to access a time series that is
* maintained by the server. A time series topic has an associated {@link
* DataType event data type}, such as `Binary` , `String` ,
* or `JSON` , that determines the type of value associated with each event.
*
* This feature provides a historic query API for time series topics, allowing a
* session to query arbitrary sub-sequences of a time series. The {@link
* Session.topics} and {@link Session.addStream} features complete the API,
* providing ways to create and subscribe to a time series topic.
*
* The API presents a time series as an append-only data structure of immutable
* events that is only changed by adding new events.
*
* Edit events
*
* Although a time series is append-only, an event can be overridden by
* appending an edit event. An edit event is a special type of event
* that overrides an earlier event in the time series (referred to as the
* original event) with a new value. When an edit event is added to a
* time series, the server retains both the original event and the edit event,
* allowing subscription and query results to reflect the edit.
*
* For example, suppose a time series has two events with the values `A`
* and `B` , and the first event has been overridden by a later edit event
* that provides a new value of `X` . The server has the following
* information about the time series.
*
* Sequence | Value | Type
* --------- | ------- | -------
* 0 | A | *original event*
* 1 | B | *original event*
* 2 | X | *edit of sequence 0*
*
* The current value of the event with sequence number 0 is `X` .
*
* If an original event has several edit events, the latest edit event (the one
* with the highest sequence number) determines its current value. Each edit
* event refers to an original event, never to another edit event.
*
* Extending the example by appending a further edit event to the time series:
*
* Sequence | Value | Type
* --------- | ------- | -------
* 3 | Y | *second edit of sequence 0*
*
* The current value of the event with sequence number 0 is now `Y` .
*
* Retained range
*
* A time series topic retains a range of the most recent events. When a new
* event is added to the time series, older events that fall outside of the
* range are discarded. By default, this range includes the ten most recent
* events. A different range can be configured by setting the
* {@link TopicSpecification.TIME_SERIES_RETAINED_RANGE
* TIME_SERIES_RETAINED_RANGE} property.
*
* Subscribing to a time series topic
*
* A session can {@link Session.select select} a time series topic and {@link
* Session.addStream add a value stream} to receive updates about events
* appended to the time series. Events are represented by {@link Event}
* instances. Each event has a value and {@link EventMetadata metadata}. An edit
* event has two sets of metadata – its own metadata and that of the
* original event that it replaces.
*
* Subscription range
*
* New subscribers are sent a range of events from the end of the time series.
* This is known as the subscription range. Configuring a subscription
* range is a convenient way to provide new subscribers with an appropriate
* subset of the latest events.
*
* The default subscription range depends on whether the topic is configured to
* publish delta streams. If delta streams are enabled, new subscribers are sent
* the latest event if one exists. If delta streams are disabled, new
* subscribers are sent no events. Delta streams are enabled by default and can
* be disabled by setting the {@link TopicSpecification.PUBLISH_VALUES_ONLY
* PUBLISH_VALUES_ONLY} property to `true`.
*
* A larger subscription range can be configured by setting the
* {@link TopicSpecification.TIME_SERIES_SUBSCRIPTION_RANGE
* TIME_SERIES_SUBSCRIPTION_RANGE} property. Regardless of the
* `TIME_SERIES_SUBSCRIPTION_RANGE` property, if delta streams are
* enabled, new subscribers will be sent at least the latest event if one
* exists.
*
* If the range of events is insufficient, the subscribing session can use a
* {@link TimeSeries.rangeQuery range query} to retrieve older events.
*
* When configuring a non-default subscription range for a time series topic,
* register value streams before subscribing to the topic. The session only
* maintains a local cache if the latest value received for a topic, not the
* full subscription range. If a value stream is added after a session has
* subscribed to a matching time series topic, the new stream will only be
* notified of the latest value.
*
* Updating a time series topic
*
* A session can use {@link TimeSeries.append append} to submit a value
* to be added to a time series. The server will add an event to the end of the
* time series based on the supplied value, with a new sequence number,
* timestamp, and the author set to the authenticated principal of the session.
*
* Providing a number as fourth argument to {@link TimeSeries.append append}
* allows a session to submit a value and supplied time. This provides control
* over the timestamp of the event. The supplied instant must not be before the
* latest event stored by the time series topic. There are no other restrictions.
*
* A session can use {@link TimeSeries.edit edit} to submit an edit to
* an original time series event, identified by its sequence number. The server
* will add an edit event to the end of the time series based on the supplied
* value, with a new sequence number, timestamp, and the author set to the
* authenticated principal of the session.
*
* Time series topics can also be updated using the functionality provided by
* the {@link TopicUpdate} feature. This includes {@link TopicUpdate.set set}
* {@link UpdateStream}s. This usage performs an append operation with the added
* benefits of {@link UpdateConstraint}s, topic creation when updating (upsert),
* and delta streams. When using methods from {@link TopicUpdate} the sequence
* number, timestamp and author metadata will be generated using the same rules
* as {@link TimeSeries.append} but the associated {@link EventMetadata} will
* not be returned to the caller.
*
* Querying a time series topic
*
* A {@link RangeQuery} is a configured query that can be evaluated for a time
* series topic using {@link RangeQuery.selectFrom selectFrom(topicPath)}.
* Results are provided as streams of {@link Event Event} instances.
*
* {@link RangeQuery} is a builder for configuring a Query that selects a range
* of a time series. There are two types of range query that differ in how edits
* are processed – value range queries and edit range queries.
*
* Value range queries
*
* A value range query returns a merged view of part of a time series. This is
* the most common time series query and appropriate for most applications.
*
* The result of a value range query reflects the latest available edits and the
* {@link QueryResult query result} is ordered by the original event sequence
* number, presenting edit events instead of the original events they replace.
* Original events that have no edit events are included verbatim. Original
* events that have edit events are replaced by the latest edit event.
*
* A value range query of the example time series, with no range constraints so
* the entire time series is selected, returns two events:
*
* ```
* sequence=3, value=Y; original event sequence=0
* sequence=1, value=B
* ```
*
* The original value of the first event is not provided. It's apparent that the
* first event is an edit event because it provides the metadata of the original
* event it replaces.
*
* Edit range queries
*
* Applications with auditing and other administrative requirements can access
* original event values using an edit range query. An edit range query returns
* an unmerged view of a time series that can include both original events and
* the edit events that replace them. Edit range queries are rarely needed
* – value range queries satisfy most use cases.
*
* Edit range queries provide a detailed view of a time series. Because this is
* potentially sensitive information, an edit range query can only be performed
* by a session that has the `QUERY_OBSOLETE_TIME_SERIES_EVENTS`
* permission for the target topic.
*
* There are two sub-types of edit range query.
*
* A full audit trail of edit events can be obtained using an all edits
* edit range query. The result contains all original events selected by the
* query, together with all subsequent edit events that affect the original
* events. The query result stream provides events in time series order. An all
* edits query of the example time series, with no range constraints so the
* entire time series is selected, returns four events:
*
* ```
* sequence=0; value=A
* sequence=1; value=B
* sequence=2; value=X; original event sequence=0
* sequence=3; value=Y; original event sequence=0
* ```
*
* A latest edits edit range query returns a query result stream in
* time series order that contains all original events selected by the query,
* together with the latest edit events that affect the original events. A
* latest edits query of the example time series, with no range constraints so
* the entire time series is selected, returns three events:
*
* ```
* sequence=0; value=A
* sequence=1; value=B
* sequence=3; value=Y; original event sequence=0
* ```
*
* The initial range of events delivered for a subscription to a time series
* topic is derived from a latest edits edit range query. See
* Subscription Range.
*
* When evaluated for a time series that has no edit events, an edit range query
* will return the same results as a similarly configured value range query.
*
* Changes to a time series made outside the API
*
* The API presents a time series as an append-only data structure of immutable
* events that is only changed by adding new events. The API does not allow
* events to be deleted or edited.
*
* There are circumstances in which events can be removed from a time series by
* server operations outside the API. For example, a time series topic can be
* configured to discard or archive older events to save storage space; or the
* time series may be held in memory and lost if the server restarts. Subscribed
* sessions are not notified when events are removed in this way, but a session
* can infer the removal of events that are no longer included in query results.
* Similarly, an event's value can be changed on the server. For example, if an
* administrator changes its value to redact sensitive data. Again, subscribed
* sessions are not notified when events are modified, but a session can infer
* this has happened from query results.
*
* Whether such changes can happen for a particular time series topic depends on
* the topic specification, and the administrative actions that are allowed. To
* write a robust application, do not rely on two Event instances with the same
* sequence number but obtained though different API calls, being equal; nor
* that there are no sequence number gaps between events in query results.
*
* Access control
*
* The session must have the {@link PathPermission.READ_TOPIC READ_TOPIC}
* permission for a topic to query a time series topic. The
* {@link PathPermission.QUERY_OBSOLETE_TIME_SERIES_EVENTS
* QUERY_OBSOLETE_TIME_SERIES_EVENTS} permission is additionally required
* to evaluate an {@link RangeQuery.forEdits edit range} query, or a
* {@link RangeQuery.forValues value range query} with an
* {@link RangeQuery.editRange edit range}.
*
* The session must have the {@link PathPermission.UPDATE_TOPIC UPDATE_TOPIC}
* path permission for a topic to {@link TimeSeries.append append} a new event
* to a time series topic. The {@link PathPermission.EDIT_TIME_SERIES_EVENTS
* EDIT_TIME_SERIES_EVENTS} permission is additionally required to {@link
* TimeSeries.edit submit an edit} to any time series event. The more
* restrictive {@link PathPermission.EDIT_OWN_TIME_SERIES_EVENTS
* EDIT_OWN_TIME_SERIES_EVENTS} permission allows a session to submit
* edits to time series topic events that are authored by the principal of the
* calling session.
*
* @since 6.0
*/
export interface TimeSeries {
/**
* Update a time series topic by appending a new value.
*
* The server will add an event to the end of the time series based on the
* supplied value, with a new sequence number, timestamp, and the author set
* to the authenticated principal of the session.
*
* @param topicPath the path of the time series topic to update
* @param value the event value
* @param valueType the type of the supplied value. This must match the value
* type of the {@link DataType} configured as the time
* series topic's {@link
* TopicSpecification.TIME_SERIES_EVENT_VALUE_TYPE event
* value type}. By default will be inferred from the
* provided value.
* @param timestamp an optional timestamp. The timestamp must be greater or
* equal to that of the most recent event appended to the
* topic
* @return a result that completes when a response is received from the
* server.
*
* If the update was successful, the Promise will complete
* successfully and provide the {@link EventMetadata} of the new
* event.
*
* Otherwise, the Promise will fail with an Error. Common reasons for
* failure include:
*
* - {@link IllegalArgumentError} – the request could not be parsed by
* the calling client;
*
- {@link NullValueError} – any of the required arguments are null
* or undefined;
*
*/
append(topicPath: string, value: any, valueType?: DataType | (new (...args: any[]) => any), timestamp?: number | Long): Promise;
/**
* Update a time series topic by appending a new value that overrides the
* value of an existing event.
*
* The existing event is identified by its sequence number and must be an
* original event.
*
* The server will add an edit event to the end of the time series based on
* the supplied value, with a new sequence number, timestamp, and the author
* set to the authenticated principal of the session.
*
* @param topicPath the path of the time series topic to update
* @param originalSequence the sequence number of the original event to edit
* @param value the event value
* @param valueType the type of the supplied value. This must match
* the value type of the {@link DataType}
* configured as the time series topic's {@link
* TopicSpecification.TIME_SERIES_EVENT_VALUE_TYPE
* event value type}. By default will be inferred
* from the provided value.
*
* @return a result that completes when a response is received from the server.
*
* If the update was successful, the CompletableFuture will complete
* successfully and provide the {@link EventMetadata} of the new
* event.
*
* Otherwise, the Promise will fail with an Error. Common reasons for
* failure include:
*
* - {@link IllegalArgumentError} – the request could not be parsed by
* the calling client;
*
- {@link NullValueError} – any of the required arguments are null
* or undefined;
*
*/
edit(topicPath: string, originalSequence: number | Long, value: any, valueType?: DataType): Promise;
/**
* Return a default range query that performs a value range query of an
* entire time series.
*
* Further queries with different parameters can be configured using the
* {@link RangeQuery} methods.
*
* The result provides {@link Bytes} values, making it
* compatible with any event data type supported by time series topics. A
* query with a more specific value type can be configured using {@link
* RangeQuery.as}.
*
* A RangeQuery equal to the one returned by this method can be created from
* an arbitrary RangeQuery as follows.
*
* ```
* defaults = anyRangeQuery.forValues()
* .fromStart()
* .untilLast(0)
* .limit(Number.MAX_INTEGER)
* .as(Uint8Array);
* ```
*
* @return a RangeQuery with default settings
*/
rangeQuery(): RangeQuery;
}
/**
* Builder for queries that select a range of events from a time series.
*
* See {@link Session.timeseries} for an overview of the various types of range
* query:
*
* * value range queries,
* * latest edits edit range queries, and
* * all edits edit range queries.
*
* {@link TimeSeries.rangeQuery rangeQuery} returns a default
* RangeQuery. Further queries with different parameters can be configured
* using the methods of this interface. {@link RangeQuery} instances are
* immutable. Each method returns a copy of this query with a modified
* setting. Method calls can be chained together in a fluent manner to create a
* query. For example:
*
* ```
* var defaultQuery = session.timeseries.rangeQuery();
*
* // A value range query that selects up to 100 original events from the
* // start of a time series.
* first100 = defaultQuery.forValues().fromStart().next(100);
* ```
*
* Creating value range queries
*
* A value range query returns a merged view of part of a time series. This is
* the most common time series query and appropriate for most applications. A
* value range query begins with the {@link RangeQuery.forValues forValues}
* operator, followed by the view range. The view range determines the
* range of original events the time series that are of interest. See Range
* expressions below for the various ways to specify `RANGE` .
*
* The events returned by the query are constrained by an optional edit
* range, introduced by the {@link RangeQuery.editRange editRange}
* operator. An event will only be included in the result if it is in the edit
* range. Let's consider some examples to see how the view range and the edit
* range interact.
*
*
*
* | Query |
* Meaning |
*
*
* rangeQuery().forValues(); |
* For each original event in the time series, either return the latest
* edit event or if it has no edit events, return the original event. |
*
*
* rangeQuery().forValues().from(100).to(150); |
* For each original event with a sequence number between 100 and 150
* (inclusive), either return the latest edit event or if it has no edit
* events, return the original event. |
*
*
*
* rangeQuery().forValues().from(100).to(150).editRange().from(400);
* |
* For each original event with a sequence number between 100 and 150
* (inclusive), return the latest edit event with a sequence number greater
* than or equal to 400.
*
* The result of this query will not include any original events because
* there is no overlap between the view range and the edit range. |
*
*
*
* Value range queries can be further refined using the {@link RangeQuery.limit
* limit()} and {@link RangeQuery.as as()} operators.
*
* Creating edit range queries
*
* An edit range query returns an unmerged view of a time series than can
* include both original events and the edit events that replace them. Edit
* range queries are rarely needed – value range queries satisfy most
* use cases.
*
* An edit range query begins with the {@link RangeQuery.forEdits forEdits}
* operator, followed by the view range. The view range determines the
* range of original events the time series that are of interest. The result
* will only contain original events that are in the view range, and edit events
* for original events in the view range. See Range expressions below
* for the various ways to specify `RANGE` .
*
* The events returned by the query are constrained by an optional edit
* range, introduced by the {@link RangeQuery.latestEdits latestEdits} or
* {@link RangeQuery.allEdits allEdits} operators. An event will only be
* included in the result if it is in the edit range. Let's consider some
* example edit range queries.
*
*
*
* | Query |
* Meaning |
*
*
* rangeQuery().forEdits(); |
* Return all events in a time series. |
*
*
* rangeQuery().forEdits().from(100).to(150); |
* Return the original events with a sequence number between 100 and 150
* (inclusive) and all edit events in the time series that refer to the
* original events. |
*
*
* rangeQuery().forEdits().from(100).to(150).latestEdits(); |
* Return the original events with a sequence number between 100 and 150
* (inclusive) and the latest edit events in the time series that refer to
* the original events. |
*
*
*
* rangeQuery().forEdits().from(100).to(150).allEdits().from(400);
* |
* For each original event with a sequence number between 100 and 150,
* (inclusive) return all edit events with a sequence number greater than or
* equal to 400.
*
* The result of this query will not include any original events because
* there is no overlap between the view range and the edit range. |
*
*
*
* Edit range queries can be further refined using the {@link RangeQuery.limit
* limit()} and {@link RangeQuery.as as()} operators.
*
* Range expressions
*
* Range expressions are used to specify the view and edit ranges in value
* range and edit range queries. Each range expression has an
* anchor that determines where to start, and a span that
* determines where the range ends. Both anchor and span are
* inclusive – if an anchor or span falls on an event, the
* event is included in the result.
*
* Both anchor and the span are optional. If the anchor is unspecified, the
* range begins at the start of the time series. If the span is unspecified,
* the range continues until the end of the time series.
*
* Anchors
*
*
* There are five ways to specify an anchor.
*
*
*
* | Anchor |
* Meaning |
*
*
* | {@link RangeQuery.from from(Number)} |
* Sets the anchor at an absolute sequence number. |
*
*
* | {@link RangeQuery.from from(Date)} |
* Sets the anchor at an absolute time. |
*
*
* | {@link RangeQuery.fromStart fromStart} |
* Sets the anchor at the start of the time series. |
*
*
* | {@link RangeQuery.fromLast fromLast(Number)} |
* Sets the anchor at a relative offset before the end of the time
* series. For value range queries, count is the number of original
* events. For edit range queries, count is the number of events of
* any type. |
*
*
* {@link RangeQuery.fromLast fromLast(Date}
* {@link RangeQuery.fromLastMillis fromLastMillis} |
* Sets the anchor at a relative time before the timestamp of the last
* event of the time series. |
*
*
*
* An anchor point can be before the start or after the end of the time
* series.
*
* Spans
*
* There are nine ways to specify a span.
*
*
*
* | Span |
* Meaning |
*
*
* | {@link RangeQuery.to to(Number)} |
* The range ends at an absolute sequence number. The sequence
* argument may be before or after the anchor. |
*
*
* | {@link RangeQuery.toStart toStart} |
* The range ends at the start of the time series. |
*
*
* | {@link RangeQuery.to to(Date)} |
* The range ends at an absolute time. The date argument may
* be before or after the anchor. |
*
*
* | {@link RangeQuery.next next(Number)} |
* The range ends at an event that is a relative number of events after
* the anchor. For value range queries, count is the number of
* original events. For edit range queries, count is the number of
* events of any type. |
*
*
* {@link RangeQuery.next next(Date)}
* {@link RangeQuery.nextMillis nextMillis} |
* The range ends at an event that is a relative time after the
* anchor. |
*
*
* | {@link RangeQuery.previous previous(Number)} |
* The range ends at an event that is a relative number of events before
* the anchor. For value range queries, count is the number of
* original events. For edit range queries, count is the number of
* events of any type. |
*
*
* {@link RangeQuery.previous previous(Date)}
* {@link RangeQuery.previousMillis previousMillis} |
* The range ends at an event that is a relative time before the
* anchor. |
*
*
* | {@link RangeQuery.untilLast untilLast(Number} |
* The range ends at an event that is a relative number of events before
* the end of the time series. For value range queries, count is the
* number of original events. For edit range queries, count is the
* number of events of any type. |
*
*
* {@link RangeQuery.untilLast untilLast(Date)}
* {@link RangeQuery.untilLastMillis untilLastMillis} |
* The range ends at an event that is a relative time before the
* timestamp of the last event of the time series. |
*
*
*
* A span can specify an end point that is before the start or after the end
* of the time series.
*
* If the span specifies an end point after the anchor, the range includes
* the first event at or following the anchor and ends at the last event at
* or preceding the end point. If the span specifies an end point before the
* anchor, the range includes the first event at or preceding the anchor and
* ends at the last event at or after the end point.
*
* Using the builder methods
*
* Although the natural order of operators in a query is as shown in the
* syntax diagrams above, RangeQuery builder methods – those that
* return another RangeQuery – can be applied in any order with the
* following exceptions:
*
* * {@link RangeQuery.editRange} only applies to value range queries, so cannot
* follow `forEdits()` without an intervening `forValues();`
* * {@link RangeQuery.latestEdits} and {@link RangeQuery.allEdits} only apply
* to edit range queries, so cannot follow `forValues()` without an
* intervening `forEdits()`.
*
* Each method overrides some configuration of the RangeQuery to which it is
* applied, as summarized in the following table.
*
*
*
* | Builder method |
* Operator type |
* Overridden configuration |
*
*
* forValues() |
* Value range |
* Overrides the existing query type to create a new value range query.
* Overrides the existing view range with a new view range that selects the
* entire time series. The existing edit range is copied unchanged. |
*
*
* forEdits() |
* Value range |
* Overrides the existing query type to create a new edit range query
* that includes all edits. Overrides the existing view range with a new
* view range that selects the entire time series. The existing edit range
* is copied unchanged. |
*
*
* editRange()
* | Edit range |
* Overrides the existing edit range with a new edit range that selects
* the entire time series. The existing view range is copied unchanged.
* Throws IllegalStateException if this is not a value range
* query. |
*
*
* latestEdits()
* allEdits() |
* Edit range |
* Overrides the existing edit range with a new edit range that selects
* the entire time series. The existing view range is copied unchanged.
*
* Throws Error if this is not an edit range query. |
*
*
* from()
* fromStart()
* fromLast() |
* Anchor |
* Overrides the anchor of the current range. |
*
*
* to()
* toStart()
* next()
* previous()
* untilLast() |
* Span |
* Overrides the span of the current range. |
*
*
* limit() |
* Limit |
* Overrides the limit. |
*
*
* as() |
* Query value type |
* Overrides the query value type. |
*
*
*
* @see Session.timeseries.rangeQuery
*/
export interface RangeQuery {
/**
* Return a copy of this RangeQuery configured to perform a value range
* query within the view range set to the entire time series.
*
* **Operator type:** value range
*
* @return a copy of this range query configured to perform a view range
* query within a new view range that selects the time time series.
*/
forValues(): RangeQuery;
/**
* Return a copy of this RangeQuery configured to perform an edit range
* query within the view range set to the entire time series.
*
* **Operator type:** value range
*
* @return a copy of this range query configured to perform an edit range
* query with a new view range that selects the entire time series
*/
forEdits(): RangeQuery;
/**
* Return a copy of this RangeQuery configured to perform a value range
* query with the edit range set to the entire time series.
*
* This operator can only be applied to value range queries. The default
* query returned by {@link TimeSeries.rangeQuery rangeQuery()} is a
* value range query. The {@link RangeQuery.forValues} operator can be used
* to create a value range query from an edit range query.
*
* **Operator type:** edit range
*
* @return a copy of this range query configured to perform a view range
* query with a new edit range that selects the entire time series
* @throws an {@link IllegalStateError} if this is not a value range query
*/
editRange(): RangeQuery;
/**
* Return a copy of this RangeQuery configured to perform an edit range
* query with the edit range that selects all edits in the entire time
* series.
*
* This operator can only be applied to edit range queries. The default
* query returned by {@link TimeSeries.rangeQuery rangeQuery()} is a
* value range query. The {@link RangeQuery.forEdits} operator can be used
* to create an edit range query form a value range query.
*
* **Operator type:** edit range
*
* @return a copy of this range query configured to perform an edit range
* query with a new edit range that selects all edits in the entire
* time series
* @throws an {@link IllegalStateError} if this is not an edit range query
*/
allEdits(): RangeQuery;
/**
* Return a copy of this RangeQuery configured to perform an edit range
* query with the edit range that selects latest edits in the entire
* time series.
*
* This operator can only be applied to edit range queries. The default
* query returned by {@link TimeSeries.rangeQuery rangeQuery()} is a
* value range query. The {@link RangeQuery.forEdits forEdits()} operator
* can be used to create an edit range query from a value range query.
*
* **Operator type:** edit range
*
* @return a copy of this range query configured to perform an edit range
* query with a new edit range that selects the latest edits in the
* entire time series
* @throws an {@link IllegalStateError} if this is not an edit range query
*/
latestEdits(): RangeQuery;
/**
* Return a copy of this RangeQuery with the anchor of the current range
* configured to be either an absolute sequence number, or a Date instance.
*
* **Operator type:** anchor
*
* @param sequence absolute sequence number or Date specifying the anchor of
* the returned range
* @return a copy of this range query with a new anchor
* @throws an {@link IllegalArgumentError} if sequence is negative
* @throws a {@link NullValueError} if sequence is null or undefined
*/
from(sequence: number | Date): RangeQuery;
/**
* Return a copy of this RangeQuery with the anchor of the current range
* configured to be the start of the time series.
*
* There is a difference between fromStart( and `from(0)`
* if the range also ends before the first event of the time series. For
* example, `fromStart().toStart()` is always empty, but
* `from(0).toStart()` includes the event with sequence number
* `0` .
*
* **Operator type:** anchor
*
* @return a copy of this range query with a new anchor
*/
fromStart(): RangeQuery;
/**
* Return a copy of this RangeQuery with the anchor of the current range
* configured to be a relative offset before the end of the time series.
*
* **Operator type:** anchor
*
* @param count specifies the anchor as a number of events before the
* end of the time series. For value range queries, count is
* the number of original events. For edit range queries,
* count is the number of events of any type.
* @return a copy of this range query with a new anchor
* @throws an {@link IllegalArgumentError} if count is negative
* @throws a {@link NullValueError} if count is null or undefined
*/
fromLast(count: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the anchor of the current range
* configured to be a relative time from the timestamp of the last event
* in the time series.
*
* **Operator type:** anchor
*
* @param timeSpan specifies anchor as a number of milliseconds relative
* to the timestamp of the latest event in the time series
* @return a copy of this range query with a new anchor
* @throws an {@link IllegalArgumentError} if timeSpan is negative
* @throws a {@link NullValueError} if timeSpan is null or undefined
*/
fromLastMillis(timeSpan: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to end at an absolute sequence number or Date instance.
*
* **Operator type:** span
*
* @param sequence absolute sequence number or Date instance specifying the
* end of the returned range
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if sequence is negative
* @throws a {@link NullValueError} if sequence is null or undefined
*/
to(sequence: number | Date): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to end at the start of the time series.
*
* There is a difference between `toStart()` and `to(0)` if
* the range also starts before the first event of the time series. For
* example, `fromStart().toStart()` is always empty, but
* `fromStart().to(0)` includes the event with sequence number
* `0` .
*
* **Operator type:** span
*
* @return a copy of this range query with a new span
*/
toStart(): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to select a range of events following the anchor.
*
* **Operator type:** span
*
* @param count specifies the end of the range of events to select
* following the anchor. For value range queries, count is the
* number of original events. For edit range queries, count is
* the number of events of any type.
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if count is negative
* @throws a {@link NullValueError} if count is null or undefined
*/
next(count: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to select a temporal range of events following the anchor.
*
* **Operator type:** span
*
* @param timeSpan the time span in milliseconds of events following the
* anchor to select
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if timeSpan is negative
* @throws a {@link NullValueError} if timeSpan is null or undefined
*/
nextMillis(timeSpan: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to select a range of events preceding the anchor.
*
* **Operator type:** span
*
* @param count specifies the end of the range of events to select
* preceding the anchor. For value range queries, count is the
* number of original events. For edit range queries, count is
* the number of events of any type.
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if count is negative
*/
previous(count: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to select a temporal range of events preceding the anchor.
*
* **Operator type:** span
*
* @param timeSpan the time span in milliseconds of events preceding the
* anchor to select
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if timeSpan is negative
*/
previousMillis(timeSpan: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to end a number of events before the end of the time
* series.
*
* **Operator type:** span
*
* @param count specifies the end of the range of events to select as a
* number of events before the end of the time series. For
* value range queries, count is the number of original
* events. For edit range queries, count is the number of
* events of any type.
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if count is negative
* @throws a {@link NullValueError} if count is null or undefined
*/
untilLast(count: number): RangeQuery;
/**
* Return a copy of this RangeQuery with the span of the current range
* configured to end at a relative time from the timestamp of the last
* event in the time series.
*
* **Operator type:** span
*
* @param timeSpan specifies the end of the range of events to select as
* a number of milliseconds relative to the timestamp of
* the latest event in the time series
* @return a copy of this range query with a new span
* @throws an {@link IllegalArgumentError} if timeSpan is negative
* @throws a {@link NullValueError} if timeSpan is null or undefined
*/
untilLastMillis(timeSpan: number): RangeQuery;
/**
* Return a copy of this RangeQuery that returns at most count events.
*
* If the query would otherwise select more than count events, only the
* latest count values (those with the highest sequence numbers) are
* returned.
*
* This is most useful when a temporal span has been configured with
* {@link RangeQuery.nextMillis} or {@link RangeQuery.previousMillis},
* where the potential number of returned events is unknown.
*
* {@link QueryResult.isComplete isComplete()} can be used to determine
* whether a query has returned an incomplete result.
*
* **Operator type:** limit
*
* @param count the maximum number of events to return
* @return a copy of this range query with a new limit
* @throws an {@link IllegalArgumentError} if count is negative
*/
limit(count: number): RangeQuery;
/**
* Return a copy of this RangeQuery with a different query value type.
*
* A query can only be evaluated successfully against time series topics
* with a compatible event data type. If a query method is called for a
* time series topic with an incompatible event data type, the query
* will complete exceptionally.
*
* If the event data type of the time series topic is known,
* compatibility of a particular `valueClass` can be checked using
* {@link DataType.canReadAs canReadAs}. The
* {@link TimeSeries.rangeQuery default range query} has a query value
* type of {@link Bytes}, which is compatible with all time series value
* data types.
*
* **Operator type:** query value type
*
* @param valueClass the value class or data type to read event values as
* @return a copy of this range query with a new query value type
* @throws an {@link IllegalArgumentError} if valueClass cannot be read as a data type
* @throws a {@link NullValueError} if valueClass is null or undefined
*/
as(valueClass: DataType | (new (...args: any[]) => any)): RangeQuery;
/**
* Evaluate this query for a time series topic.
*
* The session must have the `READ_TOPIC` path permission for `topicPath`
* to evaluate a query. The `QUERY_OBSOLETE_TIME_SERIES_EVENTS` topic
* permission is also required if this is an {@link RangeQuery.forEdits edit
* range} query, or a {@link RangeQuery.forValues value range query} with an
* {@link RangeQuery.editRange edit range}.
*
* @param topicPath the path of the time series topic to query
*
* @return a result that completes when a response is
* received from the server.
*
* If the query returned results, the result will
* complete successfully and provide an {@link QueryResult}.
*
* Otherwise, the result will complete exceptionally
* with an {@link ErrorReason}.
*/
selectFrom(topicPath: string): Promise;
}
/**
* Query result providing a {@link Stream} of events.
*/
export interface QueryResult {
/**
* The number of events selected by the query.
*
* This number may be greater than `events.length` due to a
* policy of the time series topic to limit the number of returned
* results, or the use of {@link RangeQuery.limit}.
*/
readonly selectedCount: number;
/**
* The timeseries events returned
*/
readonly events: Array>;
/**
* `true` if this result includes all events selected by the query.
*/
readonly isComplete: boolean;
/**
* A description of the structure of the result stream.
*/
readonly streamStructure: StreamStructure;
/**
* Merge this result with `other` , combining original events and
* edit events, to produce a new {@link QueryResult}.
*
* The following rules are applied to calculate the result:
*
* * If this result and `other` have an event with equal
* sequence numbers, the event from `other` is selected.
* * An edit event is selected in place of its original event.
* * If there are multiple edit events of an original edit, the one
* with the highest sequence is selected.
*
* The returned result implements {@link QueryResult.isComplete} to be true
* and {@link QueryResult.selectedCount} to contain the count of events in
* the `events` array, regardless of whether this result is complete.
*
* @param other the other query result to merge
* @return the merged result
*/
merge(other: QueryResult): QueryResult;
}
/**
* @module Session.topics
*/
/**
* This feature allows a session to manage topics. It provides the following
* capabilities:
*
* 1) Adding and removing topics.
* 2) Missing topic notifications — listening for requests to subscribe to
* topics that do not exist thus allowing dynamic topic creation on demand.
* 3) Topic event listeners — listening for topic events, such as the number of
* subscribers to a topic changing from zero to greater than zero or from
* greater than zero to zero.
*
* Topics
*
* The Diffusion server stores data in topics. Each topic is bound to a topic
* path in the topic tree, and may have a current value. Sessions can subscribe
* to topics. Updates to topic values are broadcast to subscribing sessions.
* There are several types of topic. The {@link TopicType topic type} determines
* the type of the data values a topic publishes to subscribers.
*
* Adding topics
*
* Creating topics
*
* The simplest way to create a topic is to call
* {@link TopicControl.add}, supplying a topic type. For example, to
* create a {@link TopicType.JSON JSON} topic bound to the topic path
* foo:
*
*
* const result = session.topic.add("foo", diffusion.TopicType.JSON);
*
*
* Success or failure is reported asynchronously through the CompletableFuture
* result.
*
* The nature of a topic depends primarily on its topic type, but can be
* customized using topic properties. Some types of topic cannot be created
* without supplying mandatory topic properties. Topic properties can be
* supplied in a {@link TopicSpecification topic specification} using
* {@link TopicControl.add add(topicPath: string, specification: TopicSpecification)}.
* Topic specifications can be created using
* {@link TopicSpecification new TopicSpecification(...)} and further customized
* with builder methods. For example, to create a {@link TopicType.JSON JSON}
* topic bound to the topic path foo with the
* {@link TopicSpecification.VALIDATE_VALUES VALIDATE_VALUES} property set to
* true:
*
* ```
* // Create specification for JSON topics which validate update values on the server
* const TopicSpecification = diffusion.topics.TopicSpecification;
*
* var specification = new TopicSpecification(diffusion.topics.TopicType.JSON)
* .withProperty(TopicSpecification.VALIDATE_VALUES, "true");
* ```
*
* See {@link TopicSpecification} for details of the available topic properties
* and their effects on the different types of topic.
*
* Topic creation is idempotent. If {@link TopicControl.add addTopic(path,
* specification)} is called and there is already a topic bound to `path` with a
* topic specification equal to `specification`, the call will complete normally
* with an {@link TopicAddResult} result that indicates that no topic has been
* added. However, if there is a topic bound to `path` with a different topic
* specification, the call will fail.
*
* Removing topics
*
* Topics can be removed using {@link TopicControl.remove}. Only those
* selected topics for which the caller has {@link PathPermission.MODIFY_TOPIC
* MODIFY_TOPIC} permission will be removed, any others will remain.
*
* Topics can also be automatically removed according to a removal criteria
* specified using the {@link TopicSpecification.REMOVAL REMOVAL} topic
* property.
*
* Managing topic tree hierarchies
*
* A topic can be bound to any path in the topic tree namespace. The only
* restriction is that two topics cannot have the same path.
* In the following example a topic can be created with the path A/B/foo
* even though there are no topics with path A or A/B:
*
*
* topicControl.addTopic("A/B/foo", TopicType.JSON);
*
*
* Topics bound to the paths A or A/B can be created later.
*
* Topics can be removed without affecting the topics subordinate to them in the
* topic tree using {@link TopicControl.remove} providing a path topic selector. By using
* the // topic selector qualifier it is possible to remove a topic and
* all of its descendant topics, that is to remove whole topic tree branches.
*
* Access control
*
* To add or remove a topic, a session needs {@link PathPermission.MODIFY_TOPIC
* MODIFY_TOPIC} permission for the topic path. When removing topics with a
* topic selector that matches more than one topic, only topics with paths for
* which the session has MODIFY_TOPIC permission will be removed.
*
* To register a
* {@link TopicControl.addMissingTopicHandler missing topic handler} the session
* needs {@link GlobalPermission.REGISTER_HANDLER REGISTER_HANDLER} permission.
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
* **Example:**
* ```
* // Get a reference to topic control feature
* var topics = session.topics;
* ```
*/
export interface TopicControl {
/**
* Add a topic to the server at a specific path. This returns a {@link Promise}.
*
* The path should be a string. To express hierarchies, `/` can
* be used as a delimiter. This allows topics to be nested and grouped below
* each other. For example, `session.topics.add('foo/bar');`
* creates the topic `bar` . A topic is not created at `foo`
* by this method.
*
* Each topic has a particular {@link TopicType type}, which constrains the
* kind of values that the topic will allow. This type can either be
* explicitly provided, or included as part of a {@link TopicSpecification
* TopicSpecification}.
*
* Adding from topic type
*
* To directly specify the type of topic to create, provide a string path
* and a {@link TopicType}. Topics specified in this way
* are created with default topic properties, as described in {@link TopicSpecification}.
*
* Adding from topic specification
*
* {@link TopicSpecification TopicSpecifications} allows
* the creation of topics of a particular type, along with additional
* properties that determine how the topic operates. For instance, you may
* wish to specify that a topic will validate values before publishing, or
* that it will only publish values instead of deltas.
*
* Operation results
*
* If the topic was added, or a topic already exists with the same path and
* specification, the operation will succeed. If there is a problem with
* adding the topic then the result will be rejected with an error.
*
* If any sessions have already subscribed to the same path that a topic is
* created for, they will receive a `subscription` event once the topic is
* added, and a `value` event with the initial value (if supplied).
*
* If the session is closed when calling this method, the returned result
* will be rejected.
*
* Failure
*
* If the operation fails a {@link TopicAddFailReason} is
* provided. Adding a topic may fail because the session has insufficient
* permissions; a topic already exists at the specified path; or certain
* mandatory {@link TopicSpecification TopicSpecification}
* properties were missing
*
* **Example:**
* ```
* // Create a topic with a Topic Type
* session.topics.add('foo/binary', diffusion.topics.TopicType.BINARY);
* ```
*
* **Example:**
* ```
* // Create a topic with a TopicSpecification
* const TopicSpecification = diffusion.topics.TopicSpecification;
* var specification = new TopicSpecification(diffusion.topics.TopicType.JSON, {
* TopicSpecification.VALIDATE_VALUES : "true"
* });
*
* session.topics.add('foo/json', specification);
* ```
*
* **Example:**
* ```
* // Handle the add topic result
* session.topics.add('foo/bob', diffusion.topics.TopicType.JSON).then(function(result) {
* if (result.added) {
* console.log('Topic added');
* } else {
* console.log('A compatible topic already exists');
* }
* }, function(error) {
* console.log('Topic add failed: ', error);
* });
* ```
*
* @param topicPath the topic path to create.
* @param specification the topic type/specification
* @returns a {@link Promise} for this operation
*/
add(topicPath: string, specification: TopicType | TopicSpecification): Promise;
/**
* Remove one or more topics at the server.
*
* The topics to remove will depend upon the nature of the topic selector
* specified. If the selector does not have {@link TopicSelector descendant
* pattern qualifiers} (i.e. / or //), only those topics that exist at paths
* indicated by the selector will be removed and not their descendants. If a
* single / qualifier is specified, all descendants of the matching topic
* paths will be removed. If // is specified, all branches of the topic tree
* that match the selector (i.e topics at the selected paths and all
* descendants of the selected paths) will be removed.
*
* This function can take any number of arguments. Each argument can be a string
* or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument. At least one
* valid selector has to be specified.
*
* **Example:**
* ```
* // Remove the topic at 'foo/bar', leaving descendants
* session.topics.remove('>foo/bar');
* ```
*
* **Example:**
* ```
* // Remove the topic at 'foo/bar' and all descendants
* session.topics.remove('?foo/bar//');
* ```
*
* @param selector the selector specifying the topics to remove
* @returns a {@link Promise} resolving to a {@link
* TopicRemovalResult}
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
*/
remove(selector: Array): Promise;
remove(...selector: Array): Promise;
/**
* Register a {@link MissingTopicHandler} to handle requests for a branch of
* the topic tree.
*
* The provided handler is called when a client subscribes using a topic
* selector that matches no existing topics. This allows a control client
* session to be notified when another session requests a topic that does
* not exist.
*
* A control client can register multiple handlers, but may only register a
* single handler for a given topic path. See {@link
* MissingTopicHandler.onRegister}. A handler will only be called for topic
* selectors with a {@link TopicSelector.prefix path prefix} that starts
* with or is equal to `topicPath` . If the path prefix matches multiple
* handlers, the one registered for the most specific (longest) topic path
* will be called.
*
* If the session is closed or the handler could not be registered, the
* returned {@link Promise} will call its failure callback, and the handler's
* {@link MissingTopicHandler.onClose} or {@link
* MissingTopicHandler.onError} method will be called.
*
* @param topicPath identifies a branch in the topic tree
* @param handler specifies the handler for the specified branch (unless
* overridden by a handler registered against a more
* specific branch)
*
* @returns a {@link Promise} for this registration
*/
addMissingTopicHandler(path: string, updateHandler: MissingTopicHandler): Promise;
}
/**
* Handler called when a client session subscribes using a topic
* selector that matches no topics. This interface must be implemented by the user.
*
* Handler instances can be registered using
* {@link TopicControl.addMissingTopicHandler addMissingTopicHandler}.
*
* @class MissingTopicHandler
*/
export interface MissingTopicHandler {
/**
* Called when a client session subscribes to a topic selector that selects
* no topics, and the topic path belongs to part of the topic tree for which
* this handler was registered.
*
* @param notification the missing topic notification
*/
onMissingTopic(notification: MissingTopicNotification): void;
/**
* Called when the handler has been successfully registered with the server.
*
* A session can register a single handler for a given branch of the topic
* tree. If there is already a handler registered for the topic path the
* operation will fail and {@link MissingTopicHandler.onClose onClose} will
* be called.
*
* To deregister the handler, call the `deregister` function
* supplied.
*
* @param path the registration path
* @param deregister a function that may be called to deregister this handler.
* The function will resolve when the handler has been
* deregistered.
*/
onRegister(path: string, deregister: () => Promise): void;
/**
* Called when the handler is closed. The handler will be closed if the
* session is closed, or if the handler is unregistered.
*
* Once closed, no further calls will be made for the handler.
*
* @param path the registration path
*/
onClose(path: string): void;
/**
* Notification of a contextual error related to this handler. This is
* analogous to an unchecked exception being raised. Situations in which
* `onError` is called include the session being closed before the
* handler is registered, a communication timeout, or a problem with the
* provided parameters. No further calls will be made to this handler.
*
* @param path the registration path
* @param error the error
*/
onError(path: string, error: any): void;
}
/**
* Notification that a session has made a request using a selector that does
* not match any topics.
*/
export interface MissingTopicNotification {
/**
* The common root topic path derived from the requested topic selector
*/
path: string;
/**
* The topic selector that triggered this notification
*/
selector: TopicSelector;
/**
* Session ID of the client session that triggered this notification
*/
sessionID: SessionId;
/**
* The session properties of the session that made the request
*
* @since 6.7
*/
sessionProperties: SessionProperties;
/**
* A list of the names of the servers through which the notification has
* been routed.
*
* The first name in the list will be the name of the server to which
* the originating session was connected. If the notification was routed
* through remote server connections before reaching the recipient then
* those servers will also be listed in the order that the notification
* passed through them.
*
* @since 6.7
*/
serverNames: string[];
}
/**
* A result returned when a request to add a topic completes
*/
export interface TopicAddResult {
/**
* Whether the Topic was added or not
*/
added: boolean;
/**
* The topic path that was used
*/
topic: string;
}
/**
* Reports the number of topics removed by a call to {@link TopicControl.remove}.
*
* @since 6.6
*/
export interface TopicRemovalResult {
/**
* The integer represents the number of topics removed by the
* operation. This does not include any derived topics created by a
* topic view which were removed as a side effect of this action.
*
* @return the count of topics removed
*/
removedCount: number;
}
/**
* @module Session.notifications
*/
/**
* The type of topic notification that has been received.
*/
export declare enum TopicNotificationType {
/**
* The topic was added.
*/
ADDED = 0,
/**
* The topic existed at the time of the selector registration.
*/
SELECTED = 1,
/**
* The topic was removed.
*/
REMOVED = 2,
/**
* The topic was deselected.
*/
DESELECTED = 3
}
/**
* This feature allows a client session to receive notifications about changes
* to selected topics.
*
* Notifications
*
* Sessions receive notifications via {@link TopicNotificationListener}s. The
* listener will be provided with the {@link TopicSpecification specifications}
* for all topics bound to paths that match registered selectors, and any
* subsequent notifications for the selected topics on those paths, via {@link
* TopicNotificationListener.onTopicNotification onTopicNotificaion}.
* Notifications will only be emitted for paths where a topic is bound.
*
* For example, with a registered selector "?a//" , if a topic is
* added at path a/b/c/d with no topics bound to paths higher in
* the hierarchy {@link TopicNotificationListener.onTopicNotification
* onTopicNotification} will be called once with a topic path of "a/b/c/d"
* , a notification type of {@link TopicNotificationType.ADDED ADDED},
* and the topic's associated {@link TopicSpecification}.
*
* The nature of the notification is provided by the
* {@link TopicNotificationType} enum. {@link TopicNotificationType.ADDED ADDED}
* and {@link TopicNotificationType.REMOVED REMOVED} represent structural
* changes to the topic tree; {@link TopicNotificationType.SELECTED SELECTED}
* indicates that a pre-existing topic has been selected by a new registered
* selector, and similarly {@link TopicNotificationType.DESELECTED DESELECTED}
* indicates that a topic is no longer selected because of changes to the set of
* registered selectors for the listener.
*
* Selection and deselection
*
* Registered {@link TopicNotificationListener TopicNotificationListeners} will
* receive notifications for all topics matching registered selections.
* Selection of topics using {@link TopicSelector} expressions is provided via
* the {@link TopicNotificationRegistration} associated for a specific listener.
*
* A session can request selections at any time, even if the topics do not exist
* at the server. Selections are stored on the server and any subsequently added
* topics that match registered selectors will generate notifications.
*
* Immediate descendant notifications
*
* Listeners will be informed about the presence or absence of unselected
* immediate descendants via {@link
* TopicNotificationListener.onDescendantNotification onDescendantNotification}.
* This allows listeners to determine whether to select deeper topic paths in
* order to walk the topic tree. An immediate descendant is defined as the first
* bound topic on any branch below a given topic path.
*
* For example, for topics at "a/b", "a/c", "a/c/d", "a/e/f/g" ,
* the immediate descendants of "a"} would be "a/b", "a/c",
* "a/e/f/g" .
*
* Immediate descendant notifications provide a {@link TopicNotificationType} to
* indicate the reason for the notification in the same manner as {@link
* TopicNotificationListener.onTopicNotification onTopicNotification}.
*
* For example, with a registered selector ">a" , if a topic is
* added at path a/b then {@link
* TopicNotificationListener.onDescendantNotification onDescendantNotification}
* will be called with a topic path of "a/b" and a notification
* type of {@link TopicNotificationType.ADDED ADDED}. If a topic was
* subsequently added at path a/b/c , no further notifications will
* be received until {@link TopicNotificationRegistration.select} was used to
* select the deeper topic path ">a/b" .
*
*
Access control
*
* A listener will only be notified about topics for
* which the session has {@link PathPermission.SELECT_TOPIC SELECT_TOPIC} and
* {@link PathPermission.READ_TOPIC READ_TOPIC} permissions.
* {@link PathPermission.SELECT_TOPIC SELECT_TOPIC} determines which selectors
* a listener may register; {@link PathPermission.READ_TOPIC READ_TOPIC}
* determines which selected topics the client may receive notifications for.
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
* ```
* const notifications = session.notifications;
* ```
*/
export interface TopicNotifications {
/**
* The topic notification type enum
*/ TopicNotificationType: typeof TopicNotificationType;
/**
* Register a {@link TopicNotificationListener} to receive topic notifications.
*
* @param listener the listener to receive topic notifications
* @returns a {@link Promise} for this operation
*/
addListener(listener: TopicNotificationListener): Promise;
}
/**
* Listener for topic notifications.
*/
export interface TopicNotificationListener {
/**
* Notification for an immediate descendant of a selected topic path. This
* notifies the presence or absence of a descendant topic that may
* subsequently be explicitly selected.
*
* @param path the path of the selected immediate descendant
* @param type the type of notification
*/
onDescendantNotification(path: string, type: TopicNotificationType): void;
/**
* A notification for a selected topic.
*
* @param path the path of the selected topic
* @param specification the specification of the topic that this
* notification is for
* @param type the type of notification
*/
onTopicNotification(path: string, specification: TopicSpecification, type: TopicNotificationType): void;
/**
* Called when the listener is closed. The listener will be closed if the
* session is closed, or if the listener is closed by the {@link
* TopicNotificationRegistration}
*
* Once closed, no further calls will be made to the listener.
*/
onClose(): void;
/**
* Notification of a contextual error related to this listener. This is
* analogous to an Error being thrown. Situations in which
* `onError` is called include the session being closed before the
* listener is registered, a communication timeout, or a problem with the
* provided parameters. No further calls will be made to this listener.
*
* @param {Object} error - The error
*/
onError(error: any): void;
}
/**
* The TopicNotificationRegistration represents the registration state of the
* associated listener on the server.
*
* The TopicNotificationRegistration provides operations to control which topic
* paths the listener will receive notifications for. It can also close the
* listener and remove it from the server.
*/
export interface TopicNotificationRegistration {
/**
* Request to receive notifications for all topics matched by the provided
* topic selector.
*
* This function can take any number of arguments. Each argument can be a string
* or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument. At least one
* valid selector has to be specified.
*
* @param selector the selector to register
* @returns a {@link Promise} for this operation
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
* @throws a {@link NullValueError} if the selector is `null` or `undefined`
*/
select(selector: Array): Promise;
select(...selector: Array): Promise;
/**
* Request to stop receiving notifications for all topics matched by the
* given selector.
*
* This function can take any number of arguments. Each argument can be a
* string or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument. At least one
* valid selector has to be specified.
*
* @param selector the selector to register
* @returns a {@link Promise} for this operation
*/
deselect(selector: Array): Promise;
deselect(...selector: Array): Promise;
/**
* Request that the listener is unregistered from the server.
*/
close(err?: any): void;
}
/**
* @module Session.topicUpdate
*/
/**
* Options for creating a topic update stream or for setting a value using the
* topicUpdate feature.
*/
export interface TopicUpdateOptions {
/**
* an optional constraint that must be satisfied for the topic to be
* updated.
*/
constraint?: UpdateConstraint;
/**
* an optional specification of the topic. If this is specified and the
* topic does not exist at the `path` , one will be created using
* `specification` . If a topic does exist, its specification must match
* `specification` , otherwise the operation will fail with an `Error` .
*/
specification?: TopicSpecification;
}
/**
* Promise of {@link TopicUpdate.applyJsonPatch applyJsonPatch}. Check {@link
* JsonPatchResult.failedOperation failedOperation} to determine whether any of
* the operations failed.
*
* @since 6.4
*/
export interface JsonPatchResult {
/**
* If present, this contains the index of the first operation which failed.
*/
failedOperation?: number;
}
/**
*
* This feature provides a client session with the ability to update topics.
*
* Topics can be set to new values using stateless {@link TopicUpdate.set set}
* operations or an {@link UpdateStream UpdateStream}. Both ensure that new
* values are applied safely to appropriate topics.
*
* Additionally, JSON topics can be updated with a
* {@link TopicUpdate.applyJsonPatch JSON Patch}. A patch is a list of
* operations that modifies a JSON value, removing the need to supply a complete
* new value. This is useful if the source of the updates doesn't provide
* values. For one-off, small changes to large JSON values, it can be
* significantly cheaper to apply a patch than to use `set` to provide the
* complete value.
*
* Update streams
*
* An update stream is created for a specific topic. An
* UpdateStreamBuilder can be obtained using {@link TopicUpdate.newUpdateStreamBuilder}.
* The type of the topic must
* match the type of values passed to the update stream. An update stream can be
* used to send any number of updates. It sends a sequence of updates for a
* specific topic to the server. If supported by the data type, updates will be
* sent to the server as a stream of binary deltas.
*
* Update streams have additional ways of failing compared to stateless set
* operations but when used repeatedly have lower overheads. This is because
* update streams maintain a small amount of state that reduces the overhead of
* operations but can become invalid for example, if the topic is deleted, or
* some other session updates the topic value.
*
* By default, update streams use a form of optimistic locking. An update stream
* can update its topic incrementally as long as nothing else updates the topic.
* If the topic is updated independently (for example, by another session, or by
* the current session via set or a different update stream), then the next
* update performed by the update stream will result in an error.
*
* Applications can choose to use collaborative locking to coordinate exclusive
* access to a topic. To follow this pattern acquire a {@link SessionLock
* session lock}, and use it with a
* {@link UpdateConstraintFactory.locked lock constraint}. The application is
* responsible for designing a locking scheme which determines which lock is
* required to access a particular topic, and for ensuring that all parts of the
* application that update the topic follow this scheme. Lock constraints and an
* application locking scheme can also ensure a sequence of set operations has
* exclusive access to the topic.
*
* Removing values
*
* When a {@link TopicType.STRING string}, {@link TopicType.INT64 int64}, or
* {@link TopicType.DOUBLE double} topic is set to `null`, the topic will be
* updated to have no value. If a previous value was present subscribers will
* receive a notification that the new value is `null`. New subscribers will not
* receive a value notification. Attempting to set any other type of topic to
* `null` will cause an error to be thrown.
*
* Adding topics
*
* When setting a value using either stateless operations or update streams it
* is possible to add a topic if one is not present. This is done by providing a
* topic specification when calling {@link TopicUpdate.set set} or when creating
* the update stream. If a topic exists these methods will update the existing
* topic.
*
* Time series topics
*
* All methods provided by this feature are compatible with time series topics
* except for {@link TopicUpdate.applyJsonPatch}. The {@link TimeSeries} feature
* can be used to update time series topics with custom metadata and provides
* query capabilities.
*
* Access control
*
* To update a topic a session needs {@link PathPermission.UPDATE_TOPIC
* UPDATE_TOPIC} permission for the topic path. To create a topic a session
* needs {@link PathPermission.MODIFY_TOPIC MODIFY_TOPIC} permission for the
* topic path. Requests that combine adding a topic and setting the value
* require both permissions.
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
* ```
* var topicUpdate = session.topicUpdate;
* ```
*
* @since 6.2
*/
export interface TopicUpdate {
/**
* Sets the topic to a specified value.
*
* `null` or `undefined` can only be passed to the
* `value` parameter when updating
* {@link TopicType.STRING STRING},
* {@link TopicType.INT64 INT64} or
* {@link TopicType.DOUBLE DOUBLE} topics.
*
* When a topic of type {@link TopicType.STRING STRING},
* {@link TopicType.INT64 INT64} or
* {@link TopicType.DOUBLE DOUBLE} is set
* to `null` or `undefined` , the topic will be updated
* to have no value. If a previous value was present subscribers will
* receive a notification that the new value is `undefined` . New
* subscribers will not receive a value notification.
*
* **Example:**
* ```
* session.topicUpdate.set('my_topic', diffusion.datatypes.string(), 'hello');
* ```
*
* @param path the path of the topic
* @param dataType the type of the values
* @param value the value. String, int64, and double topics accept
* `null` or `undefined` , as described above.
* Using `null` or `undefined` with other
* topic types is an error and will throw an `Error` .
* @param options optional options object
* @return a Promise that resolves when a response is received
* from the server. If a topic specification is provided
* in the options, the Promise will resolve with a
* {@link TopicCreationResult} that contains the
* specification of the topic that was created.
*
* If the task fails, the Promise will resolve with an
* `Error`.
*
* @throws an {@link IllegalArgumentError} if a topic specification was provided
* and the value type does not match the topic type
*/
set(path: string, dataType: DataType, value: any, options?: TopicUpdateOptions): Promise;
/**
* Creates an {@link UpdateStream update stream} to
* use for updating a specific topic.
*
* The type of the topic being updated must match the type derived from the
* `dataType` parameter.
*
* Update streams send a sequence of updates for a specific topic. They can
* result in more efficient use of the network as only the differences
* between the current value and the updated value are transmitted. They do
* not provide exclusive access to the topic. If exclusive access is
* required update streams should be used with {@link SessionLock session
* locks} as constraints.
*
* Streams are validated lazily when the first
* {@link UpdateStream.set set} or
* {@link UpdateStream.validate validate} operation is
* completed. Once validated a stream can be invalidated, after which it
* rejects future updates.
*
* **Example:**
* ```
* const stream = session.topicUpdate.createUpdateStream('my_topic', diffusion.datatypes.string());
* stream.set('hello');
* ```
*
* @param path the path of the topic
* @param dataType the type of the values expected by the update stream
* @param options optional options object
* @return an update stream
* @throws an {@link IllegalArgumentError} if the topic type is not compatible with the
* `dataType` parameter
*
* @deprecated since 6.9, use {@link TopicUpdate.newUpdateStreamBuilder}
*/
createUpdateStream(path: string, dataType: DataType, options?: TopicUpdateOptions): UpdateStream;
/**
* Creates an update stream builder to use for creating
* update streams.
*
* @return an update stream builder
*/
newUpdateStreamBuilder(): UpdateStreamBuilder;
/**
* Applies a JSON Patch to a JSON topic.
*
* The `patch` argument should be formatted according to the JSON
* Patch standard (RFC 6902).
*
* Patches are a sequence of JSON Patch operations contained in an array.
* The following patch will insert a number at a specific key and then test
* that it was added:
*
* ```
* [{"op":"add", "path":"/price", "value" : 41},
* {"op":"test", "path":"/price", "value": 41}]
* ```
*
* The available operations are:
*
* * Add: `{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }`
* * Remove: `{ "op": "remove", "path": "/a/b/c" }`
* * Replace: `{ "op": "replace", "path": "/a/b/c", "value": 43 }`
* * Move: `{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" }`
* * Copy: `{ "op": "copy", "from": "/a/b/c", "path": "/a/b/e" }`
* * Test: `{ "op": "test", "path": "/a/b/c", "value": "foo" }`
*
* The test operation checks that the CBOR representation of the value of a
* topic is identical to value provided in the patch after converting it to
* CBOR. If the value is represented differently as CBOR, commonly due to
* different key ordering, then the patch will fail with an error. E.g the
* values `{"foo": "bar", "count": 43}` and `{"count": 43, "foo": "bar"}`
* are unequal despite semantic equality due to the differences in a byte
* for byte comparison.
*
* @param path the path of the topic to patch
* @param patch the JSON Patch
* @param constraint optional constraint that must be satisfied for the patch to
* be applied
* @return a {@link Promise} that resolves when a response is received from
* the server.
*
* If the task fails, the Promise will reject with an error. Common reasons
* for failure include:
*
*
* - the patch is not a valid JSON Patch;
*
- applying the patch fails;
*
- there is no topic bound to
path;
* - the patch cannot be applied to the topic, for example if the
* topic type is not {@link DataTypes.json}.
*
- updates cannot be applied to the topic because an exclusive
* update source is registered for its path;
*
- the topic is managed by a component (such as fan-out) that
* prohibits updates from the caller;
*
- the cluster was repartitioning;
*
- the calling session does not have the {@link
* PathPermission.UPDATE_TOPIC UPDATE_TOPIC} permission for `path`;
*
- the session is closed.
*
*
* @see
* JavaScript Object Notation (JSON) Patch
*
* @since 6.4
*/
applyJsonPatch(path: string, patch: string | Array<{
[key: string]: any;
}>, constraint?: UpdateConstraint): Promise;
}
/**
* Description of a topic view that has been created.
*
* @since 6.3
*/
export interface TopicView {
/**
* The name of the topic view.
* If the name is empty, the operation will fail.
*/
readonly name: string;
/**
* The specification of the topic view.
*
* See the view
* specification for the description of the DSL for more
* information.
*/
readonly specification: string;
/**
* The roles used by the view when evaluating permissions.
*/
readonly roles: Set;
}
/**
* Topic view feature.
*
* This feature allows a client session to manage topic views.
*
* A topic view maps one part of a server's topic tree to another. It
* dynamically creates a set of reference topics from a set of
* source topics, based on a declarative topic view
* specification. The capabilities of topic views range from simple
* mirroring of topics within the topic tree to advanced capabilities including
* publication of partial values, expanding a single topic value into many
* topics, changing topic values, inserting values from other topics, throttling
* the rate of publication, and applying a fixed delay to the publication.
*
* A topic view can also map topics from another server (in a different
* cluster). This capability is referred to as 'remote topic views'. The view
* can specify the server that the source topics are hosted on in terms
* of a remote server (see {@link RemoteServers} for details of how to
* create and maintain remote servers).
*
* Each reference topic has a single source topic and has the same topic type as
* its source topic. Reference topics are read-only (they cannot be updated),
* nor can they be created or removed directly. Otherwise, they behave just like
* standard topics. A client session can subscribe to a reference topic, and can
* fetch the reference topic's current value if it has one.
*
* The source topics of a topic view are defined by a topic selector. One or
* more reference topics are created for each source topic, according to the
* topic view. If a source topic is removed, reference topics that are derived
* from it will automatically be removed. If a topic is added that matches the
* source topic selector of a topic view, corresponding reference topics will be
* created. Removing a topic view will remove all of its reference topics.
*
* Topic view specifications
*
* Topic views are specified using a Domain Specific Language (DSL) which
* provides many powerful features for manipulating topic data. For a full and
* detailed description of the topic views DSL see the user
* manual.
*
* The following is a simple topic view specification that mirrors all topics
* below the path a to reference topics below the path
* b.
*
*
* map ?a// to b/<path(1)>
*
*
* A topic view with this specification will map a source topic at the path
* a/x/y/z to a reference topic at the path b/x/y/z.
* The specification is simple, so the reference topic will exactly mirror the
* source topic. Other topic views features allow a single topic to be mapped to
* many reference topics and have the data transformed in the process.
*
* Topic view persistence and replication
*
* Reference topics are neither replicated nor persisted. They are created and
* removed based on their source topics. However, topic views are replicated and
* persisted. A server that restarts will restore topic views during recovery.
* Each topic view will then create reference topics based on the source topics
* that have been recovered.
*
* The server records all changes to topic views in a persistent store. Topic
* views are restored if the server is started.
*
* If a server belongs to a cluster, topic views (and remote servers) will be
* replicated to each server in the cluster. Topic views are evaluated locally
* within a server. Replicated topic views that select non-replicated source
* topics can create different reference topics on each server in the cluster.
* When remote topic views are in use, each server in the cluster will make a
* connection to the specified remote server and will separately manage their
* remote topic views.
*
* A view with a delay clause uses temporary storage to record delayed events.
* If there is a high volume of updates, temporary per-server disk files will be
* used to save server memory. The storage is per-server, and does not survive
* server restart. When a server is started, no data will be published by a view
* with a delay clause until the delay time has expired.
*
* Access control
*
* The following access control restrictions are applied:
*
*
* - To {@link listTopicViews list the topic views}, a session needs the
* {@link GlobalPermission.READ_TOPIC_VIEWS READ_TOPIC_VIEWS} global permission.
*
*
- To {@link createTopicView create, replace}, or
* {@link removeTopicView remove} a topic view, a session needs the
* {@link GlobalPermission.MODIFY_TOPIC_VIEWS MODIFY_TOPIC_VIEWS} global
* permission and {@link PathPermission.SELECT_TOPIC SELECT_TOPIC} permission
* for the path prefix of the source topic selector.
*
*
- Each topic view records the principal and security roles of the session
* that created it as the topic view security context. When a topic
* view is evaluated, this security context is used to constrain the creation of
* reference topics. A reference topic will only be created if the security
* context has {@link PathPermission.READ_TOPIC READ_TOPIC} permission for the
* source topic path, and {@link PathPermission.MODIFY_TOPIC MODIFY_TOPIC}
* permission for the reference topic path. The topic view security context is
* copied from the creating session at the time the topic view is created or
* replaced, and is persisted with the topic view. The topic view security
* context is not updated if the roles associated with the session are changed.
*
*
*
* Accessing the feature
*
* This feature may be obtained from a {@link Session session} as follows:
*
*
* const topicViews = session.topicViews;
*
*
* @since 6.3
*
*/
export interface TopicViews {
/**
* Create a new named topic view.
*
* If a view with the same name already exists the new view will update
* the existing view.
*
* @param name the name of the view
* @param specification the specification of the view using the DSL
* @return a Promise that completes when a response is received
* from the server, returning the topic view created by the
* operation.
*
* If the task fails, the Promise will resolve with an error. Common reasons
* for failure, include:
*
* - the `specification` is invalid;
*
- the cluster was repartitioning;
*
- the calling session does not have MODIFY_TOPIC_VIEW
* permission or appropriate path prefix permissions;
*
- the session is closed.
*
- {@link IllegalArgumentError} if the name is empty
*
- {@link NullValueError} – if any of the arguments are `null` or `undefined`
*
*/
createTopicView(name: string, specification: string): Promise;
/**
* List all the topic views that have been created.
*
* @return a Promise that resolves when a response is received from the
* server, returning a list of views sorted by their creation
* order.
*
* If the task fails, the Promise will resolve with an Error. Common
* reasons for failure include:
*
* - the cluster was repartitioning;
*
- the calling session does not have READ_TOPIC_VIEW permission
* or appropriate path prefix permissions;
*
- the session is closed.
*
*/
listTopicViews(): Promise;
/**
* Get a named Topic View.
*
* If the named view does not exist the Promise will resolve with null result.
*
* @param name the name of the view
* @return a Promise that resolves when a response is received from the server,
* returning a named view if it exists
*
* If the task fails, the Promise will resolve with an Error. Common
* reasons for failure include:
*
* - the operation failed due to a transient cluster error;
*
- the calling session does not have READ_TOPIC_VIEW permission or
* appropriate path prefix permissions;
*
- the session is closed.
*
- {@link NullValueError} – if the name is null` or `undefined`
*
*/
getTopicView(name: string): Promise;
/**
* Remove a named topic view if it exists.
*
* If the named view does not exist the completable future will complete
* successfully.
*
* @param name the name of the view
* @return a Promise that resolves when a response is received from the
* server.
*
* If the task fails, the Promise will resolve with an Error. Common
* reasons for failure include:
*
* - the cluster was repartitioning;
*
- the calling session does not have MODIFY_TOPIC_VIEW
* permission or appropriate path prefix permissions;
*
- the session is closed.
*
- {@link NullValueError} – if the name is null` or `undefined`
*
*/
removeTopicView(name: string): Promise;
}
/**
* @module Session
*/
/**
* This feature allows a client session to subscribe to topics to receive
* streamed topic updates, fetch the state of topics and/or update topics with
* new values.
*
* Specifically, the feature provides the ability to:
*
* - Subscribe to topics and specify streams to receive updates;
*
- Fetch the current state of topics (even if not subscribed);
*
- By extending the {@link TopicUpdate topic update feature}, update topics
* with new values;
*
- By extending the {@link TopicViews topic views feature}, manage topic
* views.
*
* Subscription and unsubscription
*
* A session can issue requests to subscribe to topics at any time, even if the
* topics do not exist at the server. Each subscription request provides a
* {@link TopicSelector topic selector} that is evaluated by the server to
* select matching topics. The session will be subscribed to any topics that
* match the selector unless they are already subscribed, or the session has
* insufficient permission. The subscription request is also retained at the
* server and the session will be automatically subscribed to newly created
* topics that match the selector (unless a subsequent unsubscription cancels
* the request).
*
* Sessions receive notifications from topics that they are subscribed to via
* subscription streams (see below). When a session is subscribed to a
* topic, all matching streams will first receive a subscription notification
* that provides details about the topic. If the server has a value for the
* topic, the value will be delivered to the streams before any other
* notifications.
*
* A session can unsubscribe from topics at any time. This is also specified
* using a topic selector. On unsubscription, matching streams are notified via
* the `on('unsubscribe')` notification. This notification will give the
* reason for unsubscription (for example, by request of the session, request of
* the server, or topic removal).
*
* Subscriptions and unsubscriptions can occur for reasons other than requests
* from the session. A session can be subscribed to or unsubscribed from a topic
* by another session using the {@link ClientControl} feature. The removal
* of a topic also automatically causes unsubscription for subscribed sessions.
*
* Subscription requests are subject to authorisation checks. The session must
* have {@link PathPermission.SELECT_TOPIC SELECT_TOPIC} permission for the
* topic selector used to subscribe. Matching topics will be further filtered to
* those for which the session has {@link PathPermission.READ_TOPIC READ_TOPIC}
* permission.
*
* Topic selection scopes
*
* Topic selection scopes allow an application with multiple components to use a
* single Diffusion session. An application component can use a topic selection
* scope to manage a set of selectors that is unaffected by unsubscriptions
* performed by other application components. The session will be subscribed to
* all topics with paths matching a selector in any scope. The unsubscribe
* operation removes a selector from specific scopes.
*
* A scope may be specified to a {@link Topics.select select} or
* {@link Topics.unsubscribe unsubscribe} method, indicating that the
* selection only applies to that scope. The server manages scopes to ensure
* that unsubscriptions applied to one scope do not affect another.
*
* Scope names are case sensitive. A scope name may not begin with the character
* $ as this is reserved for internal use.
*
* Unsubscription using a wildcard selector that indicates all topics (such as
* "?.*//") effectively removes the scope.
*
* An application can request unsubscription from all scopes using
* {@link Topics.unsubscribeAllScopes unsubscribeAllScopes}.
*
* The {@link Topics.DEFAULT_SELECTION_SCOPE default selection scope} is used for all
* methods that do not explicitly specify a scope.
*
*
Subscription streams
*
* A session can listen to subscription events and updates for a selection of
* topics by adding one or more streams. A stream is registered using a topic
* selector which specifies the topics that the stream applies to. When an
* update is received for a topic then it will be routed to every stream that
* matches both the topic selector and the stream's value type. If more than one
* stream matches, all will receive the update; the order in which they are
* notified is not defined.
*
* A stream can be added several times for different selectors. The mapping of
* topic selectors to streams is maintained locally in the client process.
*
* It is also possible to add one or more fallback streams which will
* receive updates that do not match any stream registered with a selector. This
* is useful for default processing or simply to catch unprocessed updates. A
* fallback stream can be added using {@link Topics.addFallbackStream
* addFallbackStream}. Zero, one, or more fallback streams may be assigned. If
* no fallback stream is specified, any updates that are not routed to any other
* stream will simply be discarded.
*
* If the session is already subscribed to a topic when a matching stream is
* added, the stream will immediately receive a subscription notification. For
* most topic types, the latest value is locally cached and will be provided to
* the stream following the subscription notification.
*
* A stream will receive a {@link Stream.on close} callback when unregistered
* and an {@link Stream.on error(SESSION_CLOSED)} callback if the session is
* closed.
*
* Value streams
*
* A {@link ValueStream ValueStream} receives values for matching topics as and
* when updates are received from the server. Delta updates received from the
* server are automatically applied to locally cached values so that the stream
* always receives full values for each update.
*
* Value streams are typed to a specified value class and only updates for
* compatible topics will be routed to the stream. The following table shows how
* the value class maps to compatible topic types that will be routed to the
* stream:
*
*
*
* | Value Class |
* Compatible Topic Types |
*
*
* | {@link JSONDataType JSON} |
* {@link TopicType.JSON JSON} {@link TopicType.STRING STRING}
* {@link TopicType.INT64 INT64} {@link TopicType.DOUBLE DOUBLE}
* |
*
* | {@link StringDataType String} |
* {@link TopicType.STRING STRING} |
*
*
* | {@link Int64DataType Int64} |
* {@link TopicType.INT64 INT64} |
*
*
* | {@link DoubleDataType Double} |
* {@link TopicType.DOUBLE DOUBLE} |
*
*
* | {@link BinaryDataType Binary} |
* {@link TopicType.BINARY BINARY} |
*
*
* | {@link Bytes} |
* {@link TopicType.JSON JSON} {@link TopicType.STRING STRING}
* {@link TopicType.INT64 INT64} {@link TopicType.DOUBLE DOUBLE}
* {@link TopicType.BINARY BINARY} {@link TopicType.RECORD_V2 RECORD_V2} |
*
*
* | {@link RecordV2} |
* {@link TopicType.RECORD_V2 RECORD_V2} |
*
*
*
* Value stream implementations can be added using
* {@link Topics.addStream addStream}. A value stream can be also added to
* received updates from {@link TimeSeries time series topics}. The following
* table shows how the value class specified when adding the stream maps to the
* event value class of time series topics that will be routed to the stream:
*
*
*
* | Event Value Class |
* Time Series Event Value Class |
*
*
* | {@link JSONDataType JSON} |
* {@link TopicType.JSON JSON} {@link TopicType.STRING STRING}
* {@link TopicType.INT64 INT64} {@link TopicType.DOUBLE DOUBLE}
* |
*
* | {@link StringDataType String} |
* {@link TopicType.STRING STRING} |
*
*
* | {@link Int64DataType Int64} |
* {@link TopicType.INT64 INT64} |
*
*
* | {@link DoubleDataType Double} |
* {@link TopicType.DOUBLE DOUBLE} |
*
*
* | {@link BinaryDataType Binary} |
* {@link TopicType.BINARY BINARY} |
*
*
* | {@link Bytes} |
* {@link TopicType.JSON JSON} {@link TopicType.STRING STRING}
* {@link TopicType.INT64 INT64} {@link TopicType.DOUBLE DOUBLE}
* {@link TopicType.BINARY BINARY} {@link TopicType.RECORD_V2 RECORD_V2} |
*
*
* | {@link RecordV2} |
* {@link TopicType.RECORD_V2 RECORD_V2} |
*
*
*
* Fetch
*
* A session can issue a request to fetch details of a topic or topics (subject
* to authorization) at any time. The topics required are specified using a
* topic selector.
*
* The results of a fetch will return the topic path and type of each selected
* topic. The results may also optionally return the topic values and/or
* properties.
*
* A new request can be created using {@link Topics.fetchRequest} and modified to
* specify additional requirements of the fetch operation. The request is issued
* to the server using the {@link FetchRequest.fetch fetch}
* method on the request. This will return the results via a Promise.
*
*
* Access control
*
* A session must have {@link PathPermission.SELECT_TOPIC SELECT_TOPIC}
* permission for the topic selector used to
* {@link Topics.select subscribe} or {@link Topics.fetchRequest fetch}.
* The topics that result from a subscription or fetch request are further
* filtered using the {@link PathPermission.READ_TOPIC READ_TOPIC} permission.
*
* No access control restrictions are applied to
* {@link Topics.unsubscribe unsubscription}.
*
* Accessing the feature
*
* This feature is directly available on a {@link Session session} object:
*
* @example
*
* session.select('foo/bar);
*
*
* @author DiffusionData Limited
* @since 5.0
*/
export interface Topics {
/**
* The default topic selection scope.
*
* This is used by {@link Topics.select select} and
* {@link Topics.unsubscribe unsubscribe} methods that do not explicitly
* specify a topic selection scope.
*
* @see Topics Topic Selection Scopes
*/
readonly DEFAULT_SELECTION_SCOPE: string;
/**
* Unsubscribe the client from a given topic selector with the {@link
* Topics.DEFAULT_SELECTION_SCOPE default selection scope}.
*
* This is equivalent to calling {@link Topics.unsubscribeWithScope} with
* the {@link Topics.DEFAULT_SELECTION_SCOPE default selection scope}.
*
* **Example:**
* ```
* // Unsubscribe from a single topic
* session.unsubscribe('foo');
* ```
*
* **Example:**
* ```
* // Unsubscribe from multiple topics
* session.unsubscribe('?foo/.*');
* ```
*
* @param selector the topic selector to unsubscribe from.
* @returns a Promise for this operation
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
*/
unsubscribe(selector: Array): Promise;
unsubscribe(...selector: Array): Promise;
/**
* Unsubscribe the client from a given topic selector.
*
* No more updates will be received from the server for any topics matched
* by the selector. If no topics exist that match the selector, the server
* will do nothing.
*
* Each topic that this session is unsubscribed from will cause an
* `unsubscribe` event. Any {@link ValueStream} objects produced from {@link
* Session.addStream} will remain open, and will continue to emit updates
* for topics that the session has not been unsubscribed from.
*
* The returned result will resolve normally when the session has been
* unsubscribed. It will resolve with an error if the session is unable to
* unsubscribe, for instance due to security constraints.
*
* This function can take any number of arguments. Each argument can be a
* string or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument. At least one
* valid selector has to be specified.
*
* **Example:**
* ```
* // Unsubscribe from a single topic
* session.unsubscribe('foo');
* ```
*
* **Example:**
* ```
* // Unsubscribe from multiple topics
* session.unsubscribe('?foo/.*');
* ```
*
* @param selector the topic selector to unsubscribe from.
* @param scope (optional) specifies the scope of the selection. See {@link Topics
* Topic Selection Scopes}. Defaults to {@link
* Topics.DEFAULT_SELECTION_SCOPE DEFAULT_SELECTION_SCOPE}.
* @returns a Promise for this operation
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
*/
unsubscribeWithScope(selector: string | TopicSelector | Array, scope?: string): Promise;
/**
* Unsubscribe topics from all topic selection scopes.
*
* This can be used at any time whilst connected to reduce the set of topics
* to which the session is subscribed or negate earlier subscription
* requests and will apply to all scopes in use.
*
* @param topics the topics to unsubscribe from
*
* @throws IllegalArgumentException if topics is an invalid topic selector
* expression
*
* @param selector the topic selector to unsubscribe from.
* @param scope (optional) specifies the scope of the selection. See {@link Topics
* Topic Selection Scopes}. Defaults to {@link
* Topics.DEFAULT_SELECTION_SCOPE DEFAULT_SELECTION_SCOPE}.
* @returns a Promise for this operation
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
*
* @since 6.12
*/
unsubscribeAllScopes(selector: string | TopicSelector | Array): Promise;
/**
* Creates an unconfigured fetch request.
*
* The returned request can be invoked with
* {@link FetchRequest.fetch fetch}. The server will evaluate
* the query and return a fetch result that provides the paths and types of
* the matching topics which the session has permission to read.
*
* You will usually want to restrict the query to a subset of the topic
* tree, and to retrieve the topic values and/or properties. This is
* achieved by applying one or more of the fluent builder methods provided
* by {@link FetchRequest} to produce more refined requests.
*
* **Example:**
* ```
* // Create and send a fetch request. Then pass the results to a resultHandler
* session.fetchRequest()
* .withValues(diffusion.datatypes.StringDataType)
* .fetch("*A/B//")
* .then(resultHandler);
* ```
*
* @see diffusion.topics.FetchRequest
*
* @returns a new unconfigured fetch request
*
* @since 6.2
*/
fetchRequest(): FetchRequest;
/**
* Request subscription to topics.
*
* The session will become subscribed to each existing topic matching the
* selector unless the session is already subscribed to the topic, or the
* session does not have {@link PathPermission.READ_TOPIC READ_TOPIC}
* permission for the topic path. For each topic to which the session
* becomes subscribed, a subscription notification and initial value (if
* any) will be delivered to registered value streams before the returned
* CompletableFuture completes.
*
* The subscription request is also retained at the server and the session
* will be automatically subscribed to newly created topics that match the
* selector (unless a subsequent unsubscription cancels the request).
*
* @param topics specifies the topics to request subscription to
*
* @param scope (optional) specifies the scope of the selection. See {@link Topics
* Topic Selection Scopes}. If not specified, the {@link Topics.DEFAULT_SELECTION_SCOPE
* default selection scope} will be used.
*
* @returns a result that completes when this operation succeeds
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
* @since 6.12
*/
selectWithScope(selector: string | TopicSelector | Array, scope?: string): Promise;
/**
* Subscribe the session to a topic selector with the the {@link
* Topics.DEFAULT_SELECTION_SCOPE default selection scope} in order to receive updates and
* subscription events.
*
* Subscription causes the server to establish a subscription for this
* session to any topic that matches the specified selector, including topics
* that are added after the initial call to {@link Session.select}.
*
* If the provided selector string does not begin with one of the prefixes
* defined by {@link TopicSelectors}, it will be treated as a direct topic
* path.
*
* This function can take any number of arguments. Each argument can be a string
* or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument. At least one
* valid selector has to be specified.
*
* The session will become subscribed to each existing topic
* matching the selector unless the session is already subscribed
* to the topic, or the session does not have {@link PathPermission.READ_TOPIC READ_TOPIC}
* permission for the topic path. For each topic to which the
* session becomes subscribed, a subscription notification and
* initial value (if any) will be delivered to registered value
* streams before the returned promise completes.
*
* The subscription request is also retained at the server and the
* session will be automatically subscribed to newly created
* topics that match the selector (unless a subsequent
* unsubscription cancels the request).
*
* **Example:**
* ```
* // Subscribe to a topic foo
* session.select("foo").then(function() {
* // Successfully subscribed
* }, function(err) {
* // There was an error with subscribing to topic "foo"
* });
* ```
*
* @param selector the topic selector to subscribe to.
* @returns a result that completes when this operation succeeds
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
*/
select(selector: Array): Promise;
select(...selector: Array): Promise;
/**
* Create a {@link ValueStream} to receive updates from topics that match
* the provided topic selector.
*
* This method will not cause the server to send any topic updates unless
* already subscribed. This allows the registration of listeners prior to
* subscribing via {@link Session.select}, or to add/remove listeners
* independently of subscriptions on the server.
*
* The values as specific types, use the Streams will only receive values
* from topics for which the specified {@link DataTypes Data Type}
* is compatible. Passing {@link AnyDataType} as second argument will create
* a polymorphic value stream that receives all data types. It is then up to
* the value handler to interpret the incoming data.
*
* The first argument of this function can be a string, a {@link
* TopicSelector}, or a non-empty array of strings and {@link TopicSelector}s.
*
* **Example:**
* ```
* // Produce a value stream for receiving JSON values.
* var json = diffusion.datatypes.json();
*
* session.addStream(topic, json).on('value', function(topic, specification, newValue, oldValue) {
* console.log('New value ', newValue.get());
* });
* ```
*
* @param selector the topic selector to receive updates for
* @param datatype the data type to produce a stream for.
* @returns a new {@link ValueStream} for the provided data type
* @throws an {@link IllegalArgumentError} if dataType is not a valid data type
* or if the selector could not be parsed
*/
addStream(selector: string | TopicSelector | Array, dataType: DataType | AnyDataType): ValueStream;
/**
* This adds a value stream for a given {@link DataTypes Data
* Type} without a selector which will be a fallback stream to receive all
* events that do not have a stream registered.
*
* **Example:**
* ```
* // Produce a fallback value stream for receiving JSON values.
* var json = diffusion.datatypes.json();
*
* session.addFallbackStream(json).on('value', function(topic, specification, newValue, oldValue) {
* console.log('New value ', newValue.get());
* });
* ```
*
* @param datatype the data type to produce a stream for.
* @returns a fallback stream
* @throws an {@link IllegalArgumentError} if dataType is not a valid data type
*/
addFallbackStream(dataType: DataType): ValueStream;
}
/**
* @module diffusion.selectors
*/
/**
* A `TopicSelector` is a value that identifies one or more topics.
*
* Depending on where it is used, a selector may be evaluated by either the
* server or the client library. For example, the server evaluates the selector
* used to subscribe to a topic. In contrast, the selector used to register a
* topic handler is evaluated by the client. Applications do not normally need
* to evaluate selectors, but may do so using {@link TopicSelector.selects selects}.
*
* A client may receive a selector providing the context for certain operations.
* For example, to allow it to veto subscriptions. Limited ability to query the
* selector's {@link TopicSelector.type} and associated {@link TopicSelector.expression
* expression} is provided.
*
* Selectors may be created using {@link TopicSelectors}.
*/
export interface TopicSelector {
/**
* The type of this selector
*/
readonly type: Type;
/**
* The maximum topic path prefix from this selector
*/
readonly prefix: string;
/**
* The original expression of this selector
*/
readonly expression: string;
/**
* Evaluate this selector against a topic path
*
* @param topicPath the topic path
* @returns if this selector selects the topic path
*/
selects(topicPath: string): boolean;
/**
* Convert the topic selector to a string
*
* @return the original expression of the selector
*/
toString(): string;
}
/**
* A Topic Selector Prefix
*/
export declare enum Prefix {
/** Prefix used for {@link Type.PATH} expressions. */
PATH = ">",
/** Prefix used for {@link Type.SPLIT_PATH_PATTERN} expressions. */
SPLIT_PATH_PATTERN = "?",
/** Prefix used for {@link Type.FULL_PATH_PATTERN} expressions. */
FULL_PATH_PATTERN = "*",
/** Prefix used for {@link Type.SELECTOR_SET} expressions. */
SELECTOR_SET = "#"
}
/**
* Topic Selector type.
*/
export declare enum Type {
/** A selector that selects a single topic. */
PATH = ">",
/** A selector that is a split-path pattern. */
SPLIT_PATH_PATTERN = "?",
/** A selector that is a full-path pattern. */
FULL_PATH_PATTERN = "*",
/** A composite of multiple selectors. */
SELECTOR_SET = "#"
}
/**
* @module diffusion.selectors
*/
/**
* Create {@link TopicSelector} instances for use with other API methods.
*
* Selectors are evaluated against topic paths. A topic path is a '/'
* separated string of parts, which map to the topic tree. Each part is
* formed of one or more UTF characters, except '/'. Topic paths are absolute,
* and evaluated from the root of the topic tree.
*
* **Example:**
* ```
* // Create a topic selector
* var selector = diffusion.selectors.parse('?foo/bar/.*');
* ```
*/
export declare class TopicSelectors {
/**
* The Prefix enum
*/ readonly Prefix: typeof Prefix;
/**
* The Type enum
*/ readonly Type: typeof Type;
/**
* Parse an expression to create a selector.
*
* The following types of expression are supported. The type is determined
* by the first character of the expression.
*
*
* - Path
*
- Path expressions begin with the character
>. The remainder of
* the expression must be a valid topic path. A topic path is a '/'
* separated string of parts. Each part is formed of one or more UTF
* characters, except '/'.
*
* A {@link Type.PATH PATH} selector is returned that only
* selects the topic with the given path.
*
*
* The initial > can be omitted if the path begins with a character
* other than one of #, ?, >,
* *, $, %, &, or
* <. This abbreviated syntax allows most
* topic paths to be used directly as selector expressions which appears
* more natural. Abbreviated path expressions are converted to standard path
* expressions by prepending the > character. Thus
* a/b is interpreted as >a/b.
*
* Diffusion.topicSelectors().parse("a/b").getExpression() will
* return ">a/b".
*
*
- Split-path pattern
*
- Split-path pattern expressions begin with the character
?.
* The remainder of the expression is split into a list of regular
* expressions using the / character as a separator.
*
*
* A {@link Type.SPLIT_PATH_PATTERN SPLIT_PATH_PATTERN}
* selector is returned that selects topics for which each regular
* expression matches each part of the topic path at the corresponding
* level.
*
*
* - Full-path pattern
*
- Full-path pattern expressions begin with the character
*.
* The remainder of the pattern is a regular expression.
*
*
* A {@link Type.FULL_PATH_PATTERN FULL_PATH_PATTERN} selector
* is returned that selects topics for which the regular expression matches
* the complete topic path.
*
*
*
* Full-path patterns provide a lot of expressive power but should be used
* sparingly since the server can evaluate split-path patterns more
* efficiently.
*
*
* Selector sets are the preferred way to combine expressions.
* anyOf("a", "b") is equivalent to the full-path expression "
* * /a|/b", but can be evaluated more efficiently by the
* server.
*
*
- Selector set
*
- Selector set expressions begin with the character
#. The
* remainder of the expression is a list of contained selectors, formatted
* as described below.
*
* A {@link Type.SELECTOR_SET SELECTOR_SET} selector is
* returned that selects topics that match any of the contained selectors.
*
* The contained selectors are formatted as follows. First, any selector sets
* are expanded to produce a full list of non-selector set expressions. Then
* the selector expressions are concatenated, separated by the separator
* ////. This separator has been chosen as it is not valid in a
* path, and is not a useful sequence in a pattern.
*
*
* Descendant pattern qualifiers
*
* Split-path and full-path pattern expressions can be further modified by
* appending / or //. These control the behavior of the
* selector with respect to the descendants of the topics that match the
* pattern.
*
*
*
* - If the expression does not end with
/ or //, it
* selects only the topics that match the pattern.
*
* - If the expression ends with
/, it selects only the
* descendants of the matching topics, excluding the matching topics.
*
* - If the expression ends with
//, it selects the matching
* topics and all of their descendants.
*
*
* Regular expressions
*
*
* Any Java-style regular expression can be used in
* split-path and full-path patterns, with the following restrictions:
*
*
* - A regular expression may not be empty.
*
- A regular expression used in split-path patterns may not contain the
* path separator
/.
* - A regular expression used in full-path patterns may not contain the
* selector set separator
//// .
*
*
*
* Regular expressions that break any of these restrictions would never
* match a topic path, so they make no practical difference.
*
*
*
* Examples
*
* Path expressions
*
* Path | Matches `alpha/beta`? | Matches `alpha/beta/gamma`?
* ------------- | ---------------------- | ---------------------------
* `>alpha/beta` | yes | no
* `alpha/beta` | yes | no
* `>alpha/beta/gamma` | no | yes
* `alpha/beta/gamma` | no | yes
* `>beta` | no | no
* `beta` | no | no
* `>.*``/.*` | no | no
* `>/alpha/beta/` | yes | no
* `/alpha/beta/` | yes | no
*
* Split-path pattern expressions
*
* Path | Matches `alpha/beta`? | Matches `alpha/beta/gamma`?
* ------------- | ---------------------- | ---------------------------
* `?alpha/beta` | yes | no
* `?alpha/beta/gamma` | no | yes
* `?beta` | no | no
* `?.*` | no | no
* `?.*``/.*` | yes | no
* `?alpha/beta/` | no | yes
* `?alpha/beta//` | yes | yes
* `?alpha/.*``//` | yes | yes
*
* Full-path pattern expressions
*
* Path | Matches `alpha/beta`? | Matches `alpha/beta/gamma`?
* ------------- | ---------------------- | ---------------------------
* `*alpha/beta` | yes | no
* `*alpha/beta/gamma` | no | yes
* `*beta` | no | no
* `*.*beta` | yes | no
* `*.*` | yes | yes
* `*alpha/beta/` | no | yes
* `*alpha/beta//` | yes | yes
*
* **Example:**
* ```
* // Simple selector
* var selector = diffusion.selectors.parse(">a/b");
* ```
*
* **Example:**
* ```
* // Creating a selector set
* var selectorSet = diffusion.selectors.parse(">a", ">b");
* ```
*
* @param expression the pattern expression(s). At least one
* valid selector has to be specified.
* @param args additional pattern expressions
* @return the topic selector. If multiple expressions are provided,
* this will return a `SELECTOR_SET` that will match if
* any of the * provided `selectors` match.
* @throws an {@link IllegalArgumentError} if the expression could not be parsed
*/
parse(expression: string | TopicSelector | Array, ...args: Array): TopicSelector;
}
/**
* Provide access to
* {@link UpdateConstraint UpdateConstraint},
* {@link UpdateConstraintFactory UpdateConstraintFactory},
* {@link PartialJSON PartialJSON},
* {@link TopicCreationResult TopicCreationResult}, and
* {@link UpdateStream UpdateStream}.
*
* @module diffusion.topicUpdate
*/
/**
* Promise indicating whether the operation caused a topic to be created or if
* it already existed.
*
* @since 6.2
*/
export declare enum TopicCreationResult {
/**
* A new topic was created.
*/
CREATED = 1,
/**
* A topic with the same specification already exists.
*/
EXISTS = 2
}
export interface TopicUpdateNamespace {
TopicCreationResult: typeof TopicCreationResult;
UpdateConstraintOperator: typeof UpdateConstraintOperator;
}
export declare const TopicUpdateNamespace: TopicUpdateNamespace;
/**
* @module diffusion.topicUpdate
*/
/**
* A constraint to be applied to an update operation or the creation of an
* update stream.
*
* Constraints describe a condition that must be satisfied for an operation to
* succeed. Constraints can be applied to the setting of a value or creation
* of an update stream. Constraints are only evaluated on the server.
*
* The constraints are evaluated using the:
*
* * active session locks
* * existence of the topic
* * current value of the topic
*
* The value of a topic can be described in several ways. The value can be
* described as an exact value, a partial value or an unset value.
*
* Constraints can be composed with one another. It is only possible to
* construct logical ANDs of constraints. Constraints can only be composed if
* the resulting constraint is satisfiable. Multiple session locks can be held
* but a topic can only have a single value. Constraints specifying multiple
* topic values cannot be constructed.
*
* Constraints can be created using a
* {@link UpdateConstraintFactory}, an
* instance of which can be obtained using
* {@link updateConstraints}.
* For example:
*
* ```
* const factory = diffusion.updateConstraints();
* const constraint = factory.locked(lock).and(factory.value(UpdateConstraintOperator.EQ, expectedValue));
* ```
*
* @since 6.2
*/
export interface UpdateConstraint {
/**
* Returns a composed constraint that represents a logical AND of this
* constraint and another.
*
* @param other a constraint that will be logically-ANDed with this constraint
* @return a composed constraint that represents a logical AND of this
* constraint and the `other` constraint
*
* @throws an {@link IllegalArgumentError} if the composed constraint would be
* unsatisfiable
*/
and(other: UpdateConstraint): UpdateConstraint;
/**
* Returns a composed constraint that represents a logical OR of this
* constraint and another.
*
* @param other a constraint that will be logically-ORed with this constraint
* @return a composed constraint that represents a logical OR of this
* constraint and the `other` constraint
*
* @throws an {@link IllegalArgumentError} if the composed constraint would be
* unsatisfiable
*/
or(other: UpdateConstraint): UpdateConstraint;
}
/**
* An operator used in a constraint comparison.
*
* Accessible through `diffusion.topicUpdate.UpdateConstraintOperator`
*
* @since 6.10
*/
export declare enum UpdateConstraintOperator {
/**
* Strict binary equality.
*
* This operator requires that the binary topic value is exactly
* equivalent to the value supplied for comparison.
*/
IS = 1,
/**
* Lenient equals.
*
* This operator requires that the topic value is logically equal to the
* supplied value.
*
* If the supplied value is a string the string representation of the
* specified topic value is compared for string equality.
*
* If the supplied value is a number ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double})
* the corresponding topic value may be a number or a string containing
* a parseable number and will be compared for numeric equality.
*
* If the supplied value is null the condition will be satisfied if the
* value at a specified pointer is JSON null.
*/
EQ = 2,
/**
* Lenient not equals.
*
* This operator requires that the topic value is logically not equal to
* the supplied value.
*
* If the supplied value is a string the string representation of the
* specified topic value is compared for string equality.
*
* If the supplied value is a number ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double})
* the corresponding topic value may be a number or a string containing
* a parseable number and will be compared for numeric equality.
*
* If the supplied value is null the condition will be satisfied if the
* value at a specified pointer not JSON null.
*/
NE = 3,
/**
* Lenient greater than.
*
* This operator requires that the topic value is greater than the
* supplied value.
*
* The supplied value must be a number ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double}).
* The corresponding topic value may be a number or a string containing
* a parseable number and the condition will be satisfied if the topic
* value is greater than the supplied value.
*/
GT = 4,
/**
* Lenient greater than or equals.
*
* This operator requires that the topic value is greater than or equal
* to the supplied value.
*
* The supplied value must be a number ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double}).
* The corresponding topic value may be a number or a string containing
* a parseable number and the condition will be satisfied if the topic
* value is greater than or equal to the supplied value.
*/
GE = 5,
/**
* Lenient less than.
*
* This operator requires that the topic value is less than the supplied
* value.
*
* The supplied value must be a number ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double}).
* The corresponding topic value may be a number or a string containing
* a parseable number and the condition will be satisfied if the topic
* value is less than the supplied value.
*/
LT = 6,
/**
* Lenient less than or equals.
*
* This operator requires that the topic value is less than or equal to
* the supplied value.
*
* The supplied value must be a number ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double}).
* The corresponding topic value may be a number or a string containing
* a parseable number and the condition will be satisfied if the topic
* value is less than or equal to the supplied value.
*/
LE = 7
}
/**
* A constraint requiring the current value of the
* {@link TopicType.JSON JSON} topic to match the partially described value.
*
* The code:
*
* ```
* const factory = diffusion.updateConstraints();
* const constraint = factory.jsonValue().with('/id', idValue).without('/cancellation');
* ```
*
* creates a constraint for a JSON object with a specific ID value and no
* value for a 'cancellation' property.
*
* Missing keys are matched differently to keys that are present with null values.
*
* @since 6.2
*/
export interface PartialJSON extends UpdateConstraint {
/**
* Require a value at a specific position in the JSON object.
*
* This is equivalent to calling {@link PartialJSON.with with(String, Operator, Object)}
* with an operator of {@link UpdateConstraintOperator.IS IS}.
*
* @deprecated since 6.10
*
* Rather use the {@link PartialJSON.with with(String, Operator, Object)}
* method with the {@link UpdateConstraintOperator.IS IS} operator.
*
* @param pointer the pointer expression
* @param value the value
* @param dataType the optional type of the value
* @return a new constraint
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression
* or value cannot be serialised
* @throws a {@link NullValueError} if any of the required arguments are null
*/
with(pointer: string, value: any, dataType?: DataType): PartialJSON;
/**
* Compares a location within the JSON topic value to a specified value.
*
* If there is no value found at the specified pointer position, the
* constraint will be unsatisfied.
*
* If a {@link DataTypes.string String} value is supplied and the operator is
* {@link UpdateConstraintOperator.EQ EQ} or {@link UpdateConstraintOperator.NE NE}, the string
* representation of the topic value at the given pointer will be
* compared to the supplied value. If the value at the pointer position
* is not a string or number the constraint will be unsatisfied. Other
* operators (other than {@link UpdateConstraintOperator.IS IS}) are not permitted with
* String values.
*
* If a number value ({@link DataTypes.int64 Int64} or {@link DataTypes.double Double})
* is supplied the value will be compared with the number value at the
* topic location. This will work with JSON string or number values
* only. JSON strings can only be compared if they contain a value that
* can be parsed as a number. If a string value at the location cannot
* be parsed as a number, the constraint will be unsatisfied. Any of the
* operators (other than {@link UpdateConstraintOperator.IS IS}) can be used with such
* number comparisons. Decimal numbers can be compared with integral
* numbers so {@code 1} is equal to {@code 1.0}, {@code "1"}, or
* {@code "1.0"}.
*
* If a {@code null} value is supplied and the operator is
* {@link UpdateConstraintOperator.EQ EQ} or {@link UpdateConstraintOperator.NE NE}, the topic value at
* the given pointer will be compared to JSON null. Other operators
* (other than {@link UpdateConstraintOperator.IS IS}) are not permitted with a
* {@code null} value.
*
* If a `boolean` value is supplied and the operator is
* {@link UpdateConstraintOperator.EQ EQ}, the topic value at the given pointer will be
* compared to the boolean value. Other operators are not permitted with
* a boolean value.
*
* If the {@link UpdateConstraintOperator.IS IS} operator is specified the supplied
* value will be compared to the topic value for strict binary equality.
* In this case the value must be of type {@link DataTypes.string String},
* {@link DataTypes.int64 Int64}, {@link DataTypes.double Double}, {@link Bytes}, or
* {@code null}. This is slightly more efficient than the lenient
* comparisons described above.
*
* @param pointer a JSON
* Pointer specifying the location of the {@code value} in
* the JSON object.
*
* @param value the value
* @param operator the operator that determines the type of comparison
* @return a new constraint
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression,
* the value cannot be serialised or the operator is invalid for the value type
* @throws a {@link NullValueError} if any of the required arguments are null
*
* @since 6.10
*/
with(pointer: string, value: any, operator: UpdateConstraintOperator, dataType?: DataType): PartialJSON;
/**
* Require a specific position in the JSON object to be empty.
*
* The `pointer` is a
* JSON Pointer syntax
* reference that should have no value in the JSON object. If the
* `pointer` parameter cannot be parsed as a JSON pointer an
* `Error` is thrown.
*
* The function returns a new {@link PartialJSON PartialJSON}
* object. The original object remains unmodified.
*
* @param pointer the pointer expression
* @return a new constraint
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression
* @throws a {@link NullValueError} if the pointer argument is null
*/
without(pointer: string): PartialJSON;
}
/**
* Factory for the constraint types.
*
* An instance can be obtained by calling {@link updateConstraints
* diffusion.updateConstraints()}.
*
* @since 6.2
*/
export interface UpdateConstraintFactory {
/**
* Create a constraint requiring a lock to be held by the session.
*
* This can be used to coordinate operations between multiple
* sessions.
*
* @param lock the lock
* @return the constraint
*/
locked(lock: SessionLock): UpdateConstraint;
/**
* Create a constraint requiring the current value of the topic to exactly
* match the supplied value.
*
* This is exactly equivalent to calling
* {@link UpdateConstraintFactory.value value(UpdateConstraint.Operator, Object)} specifying the
* {@link UpdateConstraintOperator.IS IS} operator.
*
* @param value the value
* @param dataType the optional type of the values
* @return the constraint
* @throws an {@link IllegalArgumentError} if the value cannot be serialised
* @throws a {@link NullValueError} if the value argument is null
*/
value(value: any, dataType?: DataType): UpdateConstraint;
/**
* Create a constraint comparing the current value of a topic to a
* supplied value.
*
* If a {@link DataTypes.string String} value is supplied and the operator is
* {@link UpdateConstraintOperator.EQ EQ} or
* {@link UpdateConstraintOperator.NE NE}, the string representation of
* the topic will be compared to the supplied value. This can only be
* used with primitive topic types (or {@link TopicType.TIME_SERIES
* TIME_SERIES} topics with a primitive event type). Other operators
* (other than {@link UpdateConstraintOperator.IS IS}) are not
* permitted with String values.
*
* If a number value is supplied ({@link DataTypes.int64 Int64} or
* {@link DataTypes.double Double}) the value will be compared with the number value of
* the topic. This will work with {@link TopicType.STRING STRING},
* {@link TopicType.INT64 INT64} or {@link TopicType.DOUBLE DOUBLE}
* topics (or {@link TopicType.TIME_SERIES TIME_SERIES} topics with a
* primitive event type) only. {@link TopicType.STRING STRING} topics
* can only be compared if they contain a value that can be parsed as a
* number. If the value of a {@link TopicType.STRING STRING} topic
* cannot be parsed as a number, or the topic is of any other non-number
* type the constraint will be unsatisfied. Any of the operators (other
* than {@link UpdateConstraintOperator.IS IS}) can be used with such
* number comparisons. Decimal numbers can be compared with integral
* numbers so {@code 1} is equal to {@code 1.0}, {@code "1"}, or
* {@code "1.0"}.
*
* If the {@link UpdateConstraintOperator.IS IS} operator is specified
* the specified value will be compared to the topic value for strict
* binary equality. The value type can be any value type supported by
* {@link DataTypes} or any {@link Bytes} value and can be used to compare
* against any topic type.
*
* When a {@link TopicType.STRING STRING}, {@link TopicType.INT64 INT64}
* or {@link TopicType.DOUBLE DOUBLE} topic is updated to a {@code null}
* value, the topic is set to have no value. Use the {@link UpdateConstraintFactory.noValue noValue()}
* constraint to check if the topic has no value.
*
* This constraint is useful when changing the value of a topic. This
* constraint is unsatisfied if no topic is present at the path, making
* it unsuitable for operations that try to add topics.
*
* @param operator the operator that determines the type of comparison
*
* @param value the value
*
* @return the constraint
* @throws an {@link IllegalArgumentError} if the value cannot be serialised or the operator is invalid
* for the value type
* @throws a {@link NullValueError} if any of the required arguments are null
*
* @since 6.10
*/
value(operator: UpdateConstraintOperator, value: any, dataType?: DataType): UpdateConstraint;
/**
* Create a constraint requiring the topic to have no value.
*
* This is useful when setting the first value of a topic. This
* constraint is unsatisfied if no topic is present at the path, making
* it unsuitable for operations that try to add topics.
*
* @return the constraint
*/
noValue(): UpdateConstraint;
/**
* Create a constraint requiring the path to have no topic.
*
* This is useful when setting the first value of a topic being added using
* an {@link UpdateStream} without changing the value if the topic already
* exists. This constraint is unsatisfied if a topic is present at the path,
* making it unsuitable for operations that try to set topics without adding
* them.
*
* @return the constraint
*/
noTopic(): UpdateConstraint;
/**
* Create a constraint that partially matches the current topic value.
*
* The topic must be a {@link TopicType.JSON JSON} topic (or a
* {@link TopicType.TIME_SERIES TIME_SERIES} topic with a json event
* type). The {@link PartialJSON} partially describes the structure of a
* {@link JSON} value. The
* {@link PartialJSON.with with} or {@link PartialJSON.without without} methods must be used to
* fully qualify the constraint.
*
* This constraint is useful when changing the value of a topic. The
* constraint is unsatisfied if no topic is present at the path, making
* it unsuitable for operations that try to add topics.
*
* @return {diffusion.topicUpdate.PartialJSON} the constraint
*/
jsonValue(): PartialJSON;
}
/**
* @module diffusion.topicUpdate
*/
/**
* An update stream provides a method for updating a specific topic.
*
* An update stream is associated with a specific topic. The type of the topic
* must match the type of values passed to the update stream. It can be created
* with an optional {@link UpdateConstraint constraint}.
* The existence of the topic, its type and the constraint are validated lazily
* by the first {@link set} or {@link validate} operation. Subsequent operations
* issued before the first operation completes will be deferred until the
* completion of the first operation.
*
* An update stream can be used to send any number of updates. It sends a
* sequence of updates for a specific topic to the server. If supported by the
* data type, updates will be sent to the server as a stream of binary deltas.
* An update stream does not prevent other sessions from updating the topic. If
* exclusive access is required update streams should be used with
* {@link SessionLock session locks} as constraints.
*
* Once validated an update stream can be invalidated. An invalidated
* update stream rejects the operations applied to it. The update stream
* will be invalidated if:
*
* * the topic is removed
* * another update stream is created for the same topic
* * the topic is updated to a new value by anything other than the stream
* * the session does not have the
* {@link PathPermission.UPDATE_TOPIC update permission}
* * an operation fails because of cluster repartitioning
*
* UpdateStreams are created using the {@link TopicUpdate} feature.
*
* @since 6.2
*/
export interface UpdateStream {
/**
* Sets the topic to a specified value.
*
* `null` or `undefined` can only be passed to the
* `value` parameter when updating {@link TopicType.STRING string},
* {@link TopicType.INT64 int64} or {@link TopicType.DOUBLE double} topics.
*
* When a topic of type {@link TopicType.STRING string},
* {@link TopicType.INT64 int64} or {@link TopicType.DOUBLE double} is set
* to `null` or `undefined` , the topic will be updated
* to have no value. If a previous value was present subscribers will
* receive a notification that the new value is `undefined` . New
* subscribers will not receive a value notification.
*
* If this method fails once, all subsequent calls to {@link UpdateStream.set} or
* {@link UpdateStream.validate} will also fail.
*
* @param value the value. Update streams for string, int64, and double
* topics accept `null` or `undefined`, as described above.
* Using null with other topic types is an error and will
* result in an `Error` .
* @return a Promise that completes when a response is received from the
* server.
*
* The first set operation will return a {@link
* TopicCreationResult} indicating whether a new topic was created
* or it already exists.
*
* If the task fails, the Promise will resolve with an
* `Error` .
*/
set(value: any): Promise;
/**
* Return the latest value of the topic set using this update stream.
*
* The returned value reflects the last value that has been set, before it
* is sent to the server.
*
* If the server rejects a set operation, the topic value will not change
* and this update stream will be invalidated.
*
* This method will throw an `Error` if called before the first
* call to {@link set}
*
* @return the cached value of the topic
*/
get(): any;
/**
* Validates the update stream.
*
* Update streams are validated lazily when {@link set setting the value}.
* This method allows the stream to be validated before a value needs to be
* set.
*
* If the update stream has not been validated yet, calling this method
* checks the topic exists, the topic type is correct, the constraint is
* satisfied and the session has permission to update the topic. Once
* it has been validated calling this method checks the topic has not been
* removed, no other stream has been created for the topic, the value
* of the topic has not been changed by anything else and the session
* still has permission to update the topic. If validation fails, the Promise
* will resolve with an `Error`.
*
* If this method fails all subsequent calls to {@link set} or
* {@link validate} will resolve with an `Error`.
*
* @return a Promise that completes when a response is received from the server.
*/
validate(): Promise;
}
/**
* An extension to {@link UpdateStream} that includes recovery functionality.
*
* A recoverable update stream wraps an {@link UpdateStream}, tracking topic
* updates and associated Promisess.
*
* In the event that a {@link RecoverableUpdateStream} returns a Promise
* that rejects, calling {@link RecoverableUpdateStream.isRecoverable}
* returns `true` recovery is possible.
*
* Call {@link RecoverableUpdateStream.recover} to re-establish the update
* stream and re-play incomplete topic updates before resuming.
*
* Construct a RecoverableUpdateStream by passing a {@link RetryStrategy} to
* {@link UpdateStreamBuilder.build}
*
* Example feature use
*
* This example demonstrates use of a RecoverableUpdateStream to update topic
* my/topic with 1000 unique values, after which it checks for
* failure in any of them. If any topic updates complete exceptionally and the
* exception is recoverable, the code recovers - reestablishing an UpdateStream
* and delivering the failed topic updates.
*
*
* const topicSpec = new TopicSpecification(TopicType.STRING);
*
* const updateStream =
* session.topics
* .newUpdateStreamBuilder()
* .specification(topicSpec)
* .build(
* 'my/topic',
* datatypes.string(),
* { interval: 1000, attempts: 10 }
* );
*
* const promises = [ ...Array(1000).keys() ]
* .map((i) => updateStream.set(`Value of ${i}`));
*
* try {
* await Promise.all(promises);
* } catch (err) {
* if (updateStream.isRecoverable()) {
* updateStream.recover();
* } else {
* console.error("Cannot recover", err);
* }
* }
*
*
* @since 6.10
*/
export interface RecoverableUpdateStream extends UpdateStream {
/**
* Check if recovery is possible following an rejected Promise returned from
* {@link RecoverableUpdateStream}.
*
* Must be used prior to calling {@link RecoverableUpdateStream.recover}.
*
* @return true if recovery is possible.
*/
isRecoverable(): boolean;
/**
* Reestablish the inner recovery stream. Deliver pending topic updates.
*
* If recoverable exceptions occur during recovery then pause and retry,
* where the pause duration and the maximum number of retries is governed by
* the {@link RetryStrategy} supplied to builder function
* {@link UpdateStreamBuilder.build}.
*
* If non-recoverable errors occur during recovery then recovery is aborted.
*
* If recovery fails for any reason then further recovery attempts will fail.
*
* @throws an Error if recovery is not possible with the limits of the retry strategy.
*/
recover(): Promise;
}
/**
* Builder for {@link UpdateStream update stream} to use for updating a
* specific topic. A builder is created using
* {@link TopicUpdate.newUpdateStreamBuilder}.
*
* The type of the topic being updated must match the type derived from the
* {@code dataType} parameter.
*
* @since 6.9
*/
export interface UpdateStreamBuilder {
/**
* Specifies a TopicSpecification for this update stream.
*
* If a topic does not exist at the {@code path} one will be created using
* the {@code topicSpecification} when the update stream is validated. If a
* topic does exist, its specification must match {@code topicSpecification},
* otherwise the operation will fail with an error.
*
* Specification is undefined by default. Calling this method with a null or undefined parameter
* removes the specification for this builder.
*
* @param topicSpecification the required specification of the topic
* @return this builder
*/
specification(topicSpecification?: TopicSpecification | TopicType): UpdateStreamBuilder;
/**
* Specifies an update constraint for this update stream.
*
* Constraints can be created using {@link updateConstraints}}.
*
* Constraints can be applied to the setting of a value and creation of an
* update stream. Constraints describe a condition that must be satisfied for
* the operation to succeed. The constraints are evaluated on the server. The
* available constraints are: an active session lock, the absence of a topic,
* the current value of the topic being updated, and a part of the current
* value of the topic being updated.
*
* Constraint is Unconstrained by default. Calling this method with a null or undefined parameter
* resets the constraint for this builder.
*
* @param updateConstraint the constraint that must be satisfied for the update
* stream to be validated
* @return this builder
*/
constraint(updateConstraint: UpdateConstraint): UpdateStreamBuilder;
/**
* Specifies if delta compression should be disabled for this update stream.
*
* This is {@code false} by default, i.e. delta compression is enabled.
*
* Disabling delta compression can reduce the CPU workload at the client
* at the cost of increased bandwidth and possible additional CPU load on
* the server (if the topic publishes deltas). This may be particularly
* useful for topics that have PUBLISH_VALUES_ONLY set.
*
* @param suppressDeltas the boolean value to set the suppression of delta compression.
* @return this builder
* @since 6.11
*/
suppressDeltas(suppressDeltas: boolean): UpdateStreamBuilder;
/**
* Resets the builder to its default parameters.
*
* @return this builder
*/
reset(): UpdateStreamBuilder;
/**
* Creates an {@link UpdateStream} to use for updating a
* specific topic.
*
* The type of the topic being updated must match the type derived from the
* {@code dataType} parameter.
*
* Update streams send a sequence of updates for a specific topic. The
* updates may be delivered to the server as binary deltas. They do not
* provide exclusive access to the topic. If exclusive access is required
* update streams should be used with
* {@link SessionLock session locks} as constraints.
*
* Streams are validated lazily when the first {@link UpdateStream.set} or
* {@link UpdateStream.validate} operation is completed. Once validated a
* stream can be invalidated, after which it rejects future
* updates.
*
* Takes an optional retry strategy that governs recovery attempts following a
* recoverable exception.
*
* @param path the path of the topic
* @param dataType the type of the values expected by the update stream
*
* @return an update stream
* @throws a {@link NullValueError} if the path or dataType is null or undefined
*/
build(path: string, dataType: DataType): UpdateStream;
/**
* Creates a {@link RecoverableUpdateStream} to use for updating a
* specific topic.
*
* Takes a retry strategy that governs recovery attempts following a
* recoverable exception.
*
* In other respects this method works in the same way as calling
* {@link UpdateStreamBuilder.build} without retry strategy.
*
* @param path the path of the topic
* @param dataType the type of the values expected by the update stream
* @param retryStrategy an optional retry strategy
*
* @return a recoverable update stream
* @throws a {@link NullValueError} if any of the required arguments null or undefined
*/
build(path: string, dataType: DataType, retryStrategy?: RetryStrategy): RecoverableUpdateStream;
}
/**
* @module diffusion.topics
*/
///
/**
* A parameterised query that can be used to search the topic tree.
*
* A new request can be created using the {@link Session.fetchRequest fetchRequest}
* method and modified to specify a range of topics and/or
* various levels of detail. The request can then be issued to the server
* using the {@link FetchRequest.fetch fetch} method
* supplying a topic selector which specifies the selection of topics.
* The results are returned via a {@link Promise}.
*
* As a minimum, the path and type of each selected topic will be returned.
* It is also possible to request that the topic {@link withValues values}
* and/or {@link withProperties properties} are returned.
*
* If values are selected then the topic types selected are naturally
* constrained by the provided `dataType` argument. So if
* {@link DataTypes.string} is specified, only {@link TopicType.STRING
* STRING} topics will be selected. However, if {@link DataTypes.json} is
* specified, all types compatible with {@link JSON} will be selected
* including {@link TopicType.STRING STRING}, {@link TopicType.INT64 INT64}
* and {@link TopicType.DOUBLE DOUBLE}. See
* {@link DataType.canReadAs} for the class hierarchy of types.
*
* To select topic types when
* values are not required, or to further constrain the selection when
* values are required, it is also possible to specify exactly which
* {@link TopicType topic types} to select.
*
* The topics selected by the topic selector can be further restricted by
* range. A range is defined by a start path and an end path, and contains
* all paths in-between in path order. Given a topic tree containing the
* topics:
*
* ```
* a, a/b, a/c, a/c/x, a/c/y, a/d, a/e, b, b/a/x, b/b/x, c
* ```
*
* The range from `a/c/y` to `b/a/x` includes the topics with paths:
*
* ```
* a/c/x, a/c/y, a/d, a/e, b, b/a/x
* ```
*
* The start point of a range can be specified using {@link from} or
* {@link after} and an end point using {@link to} or
* {@link before}. {@link from} and {@link to} include any
* topic with the specified path in the selection, whereas {@link after}
* and {@link before} are non-inclusive and useful for paging
* through a potentially large range of topics. If no start point is
* specified, the start point is assumed to be the first topic of the topic
* tree, ordered by path name. Similarly, if no end point is specified, the
* end point is the last topic of the topic tree.
*
* A limit on the number of results returned can be specified using
* {@link first}. This is advisable if the result set could
* potentially be large. The number of results returned is also limited by
* the session's maximum message size – see {@link maximumResultSize}. The
* result indicates whether the results have been limited via the
* {@link FetchResult.hasMore hasMore} method. If `hasMore()`
* returns `true`, further results can be retrieved by modifying the original
* query to request results {@link after} the last path received.
*
* By default, results are returned in path order, earliest path first,
* starting from the beginning of any range specified. It is also possible
* to request results from the end of the range indicated by specifying a
* limit to the number of results using {@link last}. This method
* complements {@link first}, returning up to the specified number of
* results from the end of the range, but in reverse path order. This is
* useful for paging backwards through a range of topics.
*
* It can be useful to explore an unknown topic tree in a breadth-first
* manner rather than the path order. This can be achieved using
* {@link limitDeepBranches}.
*
* FetchRequest instances are immutable and can be safely shared and reused.
*
* @since 6.2
*/
export declare abstract class FetchRequest {
/**
* Specifies a logical start point within the topic tree.
*
* If specified, only results for topics with a path that is lexically equal
* to or 'after' the specified path will be returned.
*
* This is the inclusive equivalent of {@link after} and if used will
* override any previous {@link after} or {@link from}
* constraint.
*
* @param topicPath the topic path from which results are to be returned
*
* @return a new fetch request derived from this fetch request but
* selecting only topics from the specified path onwards
* (inclusive)
*/
abstract from(topicPath: string): FetchRequest;
/**
* Specifies a logical start point within the topic tree.
*
* If specified, only results for topics with a path that is lexically
* 'after' the specified path will be returned.
*
* This is the non inclusive equivalent of {@link from} and if used
* will override any previous {@link from} or {@link after}
* constraint.
*
* @param topicPath the topic path after which results are to be returned
* @return a new fetch request derived from this fetch
* request but selecting only topics after the specified path (not
* inclusive)
*/
abstract after(topicPath: string): FetchRequest;
/**
* Specifies a logical end point within the topic tree.
*
* If specified, only results for topics with a path that is lexically equal
* to or 'before' the specified path will be returned.
*
* This is the inclusive equivalent of {@link before} and if used
* will override any previous {@link before} or {@link to}
* constraint.
*
* @param topicPath the topic path to which results are to be returned
* @return a new fetch request derived from this fetch request but
* selecting only topics including and before the specified path
* (inclusive)
*/
abstract to(topicPath: string): FetchRequest;
/**
* Specifies a logical end point within the topic tree.
*
* If specified, only results for topics with a path that is lexically
* 'before' the specified path will be returned.
*
* This is the non inclusive equivalent of {@link to} and if used
* will override any previous {@link to } or {@link before}
* constraint.
*
* @param topicPath the topic path before which results are to be
* returned
*
* @return a new fetch request derived from this fetch
* request but selecting only topics before the specified path (not
* inclusive)
*/
abstract before(topicPath: string): FetchRequest;
/**
* Specifies that only topics of the specified topic types should be
* returned.
*
* If this is not specified, {@link getAllTypes all
* types} will be returned (unless constrained by {@link withValues}).
*
* This may be used instead to further constrain the results when using
* {@link withValues}. For example, you can specify
* {diffusion.datatypes.DataType.json} to {@link withValues} then specify
* {@link TopicType.JSON JSON} here to ensure that only
* JSON topics are returned and not those topics that are logically value
* subtypes of JSON (e.g. {@link TopicType.STRING STRING}).
*
* If {@link withValues} has been specified then the types specified here
* must be compatible with the value class specified.
*
* @param topicTypes topic types to be selected
*
* @return a new fetch request derived from this fetch request but
* specifying that only topics of the specified topic types should
* be returned.
*
* @throws an {@link IllegalArgumentError} if invalid topic types are specified
*/
abstract topicTypes(topicTypes: TopicType[] | Set): FetchRequest;
/**
* Specifies that values should be returned for selected topics,
* constraining the selection to only those topics with a data type
* compatible with the specified {@link DataType
* DataType}.
*
* The specified value constrains the topic types. So, any topic types
* specified in a previous call to {@link topicTypes} that
* cannot be read as the specified class will be removed from the list
* of topic types.
*
* @param dataType the type of values. If no value is specified this will
* cancel any previous call (topic types will remain
* unchanged).
*
* @return a new fetch request derived from this fetch
* request but specifying that only topics compatible with the
* specified class should be returned with values.
*
* @throws an {@link IllegalArgumentError} if the data type is not compatible with any
* topic types.
*/
abstract withValues(dataType?: DataType | AnyDataType): FetchRequest;
/**
* Specifies that all properties associated with each topic's {@link
* TopicSpecification specification} should be returned.
*
* @return a new fetch request derived from this fetch request but
* specifying that topic specification properties should be
* returned.
*/
abstract withProperties(): FetchRequest;
/**
* Specifies that topic sizes should be returned.
*
* For time series topics this will fetch the size (in bytes) of
* the last event, the number of events, and the total size of all events.
*
* For all other topics this will fetch the size (in bytes) of the
* topic value, or 0 if the topic has no value.
*
* @return a new fetch request derived from this fetch request but
* specifying that topic sizes should be returned.
*
* @since 6.11
*/
abstract withSizes(): FetchRequest;
/**
* Specifies a maximum number of topic results to be returned from the start
* of the required range.
*
* If this is not specified, the number of results returned will only be
* limited by other constraints of the request.
*
* This should be used to retrieve results in manageable batches and prevent
* very large result sets.
*
* If there are potentially more results that would satisfy the other
* constraints then the fetch result will indicate so via the {@link
* FetchResult.hasMore hasMore} method.
*
* If the count is set to zero, no results will be returned. In this case,
* {@link FetchResult.hasMore hasMore} can be used to check the existence of
* any topics matching the criteria without retrieving topic details.
*
* Either this or {@link last} may be specified. This will therefore
* override any previous {@link last} or {@link first}
* constraint.
*
* @param count the non-negative maximum number of results to return from the
* start of the range
*
* @return a new fetch request derived from this fetch
* request but selecting only the number of topics specified from
* the start of the range
*
* @throws an {@link IllegalArgumentError} if the count is negative
*/
abstract first(count: number): FetchRequest;
/**
* Specifies a maximum number of topic results to be returned from the end
* of the required range.
*
* This is similar to {@link first} except that the specified number
* of results are returned from the end of the range. This is useful for
* paging backwards through a range of topics. Results are always returned
* in topic path order (not reverse order).
*
* Either this or {@link first} may be specified. This will therefore
* override any previous {@link first} or {@link last}
* constraint.
*
* @param count the non-negative maximum number of results to return from the
* end of the range
*
* @return a new fetch request derived from this fetch
* request but selecting only the number of topics specified from
* the end of the range
*
* @throws an {@link IllegalArgumentError} if the count is negative
*/
abstract last(count: number): FetchRequest;
/**
* Specifies the maximum data size of the result set.
*
* This may be used to constrain the size of the result. If not specified
* then by default the maximum message size for the session (as specified by
* {@link Options.maxMessageSize} is used.
*
* @param maximumSize the maximum size of the result set in bytes.
* If a value greater than the session's maximum message
* size is specified, the maximum message size will be
* used.
*
* @return a new fetch request derived from this fetch
* request but constraining the size of the result to the specified
* maximum
*
* @throws an {@link IllegalArgumentError} if the maximum size is negative
*/
abstract maximumResultSize(maximumSize: number): FetchRequest;
/**
* Specifies a limit on the number of results returned for each deep
* branch.
*
* A deep branch has a root path that has a number of parts equal to the
* `deepBranchDepth` parameter. The `deepBranchLimit`
* specifies the maximum number of results for each deep branch.
*
* This method is particularly useful for incrementally exploring a
* topic tree from the root, allowing a breadth-first search strategy.
*
* For example, given a topic tree containing the topics with the
* following paths:
*
* ```
* x/0
* x/x/1
* x/x/x/2
* y/y/y/y/3
* y/y/y/4
* z/5
* z/z/6
* ```
*
* Then
*
* ```
* session.fetchRequest().limitDeepBranches(1, 1).fetch("?.//");
* ```
*
* will return results with the paths `x/0`, `y/y/y/y/3`,
* and `z/5`. The application can then determine the roots of the
* tree are `x`, `y`, and `z`.
*
* The `deepBranchLimit` parameter can usefully be set to
* `0`. For example, given the same example topic tree,
*
* ```
* session.fetchRequest().limitDeepBranches(3, 0).fetch("?.//");
* ```
*
* will only return results having paths with fewer than three parts;
* namely `x/0`, and `z/5`.
*
* The fetch result does not indicate whether this option caused some
* results to be filtered from deep branches. It has no affect on the
* {@link FetchResult.hasMore hasMore()} result. If the result set
* contains `deepBranchLimit` results for a particular deep
* branch, some topics from that branch may have been filtered.
*
* @param deepBranchDepth the number of parts in the root path of a
* branch for it to be considered deep
* @param deepBranchLimit the maximum number of results to return for
* each deep branch
* @return a new fetch request derived from this fetch request but
* restricting the number of results for deep branches
* @throws an {@link IllegalArgumentError} if either parameter is negative
*
* @since 6.4
*/
abstract limitDeepBranches(deepBranchDepth: number, deepBranchLimit: number): FetchRequest;
/**
* Include the details of reference topics that are not yet published.
*
* {@link TopicViews Topic views} that use the `delay by` clause
* create reference topics in an unpublished state. The topics are
* published once the delay time has expired. A topic in the
* unpublished state prevents a lower priority topic view from creating
* a reference topic with the same path.
*
* A reference topic in the unpublished state which matches the query
* will only be included in the fetch results if the session has
* {@link PathPermission.READ_TOPIC READ_TOPIC} permission for the
* reference's source topic as well as `READ_TOPIC` permission for
* the reference topic. Requiring `READ_TOPIC` permission for the
* source topic ensures less privileged sessions cannot derive
* information from the existence of the reference topic before the
* delay time has expired.
*
* @return a new fetch request derived from this fetch request,
* additionally specifying that unpublished reference topics
* should be included in the results
* @since 6.5
*/
abstract withUnpublishedDelayedTopics(): FetchRequest;
/**
* Sends a fetch request to the server.
*
* Results are returned for all topics matching the selector that satisfy
* the request constraints within any range defined by {@link from}/{@link
* after} and/or {@link to}/{@link before}.
*
* This function can take any number of arguments. Each argument can be a string
* or a {@link TopicSelector}. Alternatively, an array of strings and
* {@link TopicSelector}s can be passed as a single argument. At least one
* valid selector has to be specified.
*
* @param topics specifies a topic selector which selects the topics to be
* fetched
*
* @return a Promise that resolves with a {@link FetchResult
* FetchResult} when a response is received from the server with
* the results of the fetch operation.
*
* If the task completes successfully, the FetchResult returned by
* the Promise will be an object encapsulating all of the results.
*
* Otherwise, the Promise will resolve with an Error. Common reasons for
* failure, listed by the error type, include:
*
* - {@link InvalidDataError} – if topic values were returned but could not
* be read.
*
*
* @throws an {@link IllegalArgumentError} if the selector could not be parsed
*/
abstract fetch(topics: Array): Promise>;
abstract fetch(...topics: Array): Promise>;
/**
* Return a set of all topic types that can be fetched.
*
* @returns the topic types that can be fetched by a FetchRequest
*/
static getAllTypes(): Set;
}
/**
* Encapsulates the results from a fetch operation issued to the server.
*
* A fetch operation is issued using a {@link FetchRequest
* fetch request} which will return a result of this type via a {@link Promise}.
*
* @param V the result value type. This will be any type unless the request
* indicated that {@link FetchRequest.withValues
* values} are to be returned, in which case this will be the data
* type requested.
*
* @since 6.2
*/
export interface FetchResult {
/**
* Returns the results from the fetch operation.
*
* Results are always returned in path order.
*
* @return a list of {@link TopicResult TopicResult}s,
* each representing a result single topic selected by the fetch
* operation.
*/
results(): Array>;
/**
* Indicates whether the fetch could have returned more results if it had not
* been constrained by the {@link FetchRequest.first first}, {@link
* FetchRequest.last last} or {@link FetchRequest.maximumResultSize
* maximumResultSize}
* limits.
*
* @return `true` if more results could have been returned,
* otherwise false
*/
hasMore(): boolean;
/**
* The number of elements in the fetch result.
*
* @return the size of the results list
* @since 6.3
*/
size(): number;
/**
* Returns `true` if the result contains zero elements.
*
* @return true if result list is empty
* @since 6.3
*/
isEmpty(): boolean;
}
/**
* Encapsulates the result of a {@link FetchRequest.fetch
* fetch} invocation for a single selected topic.
*
* @param V the result value type. This will be any type unless the request
* indicated that {@link FetchRequest.withValues values}
* are to be returned, in which case this will be the data type
* requested.
*
* @since 6.2
*/
export interface TopicResult {
/**
* Returns the topic path.
*
* @return the topic path
*/
path(): string;
/**
* Returns the topic type.
*
* @return the topic type
*/
type(): TopicType;
/**
* Returns the topic value.
*
* This will only return a value if the fetch request specified {@link
* FetchRequest.withValues withValues} and the topic actually had a value.
* For topics that have no value this will return undefined.
*
* @return the topic value or undefined if none available
*/
value(): V;
/**
* Returns the topic specification.
*
* If the request specified {@link FetchRequest.withProperties
* withProperties}, the result reflect the topic's specification and can be
* used to create an identical topic. If the request did not specify {@link
* FetchRequest.withProperties withProperties}, the specification's property
* map will be empty.
*
* @return {TopicSpecification} the topic specification
*/
specification(): TopicSpecification;
/**
* Returns the size of the topic’s value (in bytes) or 0 if the topic
* has no value.
*
* For time series topics this will be the size of the last event.
*
* @return the value size
*/
valueSize(): number;
/**
* Returns the number of values that the topic has. For a topic with no
* value this will return 0.
*
* For a non times series topic with a value this will return 1. For a
* time series topic this will return the number of events.
*
* @return the value count
*/
valueCount(): number;
/**
* Return the total value size of a topic.
*
* For a non time series topic this will be the same as `valueSize()`.
* For a time series topic this will be the total size of all events (in bytes).
*/
valueTotalSize(): Long;
}
/**
* Topic selector type.
*/
export declare enum TopicSelectionType {
/**
* Represents selection of topics (i.e. subscription).
*/
SELECT = 0,
/**
* Represents deselection of topics (i.e. unsubscription).
*/
DESELECT = 1
}
/**
* A topic selection that represents either a subscription (selection) or an
* unsubscription (deselection).
*
* @since 6.12
*/
export interface TopicSelection {
/**
* The topic selector
*/
readonly selector: TopicSelector;
/**
* The selection type
*/
readonly selectionType: TopicSelectionType;
}
/**
* @module diffusion.topics
*/
/**
* Topic specifications provide the information required to create a topic.
* Topics can be created from a topic specification using
* {@link TopicControl.add}.
*
* Topic specifications allow an application to introspect the type and
* capabilities of a topic. Topic specifications are provided to
* {@link ValueStream ValueStreams} and {@link TopicNotificationListener topic
* notification listeners}.
*
* A topic is specified in terms of its {@link TopicType type}
* and a map of optional property settings which can alter the default behavior
* of the topic.
*
* A topic specification has a {@link TopicType topic type} and a map of property settings
* which define the behavior of the topic. A default topic specification for a topic
* type can be created using `new diffusion.topics.TopicSpecification(TopicType)`. Topic
* specifications with different properties can be derived from a default instance
* using the {@link TopicSpecification.withProperties} and
* {@link TopicSpecification.withProperty} builder methods.
*
* Topic Properties
*
* Depending on the topic type, some properties must be included in the
* specification when creating a topic and some properties have no effect. All
* topic specification property values must be supplied as strings.
*
* The required and optional properties for each topic type are set out in the following table.
* Properties unsupported by the topic type are ignored.
*
*
*
* |
* Default when optional |
* {@link TopicType.STRING STRING}
* {@link TopicType.JSON JSON}
* {@link TopicType.BINARY BINARY}
* |
* {@link TopicType.DOUBLE DOUBLE}
* {@link TopicType.INT64 INT64} |
* {@link TopicType.RECORD_V2 RECORD_V2} |
* {@link TopicType.TIME_SERIES TIME_SERIES} |
*
*
* | {@link TopicSpecification.COMPRESSION COMPRESSION} |
* low |
* Optional |
* - |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.CONFLATION CONFLATION} |
* conflate |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.DONT_RETAIN_VALUE DONT_RETAIN_VALUE} |
* false |
* Optional |
* Optional |
* Optional |
* - |
*
*
* | {@link TopicSpecification.OWNER OWNER} |
* |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.PERSISTENT PERSISTENT} |
* true |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.PRIORITY PRIORITY} |
* default |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.PUBLISH_VALUES_ONLY PUBLISH_VALUES_ONLY} |
* false |
* Optional |
* - |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.REMOVAL REMOVAL} |
* |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.SCHEMA SCHEMA} |
* |
* - |
* - |
* Optional |
* - |
*
*
* | {@link TopicSpecification.TIDY_ON_UNSUBSCRIBE TIDY_ON_UNSUBSCRIBE} |
* false |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
* | {@link TopicSpecification.TIME_SERIES_EVENT_VALUE_TYPE TIME_SERIES_EVENT_VALUE_TYPE} |
* |
* - |
* - |
* - |
* Required |
*
*
* | {@link TopicSpecification.TIME_SERIES_RETAINED_RANGE TIME_SERIES_RETAINED_RANGE} |
* limit 10 |
* - |
* - |
* - |
* Optional |
*
*
* | {@link TopicSpecification.TIME_SERIES_SUBSCRIPTION_RANGE TIME_SERIES_SUBSCRIPTION_RANGE} |
* as documented |
* - |
* - |
* - |
* Optional |
*
*
* | {@link TopicSpecification.VALIDATE_VALUES VALIDATE_VALUES} |
* false |
* Optional |
* Optional |
* Optional |
* Optional |
*
*
*
* `TIME_SERIES` topics have restricted values for the
* `CONFLATION` property. They are only allowed to have the values
* `off` or `unsubscribe`.
*/
export declare class TopicSpecification {
/**
* Key of the topic property that specifies whether a topic should publish
* only values.
*
* By default, a topic that supports delta streams will publish the
* difference between two values (a delta) when doing so is more efficient
* than publishing the complete new value. Subscribing sessions can use a
* {@link ValueStream} to automatically apply the delta to a local copy of
* the topic value to calculate the new value.
*
* Setting PUBLISH_VALUES_ONLY to `true` disables this behavior so that
* deltas are never published. Doing so is usually not recommended because
* it will result in more data being transmitted, less efficient use of
* network resources, and increased transmission latency. On the other hand,
* calculating deltas can require significant CPU from the server or, if
* update streams are used, from the updating client. The CPU cost will be
* higher if there are many differences between successive values, in which
* case delta streams confer fewer benefits. If successive values are
* unrelated to each other, consider setting PUBLISH_VALUES_ONLY to `true`.
* Also consider setting PUBLISH_VALUES_ONLY to `true` if the network
* capacity is high and the bandwidth savings of deltas are not required.
*
* @see {@link TopicSpecification.DONT_RETAIN_VALUE}
*/
static readonly PUBLISH_VALUES_ONLY = "PUBLISH_VALUES_ONLY";
/**
* Key of the topic property that specifies whether a topic should validate
* inbound values.
*
* By default, the server does not validate received values before sending
* them on to client sessions. Invalid or corrupt values will be stored in
* the topic and passed on to sessions. If this property is set to `true`,
* the server will perform additional validation on values to check that
* they are valid instances of the data type, and if it is not then it will
* return an error to the updater and not update the topic.
*
* If this value is not set (or set to something other than `true`), no
* server validation of inbound values is performed. This is the recommended
* setting as there is a performance overhead to validation and values
* produced through the {@link DataTypes data type} API will not
* be invalid anyway.
*/
static readonly VALIDATE_VALUES = "VALIDATE_VALUES";
/**
* Key of the topic property that specifies the 'tidy on unsubscribe' option
* for a topic.
*
* By default, if a session unsubscribes from a topic, it will receive any
* updates for that topic that were previously queued but not sent.
*
* If this property is set to `true`, when a session unsubscribes from the
* topic, any updates for the topic that are still queued for the session
* are removed. There is a performance overhead to using this option as the
* client queue must be scanned to find topic updates to remove, however it
* may prove useful for preventing unwanted data being sent to sessions.
*
* @since 6.0
*/
static readonly TIDY_ON_UNSUBSCRIBE = "TIDY_ON_UNSUBSCRIBE";
/**
* Key of the topic property that specifies the event data type for a time
* series topic.
*
* The value is the {@link DataType.name type name} of a
* data type.
*
* @since 6.0
*/
static readonly TIME_SERIES_EVENT_VALUE_TYPE = "TIME_SERIES_EVENT_VALUE_TYPE";
/**
* Key of the topic property that specifies the range of events retained by
* a time series topic.
*
* When a new event is added to the time series, older events that fall
* outside of the range are discarded.
*
* If the property is not specified, a time series topic will retain the ten
* most recent events.
*
* Time series range expressions
*
* The property value is a time series range expression string
* composed of one or more constraint clauses. Constraints are combined to
* provide a range of events from the end of the time series.
*
*
* - limit constraint
*
- A limit constraint specifies the maximum number of events from the
* end of the time series.
*
- last clause
*
- A last constraint specifies the maximum duration of events from the
* end of the time series. The duration is expressed as an integer followed
* by one of the following time units.
*
* MS – milliseconds;
* S – seconds;
* H – hours.
*
*
* If a range expression contains multiple constraints, the constraint that
* selects the smallest range is used.
*
* Property value | Meaning
* --------------- | ---------
* `limit 5` | The five most recent events
* `last 10s` | All events that are no more than ten seconds older than the latest event
* `last 10s limit 5` | The five most recent events that are no more than ten seconds older than the latest event
*
* Range expressions are not case sensitive: `limit 5 last 10s` is
* equivalent to `LIMIT 5 LAST 10S`.
*
* @since 6.0
*/
static readonly TIME_SERIES_RETAINED_RANGE = "TIME_SERIES_RETAINED_RANGE";
/**
* Key of the topic property that specifies the range of time series topic
* events to send to new subscribers.
*
* The property value is a time series range expression, following the
* format used for {@link TopicSpecification.TIME_SERIES_RETAINED_RANGE
* TIME_SERIES_RETAINED_RANGE}.
*
* If the property is not specified, new subscribers will be sent the latest
* event if delta streams are enabled and no events if delta streams are
* disabled. See the description of Subscription range in the
* {@link TimeSeries time series feature} documentation.
*
* @since 6.0
*/
static readonly TIME_SERIES_SUBSCRIPTION_RANGE = "TIME_SERIES_SUBSCRIPTION_RANGE";
/**
* Key of the topic property that specifies a schema which constrains topic
* values.
*
* This property is only used by {@link TopicType.RECORD_V2
* RECORD_V2} topics. The property value can be generated using
* the {@link Schema.asJSON} method of a {@link Schema} created using a
* {@link SchemaBuilder}.
*
* @since 6.0
*/
static readonly SCHEMA = "SCHEMA";
/**
* Key of the topic property that specifies a topic should not retain its
* last value.
*
* By default, a topic will retain its latest value. The latest value will
* be sent to new subscribers. Setting this property to `true` disables
* this behavior. New subscribers will not be sent an initial value. No
* value will be returned for fetch operations that select the topic. This
* is useful for data streams where the values are only transiently valid.
*
* Setting DONT_RETAIN_VALUE to `true` also disables delta streams,
* regardless of the {@link TopicSpecification.PUBLISH_VALUES_ONLY
* PUBLISH_VALUES_ONLY} value. If subsequent values are likely to be
* related, delta streams usually provide performance benefits (see {@link
* TopicSpecification.PUBLISH_VALUES_ONLY PUBLISH_VALUES_ONLY}). Consider
* leaving DONT_RETAIN_VALUE set to `false` to benefit from delta streams,
* even if there is no other requirement to retain the last value.
*
* Bearing in mind the performance trade-offs of disabling delta streams,
* there are two reasons to consider setting DONT_RETAIN_VALUE to `true`.
* First, it stops the server and each subscribed client from keeping a copy
* of the value, reducing their memory requirements. Second, when a topic
* has a high update rate and is replicated across a cluster, it can
* significantly improve throughput because the values need not be persisted
* to the cluster.
*
* Time series topics ignore this property and always retain the latest
* value.
*
* @since 6.0
*/
static readonly DONT_RETAIN_VALUE = "DONT_RETAIN_VALUE";
/**
* Key of the topic property that can be used to prevent a topic from being
* persisted when the server is configured to enable persistence.
*
* By default, a topic will be persisted if persistence is enabled at the
* server and the topic type supports persistence.
*
* Setting PERSISTENT to `false` will prevent the topic from being
* persisted.
*
* @since 6.1
*/
static readonly PERSISTENT = "PERSISTENT";
/**
* Key of the topic property that specifies a removal policy for automatic
* removal of the topic (and/or other topics).
*
* This property is specified as an expression which defines one or more
* conditions that are to be satisfied before automatic removal occurs.
*
* The expression takes the form:
*
*
* when conditions [remove 'selector']
*
*
* At least one condition must be supplied. If more than one is supplied,
* they must be separated by logical operators (`and` or `or`).
* The natural evaluation order of the operators may be changed by
* surrounding with parentheses (e.g. (condition `and`
* condition)).
*
* The `remove` clause is optional. It provides a {@link TopicSelector}
* expression representing the topics to be removed. If a `remove` clause is
* specified, the topic with the removal policy will only be removed if its
* path matches the selector expression. The selector must be surrounded by
* either double or single quotes.
*
* When many topics have the same removal policy, it is better to
* set the `REMOVAL` property for one of them, using a `remove`
* clause that selects all of the topics. This is more efficient because it
* allows the server to avoid evaluating the same condition many times.
*
* The permissions that are applied at the time of removal are those defined
* by the roles of the principal that created the topic at the time of
* creation. The roles of that principal may therefore change before the
* removal with no effect, but if the permissions given to the roles change
* it may have an effect upon the final removal.
*
* Only one occurrence of each of the following condition types may be
* included within the expression:
*
*
* | Condition Type |
* Format |
* Usage |
*
*
* | time after |
* time after absoluteTime |
* Removal should occur after a specified absolute time. Absolute time
* may be specified as a number of milliseconds since the epoch (00:00:00 on
* 1 January 1970) or as a quoted date and time formatted in RFC_1123
* date time format. Either single or double quotes may be used. |
*
*
* | subscriptions less than |
* [local] subscriptions < n for forPeriod [after afterPeriod] |
* Removal should occur when the topic has had less than the specified
* number (n) of subscriptions for a given period (forPeriod)
* of time. Optionally, an initial period (afterPeriod) may be
* specified by which to delay the initial checking of this condition. See
* below for period formats.
* The optional local keyword restricts evaluation to only count
* subscriptions from sessions belonging to the local server or cluster,
* ignoring subscriptions from sessions belonging to downstream remote servers that
* host fanout replicas of the topic. |
*
*
* | no updates for |
* no updates for forPeriod [after afterPeriod] |
* Removal should occur when the topic has had no updates for a given
* period (forPeriod) of time. Optionally, an initial period
* (afterPeriod) may be specified by which to delay the initial
* checking of this condition. See below for period formats. |
*
*
*
* Multiple occurrences of the following condition types may be
* included within the expression:
*
*
* | Condition Type |
* Format |
* Usage |
*
*
* | no session has |
* no [local] session has 'criteria' [for forPeriod] [after afterPeriod] |
* Removal should occur when no sessions satisfy certain criteria.
* Optionally the criteria can be required to be satisfied for a period of time
* (forPeriod). Optionally, an initial period (afterPeriod) can
* be specified to delay the initial check of the criteria. Session selection
* criteria are specified as defined in {@link Session session filters} and
* must be surrounded by single or double quotes. See below for period formats.
* The optional local keyword restricts evaluation to sessions
* belonging to the local server or cluster, ignoring sessions belonging to
* downstream remote servers that host fanout replicas of the topic. |
*
*
* |
* this session closes |
* This is a shorthand form of `no local session has` that may be used to
* indicate that the topic is to be removed when the session that created it
* closes. |
*
*
*
* Time periods are specified as a number followed (with no intermediate
* space) by a single letter representing the time unit. The time unit may
* be `s` (seconds), `m` (minutes), `h` (hours) or `d` (days). For example,
* 10 minutes would be specified as 10m.
*
* If quotes or backslashes (`\`) are required within quoted values such as
* selectors or session criteria then they may be escaped by preceding with
* `\`. The convenience method {@link escape} is provided to escape such
* characters in a value. The expression is validated only by the server and
* therefore if an invalid expression is specified it will be reported as an
* Error.
*
* **Examples:**
*
* ```
* when time after 1518780068112
* ```
*
* The topic will be removed when the date and time indicated by the
* specified number of milliseconds since the epoch has passed.
*
* ```
* when time after 'Tue, 3 Jun 2018 11:05:30 GMT'
* ```
*
* The topic will be removed when the specified date and time has passed.
*
* ```
* when time after 'Tue, 3 Jun 2018 11:05:30 GMT' remove '*alpha/beta//'
* ```
*
* The topic alpha/beta and all topics subordinate to it will be removed
* when the specified date and time has passed.
*
* ```
* when subscriptions < 1 for 20m
* ```
*
* The topic will be removed when it has had no subscriptions for a
* continuous period of 20 minutes.
*
* ```
* when subscriptions < 2 for 20m after 1h
* ```
*
* The topic will be removed when it has had less than 2 subscriptions for a
* continuous period of 20 minutes after one hour has passed since its
* creation.
*
* ```
* when no updates for 3h
* ```
*
* The topic will be removed when it has had no updates for a continuous
* period of 3 hours.
*
* ```
* when no updates for 15m after 1d
* ```
*
* The topic will be removed when it has had no updates for a continuous
* period of 15 minutes after one day has passed since its creation.
*
* ```
* when this session closes
* ```
*
* The topic will be removed when the session that created it closes.
*
* ```
* when no session has '$Principal is "Alice"'
* ```
*
* The topic will be removed when there is no session with the principal 'Alice'.
*
* ```
* when no session has '$Principal is "Alice"' for 10m
* ```
*
* The topic will be removed when there are no sessions with the principal
* 'Alice' for a continuous period of 10 minutes.
*
* ```
* when no session has 'Department is "Accounts"' for 30m after 2h
* ```
*
* The topic will be removed when there have been no sessions from the Account
* department for a continuous period of 30 minutes after 2 hours have passed
* since its creation.
*
* ```
* when time after "Tue, 3 Jun 2018 11:05:30 GMT" and subscriptions < 1 for 30m
* ```
*
* The topic will be removed when the specified date and time has passed and
* the topic has had no subscriptions for a continuous period of 30 minutes
* after that time.
*
* ```
* when time after "Tue, 3 Jun 2018 11:05:30 GMT" and subscriptions < 2 for 10m after 1h
* ```
*
* The topic will be removed when the specified date and time has passed and
* the topic has had less than 2 subscriptions for a continuous period of 10
* minutes after that time plus one hour.
*
* ```
* when time after "Tue, 3 Jun 2018 11:05:30 GMT" or subscriptions < 2 for 10m after 1h
* ```
*
* The topic will be removed when the specified date and time has passed or
* the topic has had less than 2 subscriptions for a continuous period of 10
* minutes after one hour from its creation.
*
* ```
* when time after "Tue, 3 Jun 2018 11:05:30 GMT" and (subscriptions < 2 for 10m after 1h or no updates for 20m)
* ```
*
* The topic will be removed when the specified date and time has passed and
* either the topic has had less than 2 subscriptions for a continuous
* period of 10 minutes after that time plus one hour or it has had no
* updates for a continuous period of 20 minutes. Note that the parentheses
* are significant here as without them the topic would be removed if it had
* had no updates for 20 minutes regardless of the time and subscriptions
* clause.
*
* **Notes and restrictions on use**
*
* The `after` time periods refer to the period since the topic was
* created or restored from persistence store after a server is restarted.
* They are designed as a 'grace' period after the topic comes into
* existence before the related conditions starts to be evaluated. When not
* specified the conditions start to be evaluated as soon as the topic is
* created or restored.
*
* The server will evaluate conditions on a periodic basis (every few
* seconds) so the exact removal time will not be precise for low periodic
* granularity.
*
* The meaning of the `for` period in a `no session has` condition is subtly
* different from its use in other conditions. It does not guarantee that
* there has been no session satisfying the condition at some point between
* evaluations, only that when evaluated the given period of time has passed
* since it was last evaluated and found to have no matching sessions.
*
* Subscriptions is the number of subscriptions to a topic.
*
* Automatic topic removal is supported for a topic that is replicated
* across the local cluster, and for a topic with with fanout replicas on
* downstream remote servers. A `subscriptions less than` condition will be evaluated
* against the total number of subscriptions across the cluster and on all
* fanout replicas on downstream remote servers. A `no session has`
* condition will consider all sessions hosted across the cluster and all
* sessions hosted by downstream remote servers that have a fanout replica
* of the topic. The `local` keyword can be used to restrict evaluation to
* the local cluster, ignoring fanout replicas.
*
* @since 6.1
*/
static readonly REMOVAL = "REMOVAL";
/**
* Key of the topic property that specifies the conflation policy of the
* topic. The policy specifies how the server manages queued topic updates.
* Conflation is applied individually to each session queue.
*
* Conflation is the process of merging or discarding topic updates queued
* for a session to reduce the server memory footprint and network data. The
* server will conflate sessions that have a large number of queued messages
* to meet configured queue size targets. The sessions with the largest
* queues are typically slow consumers or have been disconnected - both will
* benefit from conflation. This property allows conflation behavior to be
* tuned on a topic-by-topic basis.
*
* The supported policies are:
*
* * `off`
* * `conflate`
* * `unsubscribe`
* * `always`
*
* The default policy used when the property is not specified and the topic
* type is not time series is `conflate`. The default policy used when the
* property is not specified and the topic type is time series is `off`.
*
* The policy `off` disables conflation for the topic. This policy
* disables all conflation for the topic, so topic updates will never be
* merged or discarded.
*
* The policy `conflate` automatically conflates topic updates when
* back pressure is detected by the server.
*
* The policy `unsubscribe` automatically unsubscribes the topic when
* back pressure is detected by the server. The unsubscription is not
* persisted to the cluster. If a session fails over to a different server
* it will be resubscribed to the topic.
*
* The policy `always` automatically conflates topic updates as they
* are queued for the session. This is an eager policy that ensures only the
* latest update is queued for the topic, minimising the server memory and
* network bandwidth used by the session.
*
* The `conflate` and `unsubscribe` policies are applied when
* the server detects back pressure for a session. The server configuration
* places limits on the data queued for each session. If these limits are
* breached, the server will conflate the session queue to attempt to reduce
* its size. If the session queue still exceeds the limits after conflation,
* the session will be terminated.
*
* Conflation can be disabled on a session-by-session basis. If conflation is
* disabled for a session the policy will not be applied to topic updates
* queued for the session but will be for other sessions that have conflation
* enabled.
*
* The policies `conflate` and `always` are not supported for
* time series topics as they would cause missing events. Attempts to enable
* these policies with time series topics will cause the creation of the
* topic to fail, reporting that the specification is invalid.
*
* @since 6.2
*/
static readonly CONFLATION = "CONFLATION";
/**
* Key of the topic property that allows the creator of a topic to extend
* READ_TOPIC, MODIFY_TOPIC, and UPDATE_TOPIC permissions to a specific
* principal, in addition to the permissions granted by the authorisation
* rules in the security store.
*
* A session that has authenticated using the principal can update and
* remove the topic, so the principal can be considered the topic owner. To
* fetch or subscribe to the topic, the principal must also be granted
* the SELECT_TOPIC permission by the security store rules.
*
* This may be used in the following cases:
* 1) A session creates a topic and makes its own principal the owner.
* 2) A session creates a topic and makes another principal the owner.
*
* The format of the property value is:
*
* `$Principal is "name"`
*
* where name is the name of the principal. Single quotes may be used
* instead of double quotes and special characters can be escaped using
* {@link escape} if required.
*
* The purpose of this property is to allow a client to create topics on
* behalf of other users. This can be used in conjunction with the
* {@link REMOVAL} property so that such topics are removed when there are
* no longer any sessions for the named principal.
*
* **Example:**
* ```
* specification.withProperty(diffusion.topics.TopicSpecification.OWNER,
* "$Principal is 'myPrincipal'")
* .withProperty(diffusion.topics.TopicSpecification.REMOVAL,
* "when no session has '$Principal is \"myPrincipal\"' for 5s");
* ```
*
* @since 6.1
*/
static readonly OWNER = "OWNER";
/**
* Key of the topic property that allows the compression policy to be set
* on a per-topic basis.
*
* Compression reduces the bandwidth required to broadcast topic updates to
* subscribed sessions, at the cost of increased server CPU.
*
* Changes to a topic's value are published to each subscribed session as a
* sequence of topic messages. A topic message can carry the latest value or
* the difference between the latest value and the previous value (a delta).
* The compression policy determines if and how published topic messages
* are compressed. Topic messages are not exposed through the client API;
* the client library handles decompression and decodes deltas
* automatically, passing reconstructed values to the application.
*
* The compression policy for a topic is specified by setting this property
* to one of several values:
*
* * `off`
* * `low`
* * `medium`
* * `high`
*
* The policies are listed in the order of increasing compression and
* increasing CPU cost. `off` disables compression completely for the
* topic and requires no additional CPU; `high` compresses the topic
* messages to the smallest number of bytes, but has the highest CPU cost.
* Generally some compression is beneficial, so the default value for this
* property is `low`.
*
* Prior to version 6.4, only two values were allowed: `true`
* (equivalent to `medium`, and the previous default policy) and
* `false` (equivalent to `off`). These values are still
* supported.
*
* This property is only one factor that determines whether a topic message
* will be compressed. Other factors include:
*
* * Compression must be enabled in the server configuration.
*
* * The client library must support the server's compression
* scheme. In this release, the server supports zlib
* compression, and also allows compression to be disabled on a
* per-connector basis. From 6.4, all client libraries are
* capable of zlib compression. A JavaScript client may or may
* not support zlib compression, depending on whether the zlib
* library can be loaded. The zlib library is packaged
* separately to reduce the download size of the core library.
*
* @since 6.2
*/
static readonly COMPRESSION = "COMPRESSION";
/**
* Key of the topic property that specifies the topic delivery priority.
*
* The supported delivery priorities are:
*
* * `low`
* * `default`
* * `high`
*
* The delivery priority affects the order of topic updates sent to a
* subscribed client session. When there are multiple topic updates for
* topics with different priorities in a session's outbound queue, updates
* for `high` priority topics will be delivered first, followed by
* updates for `default` priority topics, followed by updates for
* `low` priority topics. Topic subscription and unsubscription
* notifications are also delivered according to the topic delivery
* priority.
*
* Using different delivery priorities is most beneficial when there is a
* large backlog of queued updates to deliver to a client session. On
* lightly loaded systems, updates typically remain in the outbound queue
* for a few milliseconds and so there is a lower chance of topic updates
* being reordered based on their priority. The backlog will be larger if
* the topic update rate is higher; the server or the client are more
* heavily loaded; the client session becomes temporarily disconnected; or
* if there is poor network connectivity between the server and the client.
*
* Messages from the server to the client that are not topic updates, for
* example ping requests and responses, are queued with the
* `default` delivery priority.
*
* @since 6.4
*/
static readonly PRIORITY = "PRIORITY";
/**
* The topic type.
*/
type: TopicType;
/**
* A map of the topic properties.
*/
properties: {
[key: string]: string;
};
/**
* Create a new TopicSpecification
*
* @param type the topic type for this specification.
* @param properties the properties to use for this specification.
* @since 5.9
*
* **Example:**
*
* Properties can be set when creating the specification by passing an object
* ```
* // Create specification for JSON topics which validate update values on the server
* const TopicSpecification = diffusion.topics.TopicSpecification;
*
* var specification = new TopicSpecification(diffusion.topics.TopicType.JSON, {
* "VALIDATE_VALUES" : "true"
* });
* ```
*
* **Example:** New specifications can be created with additional properties
* ```
* // Create specification for JSON topics which validate update values on the server
* const TopicSpecification = diffusion.topics.TopicSpecification;
*
* var specification = new TopicSpecification(diffusion.topics.TopicType.JSON)
* .withProperty(TopicSpecification.VALIDATE_VALUES, "true");
* ```
*/
constructor(type: TopicType, properties?: {
[key: string]: string;
});
/**
* Returns a new TopicSpecification with the specified property set to the supplied value.
* @param key the new property key
* @param value the new property value
* @returns a new TopicSpecification with the specified property set.
*
* @throws an {@link IllegalArgumentError} if the key is not a valid property key.
*/
withProperty(key: string, value: string): TopicSpecification;
/**
* Returns a new TopicSpecification with the specified property set to the supplied value.
* @param key the new property key
* @param value the new property value
* @returns a new TopicSpecification with the specified property set.
*
* @throws an {@link IllegalArgumentError} if the key is not a valid property key.
*/
withProperties(properties: {
[key: string]: string;
}): TopicSpecification;
}
/**
* @module diffusion.topics
*/
/**
* Enum containing possible Topic Types.
*
* **Example:**
* ```
* // Get a topic type for adding topics
* var topicType = diffusion.topics.TopicType.JSON;
*
* session.topics.add("foo", topicType);
* ```
*/ export declare enum TopicType {
/**
* Binary Topic.
*
* This is a stateful topic that handles data in Binary format.
* @since 5.7
*/ BINARY = 14,
/**
* JSON (JavaScript Object Notation) Topic.
*
* This is a stateful topic that handles data in JSON representation.
* @since 5.7
*/ JSON = 15,
/**
* Topic that stores and publishes String values. Based on the {@link string string data type}.
*
* Supports null String values.
*
* Supports delta-streams.
*
* @since 6.0
*/ STRING = 17,
/**
* Topic that stores and publishes 64-bit integer values. Based on the
* {@link int64 int64 data type}. Values are of the type
* {@link Int64}.
*
* Supports null int64 values.
*
* Does not support delta-streams - only complete values are transmitted.
*
* @since 6.0
*/ INT64 = 18,
/**
* Topic that stores and publishes IEEE 754 double-precision floating point
* numbers (i.e native JavaScript Numbers). Based on the {@link double double data type}.
*
* Supports null Double values.
*
* The topic does not support delta-streams - only complete values are transmitted.
*
* @since 6.0
*/ DOUBLE = 19,
/**
* Time Series Topic.
*
* A time series is a sequence of events. Each event contains a
* value and has server-assigned metadata comprised of a sequence number,
* timestamp, and author.
*
* A time series topic allows sessions to access a time series that is
* maintained by the server. A time series topic has an associated
* {@link DataType event data type}, such as `Binary`, `String`,
* or `JSON`, that determines the type of value associated with each
* event.
*
* Retained range
*
* The {@link TopicSpecification.TIME_SERIES_SUBSCRIPTION_RANGE
* TIME_SERIES_SUBSCRIPTION_RANGE} property configures the range of historic
* events retained by a time series topic. If the property is not specified,
* a time series topic will retain the ten most recent events.
*
* Subscription range
*
* The {@link TopicSpecification.TIME_SERIES_SUBSCRIPTION_RANGE
* TIME_SERIES_SUBSCRIPTION_RANGE} property configures a time series topic
* to send a range of historic events from the end of the time series to new
* subscribers. This is a convenient way to synchronize new subscribers
* without requiring the use of a {@link TimeSeries.rangeQuery range query}.
*
* By default, new subscribers will be sent the latest event if delta
* streams are enabled and no events if delta streams are disabled. See the
* description of Subscription range in the {@link
* Session.timeseries} time series feature} documentation.
*
*
* Mandatory properties
*
* The {@link TopicSpecification.TIME_SERIES_EVENT_VALUE_TYPE
* TIME_SERIES_EVENT_VALUE_TYPE} property must be provided when creating a
* time series topic.
*
*
* @since 6.0
* @see diffusion.datatypes.TimeSeriesDataType
*/ TIME_SERIES = 16,
/**
* Topic that stores and publishes data in the form of records and fields.
* Based on the {@link RecordV2DataType RecordV2 data type}.
*
* Supports delta-streams.
*
* @since 6.0
*/ RECORD_V2 = 20,
/**
* A topic type that is unsupported by the session.
*
* @since 6.3
*/ UNKNOWN_TOPIC_TYPE = 21
}
/**
* Provide access to {@link TopicType TopicType},
* {@link TopicSpecification TopicSpecification}, and
* {@link UnsubscribeReason UnsubscribeReason}
* @namespace diffusion.topics
*
* @module diffusion.topics
*/
/**
* A type containing information about the reason for an unsubscription
*/
export declare class UnsubscribeReason {
/**
* The unsubscribe reason's id
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
readonly id?: number;
/**
* The unsubscribe reason's description
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
readonly reason: string;
/**
* Create a `UnsubscribeReason`
*
* @param id the unsubscribe reason's id
* @param reason the unsubscribe reason's description
*/
constructor(id: number | undefined, reason: string);
}
/**
* Enum containing reasons that an unsubscription occurred.
*
* **Example:**
* ```
* // Use UnsubscribeReason to validate unsubscription notifications
* session.addStream('>foo', diffusion.datatypes.string())
* .on('unsubscribe', function(topic, specification, reason) {
* switch (reason) {
* case diffusion.topics.UnsubscribeReason.REMOVED :
* // Do something if the topic was removed
* default :
* // Do something else if the client was explicitly unsubscribed
* }
* });
* ```
*/ export declare const UnsubscribeReasonEnum: {
[key: string]: UnsubscribeReason;
};
/**
* A type containing information about the reason for failure of an update
*/
export declare class UpdateFailReason {
/**
* The update fail reason's id
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
readonly id?: number;
/**
* The update fail reason's description
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
readonly reason: string;
/**
* Create a `UpdateFailReason`
*
* @param id the update fail reason's id
* @param reason the update fail reason's description
*/
constructor(id: number | undefined, reason: string);
}
/**
* The reason that a topic could not be updated.
*
* **Example:**
* ```
* session.topics.update('foo', 'bar').then(function() { ... }, function(err) {
* switch (err) {
* case diffusion.topics.UpdateFailReason.MISSING_TOPIC:
* ...
* case diffusion.topics.UpdateFailReason.EXCLUSIVE_UPDATER_CONFLICT:
* ...
* }
* });
* ```
*/ export declare const UpdateFailReasonEnum: {
[key: string]: UpdateFailReason;
};
/**
* A type containing information about the reason for failure of adding a topic
*/
export declare class TopicAddFailReason {
/**
* The topic add failure reason's id
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
readonly id?: number;
/**
* The topic add failure reason's description
*
* @deprecated since 6.8
*
* This member is deprecated and will be removed in the future.
*/
readonly reason: string;
/**
* Create a `TopicAddFailReason`
*
* @param id the topic add failure reason's id
* @param reason the topic add failure reason's description
*/
constructor(id: number | undefined, reason: string);
}
/**
* The reason that a topic could not be added.
*
* **Example:**
* ```
* session.topics.add('foo').then(function() { ... }, function(err) {
* switch (err) {
* case diffusion.topics.TopicAddFailReason.EXISTS:
* ...
* case diffusion.topics.TopicAddFailReason.INVALID_NAME:
* ...
* }
* });
* ```
*
*/ export declare const TopicAddFailReasonEnum: {
[key: string]: TopicAddFailReason;
};
export interface TopicsNamespace {
FetchRequest: typeof FetchRequest;
TopicType: typeof TopicType;
TopicSpecification: typeof TopicSpecification;
UnsubscribeReason: typeof UnsubscribeReasonEnum;
UpdateFailReason: typeof UpdateFailReasonEnum;
TopicAddFailReason: typeof TopicAddFailReasonEnum;
}
export declare const topicsNamespace: TopicsNamespace;
/**
* @module diffusion
*/
/**
* An enum for the available log levels
*
* Accessible through `diffusion.LogLevel`.
*/
export declare enum LogLevel {
trace = "trace",
debug = "debug",
info = "info",
warn = "warn",
error = "error",
silent = "silent"
}
/**
* @module diffusion.datatypes
*/
/**
* Binary data type.
*
* Accessed via:
* `diffusion.datatypes.binary();`
*
* The implementation provides support for binary deltas.
*
* {@link Binary} values can be used to store and transmit arbitrary
* information. The responsibility for formatting and interpreting the
* information belongs solely to the application. Before using Binary for a
* topic, consider other data types such as {@link JSON JSON} or
* single value topic types; these may provide a simpler interface for
* your application.
*
* The implementation provides support for {@link BinaryDelta binary deltas}.
*
* {@link Binary} values are created by passing a `Uint8Array` object to {@link
* BinaryDataType.from}. When running the Diffusion Client in a browser context,
* access to the `Uint8Array` api is made available through
* [diffusion.buffer](../globals.html#buffer).
*
* @since 5.7
*/
export interface BinaryDataType extends DataType {
/**
* The Binary data type value class
*/ Binary: new (value: Uint8Array) => Binary;
/**
* Returns a new {@link Binary} instance from a buffer.
*
* @param buffer The binary data
* @return A Binary data-type instance
* @throws an {@link IllegalArgumentError} if the data is not a valid Binary
*/
from(buffer: Uint8Array): Binary;
}
/**
* @module diffusion.datatypes
*/
/**
* Delta that represents the difference between two binary values.
*
* {@link DataType} implementations that support binary deltas by returning a
* delta type implementation as the result of a diff operation
* {@link Binary.diff diff}. Two values of such a data type can be diffed to
* create a binary delta. The binary delta can later be applied to the first
* value to calculate the second value.
*
* @since 5.7
*/
export interface BinaryDelta {
/**
* Whether this delta contains any changes.
*
* @returns if the delta contains changes
*/
hasChanges(): boolean;
}
/**
* @module diffusion.datatypes
*/
///
/**
* A read-only binary value with support for binary deltas.
*
* Values are effectively immutable. Instances can be backed by
* {@link BinaryDataType.from user-supplied buffers}.
* Once a Binary has been constructed around a buffer, care must
* be taken not to modify the data in the buffer because doing
* so would violate immutability.
*
* @since 5.7
*/
export interface Binary extends Bytes {
/**
* Get the value as a Buffer.
*
* @return the buffer value
*
* @deprecated since version 6.11. Buffer has been replaced by Uint8Array.
* Use getArray instead. This will be removed
* in a future release.
*/
get(): Buffer;
/**
* Get the value as a Uint8Array.
*
* @return the array value
*/
getArray(): Uint8Array;
/**
* Compare this Binary value with an earlier version to create a delta.
*
* Convenient equivalent to:
* `diffusion.datatypes.binary().deltaSupport(type).diff(original, this);`
*
* Buffers stored in a `Uint8Array` may also be provided as the value to diff instead of a
* {@link Binary} instance.
*
* **Example:**
*
* Node.js:
* ```
* const delta = binaryValue.diff(Buffer.from('Hello world'));
* ```
*
* Browser:
* ```
* const delta = binaryValue.diff(new TextEncoder().encode('Hello World'));
* ```
*
* @param original the value to diff against this
* @param type the type of delta to generate (default: `binary`);
* @return a delta representing the difference between this and the provided value
*/
diff(original: Binary | Uint8Array, type?: string): BinaryDelta;
/**
* Apply a delta to this Binary value to create a new value.
*
* Convenient equivalent to:
* `diffusion.datatypes.binary().deltaSupport(delta).apply(this, delta);`
*
* @param delta the binary delta to apply to this value
* @return a new instance derived from applying the delta to this value
* @throws an {@link InvalidDataError} if the delta is invalid
*/
apply(delta: BinaryDelta): Binary;
}
/**
* @module diffusion.datatypes
*/
/**
* JSON data type.
*
* Accessed via:
* `diffusion.datatypes.json();`
*
* The JSON Data Type provides {@link JSON} values, which
* are a wrapper around native JSON objects.
*
* For efficiency, the JSON value is serialized in binary form following
* the CBOR specification.
*
* The implementation provides support for binary deltas.
*
* JSON instances defer parsing of underlying binary data until required. If the
* data is not valid, an Error may be thrown when {@link JSON.get} is called.
*
* @since 5.7
*/
export interface JSONDataType extends DataType {
/**
* The JSON data type value class
*/
JSON: new (value: any) => JSON;
/**
* Returns a new {@link JSON} instance from a native JS object.
*
* Passing a string will produce a JSON instance encoding a single string
* token. To produce a JSON datatype instance from a JSON string, use {@link
* JSONDataType.fromJsonString} instead.
*
* This is useful in cases where providing the raw value may be ambiguous
* for SDK methods that infer the datatype from provided arguments, such as
* {@link Messages.sendRequest}.
*
* **Example:**
* ```
* // Value from object
* var value = jsondatatype.from({
* foo : "bar",
* baz : [1, 2, 3]
* });
* ```
*
* **Example:**
* ```
* // Datatype instance from string
* var value = jsondatatype.from("this is a simple string");
* ```
*
* @param object the object data
* @return a JSON data-type instance
*/
from(object: any): JSON;
/**
* Returns a new {@link JSON} instance from a JSON
* string.
*
* Precision for numeric types is lost in the translation to the internal
* CBOR binary form and non-significant white space is not preserved.
*
* **Example:**
* ```
* // Datatype instance from a JSON string.
* var value = jsondatatype.fromJsonString("{\"foo\" : \"bar\"}");
*
* // The value contains the parsed object representation
* value.get(); // => { foo : "bar" }
* ```
*
* @param json the JSON string
* @return a JSON data-type instance
*
* @since 5.9
*/
fromJsonString(json: string): JSON;
}
/**
* Alias for the JSONDataType interface to keep compatibility with old TypeScript definitions
*/
export declare type JsonDataType = JSONDataType;
/**
* @module diffusion.datatypes
*/
/**
* An unmodifiable map describing the changes to a JSON value.
*
* The {@link JSONDelta.inserted} method returns a
* {@link ChangeMap ChangeMap} describing the parts
* of the second JSON value not found in the first JSON value. Similarly,
* {@link JSONDelta.removed}
* returns a `ChangeMap` describing the parts of the first JSON value
* not found in the second JSON value.
*
* The map contains an entry for each change, as follows:
* * The key is a JSON
* Pointer syntax reference locating the change in the complete value.
* Since a JSON value is a list of zero or more data items, the reference
* always begins with an array index. For example, the first part is
* identified by the JSON Pointer `/0`.
* * The value is part of the complete value. It is returned as a parsed
* value.
*
* An error will be thrown if an invalid JSON pointer expression is passed to
* {@link ChangeMap.get get},
* {@link ChangeMap.containsKey containsKey},
* {@link ChangeMap.descendants descendants}, or
* {@link ChangeMap.intersection intersection}. This only
* occurs if the expression does not start with `/` and is not empty.
*/
export interface ChangeMap {
/**
* Retrieve a value from this change map, identified by a JSON Pointer.
*
* @param pointer the JSON Pointer expression
* @returns the change map value, if it exists, otherwise null
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression
*/
get(pointer: string): any;
/**
* Determines if this change map contains an entry for a given JSON Pointer
*
* @param pointer the JSON Pointer expression
* @returns `true` if an entry exists, false if not
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression
*/
containsKey(pointer: string): boolean;
/**
* Returns an array of map entries. Each entry is in the form of a key/value object pair.
*
* The key is a JSON Pointer expression, in string form. The value will be parsed from the
* underlying {@link JSON} object.
*
* @returns the entry array
*
* **Example:**
* ```
* changeMap.entrySet().forEach(function(entry) {
* console.log(entry.key, entry.value);
* });
* ```
*/
entrySet(): Array<{
key: string;
value: string;
}>;
/**
* Returns a view of the portion of this map whose keys are descendants
* of `pointer`. If `pointer` is contained in this map, it
* will be included in the result.
*
* @param pointer the json pointer expression to derive descendants for
* @returns changemap of descendant changes
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression
*/
descendants(pointer: string): ChangeMap;
/**
* Returns a view of the portion of this map whose keys are descendants
* or parents of `pointer`. If `pointer` is contained in
* this map, it will be included in the result.
*
* This method can be used to determine whether a structural
* delta affects a particular part of a JSON value. For example:
*
* ```
* if (structuralDelta.removed().intersection("/contact/address").length) {
* // The structural delta removes elements that affect '/contact/address'.
* }
* if (structuralDelta.inserted().intersection("/contact/address").length) {
* // The structural delta inserts elements that affect '/contact/address'.
* }
* ```
*
* @param pointer the json pointer expression to derive intersection for
* @returns changemap of intersection changes
* @throws an {@link IllegalArgumentError} if pointer is an invalid JSON Pointer expression
*/
intersection(pointer: string): ChangeMap;
}
/**
* Structural delta type for {@link JSON}.
*
* A JSONDelta describes the differences between two JSON values. Unlike a
* {@link BinaryDelta binary delta}, a
* structural delta can be queried to determine its effect. The
* {@link JSONDelta.removed removed} and
* {@link JSONDelta.inserted inserted} methods provide full
* details of the differences between the two values.
*
* An instance can be created from two JSON values using
* {@link JSON.jsonDiff}.
*
* JSONDeltas are useful for identifying small changes to complex JSON values.
* Here's an example of how to use this class to filter interesting changes in
* a ValueStream.
*
* ```
* const valueStream = session.addStream('foo/bar', diffusion.datatypes.json());
* valueStream.on('value', (topicPath, oldValue, newValue) => {
* const delta = newValue.diff(oldValue);
*
* if (!delta.removed().intersection('/address').isEmpty() ||
* !delta.inserted().intersection('/address').isEmpty()) {
*
* // The 'address' field has changed.
* processAddress(newValue);
* }
* }
*
* // ...
* }
* ```
*
* @author DiffusionData Limited
* @since 5.9
*/
export interface JSONDelta {
/**
* Returns the parts of the first JSON value not found in the second JSON
* value.
*
* @return the removed parts. The JSON Pointer references used for the
* keys are relative to first JSON value.
*/
removed(): ChangeMap;
/**
* Returns the parts of the second JSON value not found in the first JSON
* value.
*
* @return the removed parts. The JSON Pointer references used for
* the keys are relative to second JSON value.
*/
inserted(): ChangeMap;
/**
* Returns whether the two JSON values used to create this instance are
* different.
*
* @return `true` if this delta has an effect
*/
hasChanges(): boolean;
}
/**
* @module diffusion.datatypes
*/
/**
* Immutable JSON data. The value is stored internally as a buffer.
*
* JSON is "JavaScript Object Notation", a lightweight data-interchange format.
* See www.json.org.
*
* To create an instance from an object, obtain a {@link JSONDataType}
* implementation from `diffusion.datatypes.json()` and call {@link
* JSONDataType.from}.
*
* The encapsulated value can be accessed by calling {@link JSON.get}.
*
*
CBOR representation
*
* Internally the value is stored and transmitted not as a JSON string, but in
* CBOR format to reduce memory and network overhead. CBOR (Concise Binary
* Object Representation) is a standardized format for binary representation of
* structured data defined by RFC
* 7049. See www.cbor.io.
*
* Rather than working with JSON strings it is possible, and usually preferable,
* for applications to work directly with the underlying CBOR-format binary
* representation. This avoids creating intermediate JSON strings, and allows
* access to CBOR features such as the byte string data type.
*
* Each JSON value is represented as a single CBOR data item. CBOR supports
* composite data types just like JSON, so this data item can be an array or a
* map of other data items. The JSON `null` value is represented by the
* CBOR `null` value.
*
* A particular advantage of working directly with the CBOR-format data is that
* binary data can be written to the value as a data item using the CBOR byte
* string type. The data item will be stored as part of the JSON value in binary
* form and transmitted without further conversion.
*
* @since 5.7
*/
export interface JSON extends Bytes {
/**
* Get this instance's value. Use this method to access the provided data when a
* {@link JSON} instance is received through the API.
*
* **Example:**
* ```
* session.addStream('foo', diffusion.datatypes.json())
* .on('value', function(path, spec, value) {
* // Get the actual value from the JSON instance
* const data = value.get();
* });
* ```
*
* @return the JSON value
* @throws an {@link InvalidDataError} if the value cannot be read
*/
get(): any;
/**
* Compare this JSON value with an earlier version to create a delta.
*
* Convenient equivalent to:
* `diffusion.datatypes.json().deltaType(type).diff(original, this);`
*
* Standard JSON objects may also be provided as the value to diff instead
* of a {@link JSON} instance.
*
* **Example:**
* ```
* const binaryDelta = jsonValue.diff({ foo : 'bar' });
* ```
*
* **Example:**
* ```
* const jsonDelta = jsonValue.diff({ foo : 'bar' }, 'json');
* ```
*
* @param original the value to diff against this
* @param type the type of delta to generate (default = 'binary')
* @return a delta representing the difference between this and the provided value
* @throws an {@link InvalidDataError} if the type is `json` but the diff could not be parsed
*/
diff(original: any, type?: string): BinaryDelta | JSONDelta;
/**
* Compare this JSON value with an earlier version to create a structural
* {@link JSONDelta json delta}.
*
* Convenient equivalent to:
* `this.diff(original, 'json');`
*
* Standard JSON objects may also be provided as the value to diff instead
* of a {@link JSON} instance.
*
* **Example:**
* ```
* const delta = jsonValue.jsonDiff({ foo : 'bar' });
* ```
*
* @param original the value to diff against this
* @return a delta representing the difference between this and
* the provided value
*/
jsonDiff(original: any): JSONDelta;
/**
* Apply a delta to this JSON value to create a new value.
*
* Convenient equivalent to:
* `diffusion.datatypes.JSON().deltaType(delta).apply(this, delta);`
*
* @param delta the binary delta to apply to this value
* @return a new instance derived from applying the delta to this value
* @throws an {@link InvalidDataError} if the delta is invalid
*/
apply(delta: BinaryDelta): JSON;
}
/**
* Alias for the JSON interface to keep compatibility with old TypeScript definitions
*/
export declare type Json = JSON;
/**
* @module diffusion.datatypes
*/
/**
* Double data type.
*
* Accessed via:
* `diffusion.datatypes.double();`
*
* Provides a data type implementation which supports double float (native
* JavaScript Number) values. The double value is serialized in CBOR-format
* binary.
*
* This data type supports null double values.
*
* @since 6.0
*/ export interface DoubleDataType extends DataType {
}
/**
* @module diffusion.datatypes
*/
/**
* A type that can be converted to an int64
*/
export declare type Int64SourceType = string | number | Uint8Array | Int64;
/**
* Int64 data type.
*
* Accessed via:
* `diffusion.datatypes.int64();`
*
* Provides a data type implementation which supports {@link Int64 64-bit signed
* integer} values. The Int64 value is serialized in CBOR-format binary.
*
* This data type supports null Int64 values.
*
* @since 6.0
*/
export interface Int64DataType extends DataType {
/**
* The Int64 data type value class
*/ Int64: new (value: string | number | Uint8Array, radix?: number) => Int64;
}
/**
* @module diffusion.datatypes
*/
/**
* Signed 64-bit integer. Provides a means to read integer values larger than
* supported natively by JavaScript.
*
* Used as the value type of the Int64 data type:
* ```
* var datatype = diffusion.datatypes.int64();
* var value = new datatype.Int64("9223372036854775807");
* ```
*
* @since 6.0
*/
export interface Int64 {
/**
* Read this value as a string.
*
* @param radix the radix to use. Defaults to base `10`.
* @return the string representation of the int64 value.
*/
toString(radix?: number): string;
/**
* Read this value as a number. The validity of the returned number can only be guaranteed for values up to
* `Math.pow(2, 53) - 1` due to underlying platform limitations of JavaScript.
*
* @return the numerical value of this int64, as a 53-bit integer.
*/
toNumber(): number;
}
/**
* @module diffusion.datatypes
*/
/**
* A type that can be converted to a string
*/
export declare type StringSourceType = string | {
toString: () => string;
};
/**
* String data type.
*
* Accessed via:
* `diffusion.datatypes.string();`
*
* Provides a data type implementation which supports string values. The string value is serialized in CBOR-format
* binary.
*
* This data type supports null string instances.
*
* @since 6.0
*/ export interface StringDataType extends DataType {
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* This is a mutable data model of {@link RecordV2} data
* based upon a {@link Schema}.
*
* An initial version of such a model can be created from a schema using the
* {@link Schema.createMutableModel} method. A
* model created in this way will have all mandatory fields set to default
* values.
*
* The model may then be updated as required and then at any time a {@link
* RecordV2} object can be generated from the current state using the {@link
* MutableRecordModel.asValue asValue} method. The {@link RecordV2} object may
* then be used to update a topic.
*
* When values for integer or decimal type fields are supplied the values are
* validated and normalized. All number values will have any insignificant
* leading zeroes removed. A decimal value will also be rounded to its specified
* scale.
*
* All mutator methods return the model so that calls can be chained.
*
* @since 6.0
*/
export interface MutableRecordModel extends RecordModel {
/**
* Set a field value.
*
* This allows an item to be addressed using a key of the form
* `recordName(recordIndex).fieldName(fieldIndex)`. Indexes may be omitted
* in which case `0` is assumed.
*
* **Example:**
* ```
* // Get field value with record & field names and indices
* var value = model.set("record", 0, "field", 0, "foo");
* ```
*
* @param recordName the name of the record
* @param recordIndex the index of the record
* @param fieldName the name of the field
* @param fieldIndex the index of the field
* @param value the value to be set
* @return this model
*
* @throws an {@link IllegalArgumentError} if `recordName` is invalid
* @throws an {@link OutOfBoundsError} if `recordIndex` or `fieldIndex` is out of range
* @throws an {@link SchemaViolationError} if a record or field was requested that
* does not exist in the schema
*/
set(recordName: string, recordIndex: number, fieldName: string, fieldIndex: number, value: string): MutableRecordModel;
set(recordName: string, fieldName: string, value: string): MutableRecordModel;
set(recordName: string, value: string): MutableRecordModel;
/**
* Adds new values to the end of a variable length field list.
*
* This can only be used for a variable multiplicity field which can only be
* the last field in a record and therefore the field does not need to be
* named.
*
* If the record name and index are not supplied, this will add values to the last
* record in the model. If the model's schema does not specify a variable last field
* or record, an error will be thrown.
*
* @param recordName the name of the record
* @param recordIndex the index identifying the occurrence of the record
* @param values the values to add
* @return this model
*
* @throws a {@link SchemaViolationError} if adding the values would violate the schema
*/
add(recordName: string, recordIndex: number, ...values: string[]): MutableRecordModel;
add(recordName: string, ...values: string[]): MutableRecordModel;
/**
* Adds a new initialized record occurrence to the end of a variable
* multiplicity record list.
*
* As the only variable multiplicity record can be the last one there is no
* need to name the record. This method will add to the list of occurrences
* of the last defined record. The record will be initialized with default
* values appropriate to the schema definition and may then have individual
* field items set separately.
*
* @return this model
* @throws a {@link SchemaViolationError} if adding a record would violate the schema
*/
addRecord(): MutableRecordModel;
/**
* Removes the specified occurrence of a variable multiplicity record.
*
* A variable multiplicity record must be the last or only record within a
* schema and therefore the record name is not required.
*
* @param index the index of the record to remove
* @return this model
*
* @throws an {@link IllegalArgumentError} if the index is out of range
* @throws a {@link SchemaViolationError} if removing the record would violate the schema
*/
removeRecord(index: number): MutableRecordModel;
/**
* Removes the specified occurrence of a variable multiplicity field.
*
* A variable multiplicity field must be the last or only field within a
* record and therefore the field name is not required.
*
* @param recordName the name of the record
* @param recordIndex the record index
* @param fieldIndex the index of the field to remove
* @return this model
*
* @throws an {@link IllegalArgumentError} if one of the indices is out of range
* @throws a {@link OutOfBoundsError} if `recordIndex` or `fieldIndex` is out of range
* @throws a {@link SchemaViolationError} if removing the field would violate the schema
*/
removeField(recordName: string, recordIndex: number, fieldIndex: number): MutableRecordModel;
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* Builds free format {@link RecordV2 RecordV2 value}.
*
* This type of builder may be used to generate free format {@link RecordV2}
* data which is not constrained by a {@link Schema}.
*
* A builder can be created using {@link RecordV2DataType.valueBuilder}.
*
* @since 6.0
*/
export interface RecordV2Builder {
/**
* Adds one or more field values.
*
* If there is a current record, this adds the fields to the end of the
* current record.
*
* @param values field values
* @return this builder
*/
addFields(fields: string[]): RecordV2Builder;
addFields(...fields: string[]): RecordV2Builder;
/**
* Adds a new record comprising the specified field values.
*
* @param fields the fields within the new record. If no fields are
* supplied, an empty record will be added.
* @return this builder
*/
addRecord(fields: string[]): RecordV2Builder;
addRecord(...fields: string[]): RecordV2Builder;
/**
* Clears all current values from the builder allowing it to be reused to
* generate new data.
*
* @return this builder
*/
clear(): void;
/**
* Builds a {@link RecordV2} object from the current
* builder state.
*
* @return a new {@link RecordV2} object
*/
build(): RecordV2;
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* Record-based data type.
*
* This provides the ability to handle data in Diffusion proprietary 'record'
* format. This format allows string data to be organized into 'records' which
* in turn are made up of 'fields'. Each field is a string but may be handled as
* either an integer or a decimal field if required.
*
* This format is compatible with legacy RECORD topics (removed in release 6.2)
* and therefore can be used to migrate client applications from using such
* topics with minimal change to the application.
*
* The data can either be free format or constrained by a {@link Schema}.
*
* In free format mode, no schema is associated with the data and the data will
* contain zero or more records, each comprising zero or more fields. In this
* mode the meaning of each field is entirely up to the application and no
* validation will be performed by Diffusion, either in the client library, or
* at the server. To write free format records, a {@link RecordV2Builder} can be
* used to create a [RecordV2](recordv2.html) object. Such a builder may be
* created using the {@link RecordV2DataType.valueBuilder} method.
*
* When using a {@link Schema} then the permitted records and fields are defined
* by the schema. The schema names the records and the fields within them and
* provides a mechanism for direct access to the fields. The schema is also used
* to validate the data to ensure it complies with the schema definition.
*
* In schema mode, data can be created and updated using a {@link
* MutableRecordModel} which allows records and fields to be conveniently set
* and updated by name. A base model can be created from a schema using the
* {@link Schema.createMutableModel} method. The model can at any time be used
* to create a new [RecordV2](recordv2.html) object. A consumer of a
* [RecordV2](recordv2.html) value can read it as a {@link RecordModel} by
* simply using the {@link RecordV2.asModel} method to produce an immutable
* representation of the data. When creating the data using a {@link
* MutableRecordModel} then the model ensures that the data is valid and
* therefore there is no need for the server or the consuming client to validate
* the data.
*
* Schemas can be parsed from JSON strings or more simply using a {@link
* SchemaBuilder} obtained using the {@link RecordV2DataType.schemaBuilder}
* method. A schema can be bound to a [RecordV2](recordv2.html) data type
* instance using the method {@link RecordV2DataType.withSchema}. This method
* will return a new RecordV2DataType instance with the schema bound to it for
* validation.
*
* A [RecordV2](recordv2.html) object can only be validated within the context
* of a {@link Schema}.
*
* Accessed via:
* `diffusion.datatypes.recordv2();`
*
* @since 6.0
*/
export interface RecordV2DataType extends DataType {
/**
* The RecordV2 data type value class
*/ RecordV2: new (...args: any[]) => RecordV2;
/**
* Bind a specific schema to a {@link RecordV2DataType}
* instance.
*
* @param schema schema to bind to the data type
* @return a {@link RecordV2DataType} bound to a
* specific schema
*/
withSchema(schema: Schema): RecordV2DataType;
/**
* Parse a schema from a JSON string.
*
* @param json json string containing a schema definition
* @return the schema
*/
parseSchema(json: string): Schema;
/**
* Creates a new {@link RecordV2Builder}.
*
* Such a builder may be used to generate a free format [RecordV2](recordv2.html)
* format value that is not constrained by a {@link Schema}.
*
* @return a new records builder
*/
valueBuilder(): RecordV2Builder;
/**
* Creates a new schema builder.
*
* @return a new schema builder
*/
schemaBuilder(): SchemaBuilder;
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* Represents a single change to a Record value.
*/
export interface Change {
/**
* The name of the affected record
*/
readonly recordName: string;
/**
* The index of the affected record
*/
readonly recordIndex: number;
/**
* The name of the affected field
*/
readonly fieldName: string;
/**
* The index of the affected field
*/
readonly fieldIndex: number;
/**
* Returns the string key representation of the affected item in
* the form `recordName(recordIndex).fieldName(fieldIndex)`.
*/
readonly key: string;
/**
* String denoting the type of change that this represents
*/
readonly type: string;
}
/**
* {@link RecordV2} structural delta.
*
* A RecordV2Delta describes the differences between two {@link RecordV2}
* values. Unlike a {@link BinaryDelta binary delta}, a structural delta
* can be queried to determine its effect. The
* {@link RecordV2Delta.changes} method provides details of which values
* have changed.
*
* An instance can be created from two RecordV2 values using
* {@link RecordV2.diff}.
*
* RecordV2Deltas are useful for identifying small changes to complex RecordV2
* values. Here is an example of how to use this class to filter interesting
* changes from a value stream.
*
* **Example:**
* ```
* var datatype = diffusion.datatypes.recordv2();
*
* session.addStream("topic", datatype).on('value', (path, spec, newValue, oldValue) => {
* var schema = datatype.parseSchema(spec.properties.SCHEMA);
*
* newValue.diff(oldValue).changes(schema).forEach((change) => {
* if (change.fieldName === "address") {
* // Do something with the changed address
* console.log(newValue.getFields());
* }
* });
* });
* ```
*
* @author DiffusionData Limited
* @since 6.0
* @see diffusion.datatypes.RecordV2.diff
*/
export interface RecordV2Delta extends Bytes {
/**
* Returns a list of the changes represented by the delta with reference to
* a specified schema.
*
* The schema supplied must comply with the data format of the delta. No
* validation takes place, so if the schema does not match the data then the
* results may be unpredictable.
*
* @param schema the schema
* @return the list of changes
* @throws an {@link SchemaViolationError} if the schema is not compatible with the delta
*/
changes(schema: Schema): Change[];
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* {@link RecordV2} data model.
*
* A read only model can be created from any {@link RecordV2} object using the
* {@link RecordV2.asModel asModel} method. The model then provides direct
* access to the fields within the data. Fields may be accessed either by
* explicitly specifying the record and field occurrence or by specifying a key
* of the form:
*
* ```
* recordName(recordIndex).fieldName(fieldIndex)
* ```
*
* Indexes start from 0 and if omitted then 0 is assumed. The record name may
* also be omitted, in which case the first record definition is accessed. This
* form of addressing is useful when there is only one record definition.
*
* So valid keys are:
*
* Key | Description
* ---------------------------| --------------------
* `Address(4).AddressLine(3)`| The 4th `AddressLine` occurrence within the 5th `Address` record
* `Address.Name` | The first (or only) `Name` field within the first (or only) `Address` record
* `AddressLine(1)` | The 2nd `AddressLine` field within the first (or only) record
* `Name` | The first (or only) `Name` field within the first (or only) record
*
* The {@link RecordModel.recordCount} and
* {@link RecordModel.fieldCount} methods are useful for
* determining the actual number of occurrences of variable multiplicity items.
*
* @since 6.0
*/
export interface RecordModel {
/**
* Get a field value.
*
* This allows an item to be addressed using a key of the form
* recordName(recordIndex).fieldName(fieldIndex). Indexes may be omitted in
* which case `0` is assumed.
*
* **Example:**
* ```
* // Get field value with record & field names and indices
* const value = model.get("record", 0, "field", 0);
*
* // Get field value with key
* const value = model.get("Address.Name");
* ```
*
* @param recordKey the key addressing the record
* @param recordName the name of the record
* @param recordIndex the index of the record
* @param fieldName the name of the field
* @param fieldIndex the index of the field
* @return the field value
*
* @throws an {@link IllegalArgumentError} if `recordName` can not be parsed
* @throws an {@link OutOfBoundsError} if `recordIndex` or `fieldIndex` is out of range
* @throws an {@link SchemaViolationError} if a record or field was requested that
* does not exist in the schema
*/
get(recordName: string, recordIndex: number, fieldName: string, fieldIndex?: number): string | null;
get(recordName: string, fieldName: string, fieldIndex?: number): string | null;
get(recordKey: string): string | null;
/**
* Creates an immutable {@link RecordV2} object
* generated from the model.
*
* @return a new immutable instance
*/
asValue(): RecordV2;
/**
* Returns the actual number of occurrences of a named field within a
* specified record.
*
* For all but variable fields this simply returns the schema defined number
* of occurrences of the field.
*
* @param recordName the record name
* @param recordIndex the record index
* @param fieldName the field name
* @return the actual number of occurrences of the field
*
* @throws an {@link SchemaViolationError} if a record or field was requested that
* does not exist in the schema
*/
fieldCount(recordName: string, recordIndex?: number, fieldName?: string): number;
/**
* Returns the actual number of occurrences of a named record.
*
* If the record is not variable, this is the same as the defined number of
* occurrences in the schema
*
* @param recordName the record name
* @return the actual number of occurrences of the record
*/
recordCount(recordName: string): number;
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* An immutable value representing a list of records.
*
* See {@link RecordV2DataType} for details
*
* @since 6.0
*/
export interface RecordV2 extends Bytes {
/**
* Compare this value with an earlier version to calculate a structural
* delta.
*
* @param original the original value to compare with this value
* @return a structural delta representing the difference between
* the original and this value
*/
diff(original: RecordV2): RecordV2Delta;
/**
* Parses the content into a model based upon a specified schema.
*
* This assumes that data is compatible with the schema and does not do any
* validation. There is no need to validate the data if this has been done
* on entry or at the server. However, if the data is invalid then issues
* may occur when attempting to access it.
*
* If it is not certain that the data is valid then the {@link
* asValidatedModel} method may be used instead.
*
* @param schema the schema to use for parsing the data
* @return an immutable model derived from the data content
*/
asModel(schema: Schema): RecordModel;
/**
* Parses the content into a model based upon a specified schema.
*
* The data is validated against the schema
*
* @param schema the schema to use for parsing the data
* @return an immutable model derived from the data content
*
* @throws an {@link InvalidDataError} if the model data is found to be invalid when validated against the schema
*/
asValidatedModel(schema: Schema): RecordModel;
/**
* Returns the data content as an Array of Arrays of strings.
*
* **Example:**
* ```
* // Iterate across each record's fields
* value.asRecords().forEach((record) => {
* record.forEach((field) => {
* console.log("Field value: " + field);
* });
* });
* ```
*
* @return a new mutable list where each entry represents a record within the data
*/
asRecords(): string[][];
/**
* Returns the data content as a list of fields.
*
* This disregards record boundaries. If there is more than one record, they
* are concatenated to produce a list of all of the fields.
*
* This method would normally only be used when it is known that there is
* only one record.
*
* @return a new mutable list of all the fields
*/
asFields(): string[];
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* Used to build an immutable {@link Schema}.
*
* A schema defines the records and fields that may occur in a {@link RecordV2} topic
* value.
*
* The schema must declare at least one record type and every record must have
* at least one field type declared.
*
* Every record type and field type has a 'multiplicity' which defines the
* number of times that the record or field may occur within the data.
* Multiplicity is specified as a 'minimum' and 'maximum' number of occurrences
* or where the minimum and maximum are the same (fixed multiplicity) then the
* multiplicity may be specified as a single 'occurs' value. If the minimum and
* maximum are different, this is referred to a 'variable' multiplicity. Only
* the last record declared or the last field within a record may have variable
* multiplicity. The maximum value may be declared as -1 to indicate that the
* record or field can have an unlimited number of occurrences.
*
* The builder is used to add a record definition followed by the fields within
* it. After all fields have been added to a record another may then be added,
* and so on, and then finally {@link SchemaBuilder.build build()} is called to create
* an immutable schema object.
*
* Every call returns the builder instance allowing calls to be chained, for
* example:
*
* ```
* const schema = builder.record('R1').string('S1').string('S2', 1, 5)
* .record('R2', 0, -1).decimal('D', 5).build();
* ```
*
* A builder is obtained using the {@link RecordV2DataType.schemaBuilder}
* method.
*
* @since 6.0
*/
export interface SchemaBuilder {
/**
* Add a new record to the schema
*
* The record added must not have the same name as a previously added record.
*
* A record may not be added after a record that has variable multiplicity (min != max)
*
* A record may not be added directly after another record which has had no fields added.
*
* @param name record name. This must not the same as any record already added
* @param min=1 the minimum number of times the record should occur within the schema
* @param max=1 the maximum number of times the record should occur within the schema.
* May be either `-1` (indicating no upper limit) or a
* positive value that is not less than * `min`
* @return the builder instance
*
* @throws a {@link SchemaViolationError} if the record name or multiplicity is invalid
*/
record(name: string, min?: number, max?: number): SchemaBuilder;
/**
* Add a string field to the current record.
*
* A field may not be added after a field that has variable multiplicity (min != max)
*
* @param name field name. This must not the same as any field already added
* @param min=1 the minimum number of times the field should occur within the record
* @param max=1 the maximum number of times the field should occur within the record.
* May be either `-1` (indicating no upper limit) or a
* positive value that is not less than * `min`
*
* @throws a {@link SchemaViolationError} if the field name or multiplicity is invalid
*
*/
string(name: string, min?: number, max?: number): SchemaBuilder;
/**
* Add an integer field to the current record.
*
* A field may not be added after a field that has variable multiplicity (min != max)
*
* @param name field name. This must not the same as any field already added
* @param min=1 the minimum number of times the field should occur within the record
* @param max=1 the maximum number of times the field should occur within the record.
* May be either `-1` (indicating no upper limit) or a
* positive value that is not less than * `min`
*
* @throws a {@link SchemaViolationError} if the field name or multiplicity is invalid
*/
integer(name: string, min?: number, max?: number): SchemaBuilder;
/**
* Add a decimal field to the current record.
*
* A field may not be added after a field that has variable multiplicity (min != max)
*
* @param name field name. This must not the same as any field already added
* @param scale the scale of the field (number of decimal places). This must be strictly positive.
* @param min=1 the minimum number of times the field should occur within the record
* @param max=1 the maximum number of times the field should occur within the record.
* May be either `-1` (indicating no upper limit) or a
* positive value that is not less than * `min`
*
* @throws a {@link SchemaViolationError} if the field name or multiplicity is invalid
*/
decimal(name: string, scale: number, min?: number, max?: number): SchemaBuilder;
/**
* Build an immutable Schema.
*
* At least one record with at least one field must have been added to the
* builder.
*
* @return a new immutable schema object representing the current state of
* the builder
*
* @throws a {@link SchemaViolationError} if no records have been added to the schema.
*/
build(): Schema;
}
/**
* @module diffusion.datatypes.RecordV2
*/
/**
* A Node in the schema definition
*/
export interface Node {
/**
* The node name
*/
name: string;
/**
* The minimum number of occurrences of the node within its parent
*/
min: number;
/**
* The maximum number of occurrences of the node within its parent
*/
max: number;
/**
* Flag that indicates if the node has variable multiplicity, or has fixed
* multiplicity
*/
isVariable: boolean;
}
/**
* A field node in the schema definition
*/
export interface Field extends Node {
/**
* An optional scale definition for decimal field types
*/
scale?: number;
}
/**
* A record node in the schema definition
*/
export interface Record extends Node {
/**
* A list of the field definitions. There will be at least one
*/
fields: Field[];
}
/**
* A {@link RecordV2} schema.
*
* A schema describes data value format in terms of one or more record definitions.
* A record definition describes the layout of a record and comprises one or more
* field definitions.
*
* Within the data value there can be multiple occurrences of a record or
* field described by a single definition. The defined (or allowed, when
* describing variable numbers) number of occurrences of each definition is
* referred to as its 'multiplicity'. The multiplicity can be fixed (the item
* occurs a fixed number of times), or variable (the item occurs from a minimum
* number of times to a maximum number of times). If a variable field is used it
* must be the last in a record definition and if a variable record is used it
* must be the last in the schema definition.
*
* A field may be defined as of type 'string', 'integer' or 'decimal'. A decimal
* type has a further property of 'scale' which defines the number of digits to
* the right of the decimal point.
*
* A schema can be obtained from {@link RecordV2DataType.parseSchema} or from a
* {@link SchemaBuilder}
*
* @since 6.0
*/
export interface Schema {
/**
* Returns an immutable, ordered list of record definitions.
*
* There will be at least one.
*
* @return a list of the record definitions in the schema
*/
getRecords(): Record[];
/**
* Returns the schema in a JSON format
*
* @return schema in JSON format
*/
asJSON(): any;
/**
* Create a mutable model based upon the schema.
*
* The model will be created with all mandatory record occurrences and all
* mandatory field occurrences initialized to default values.
*
* Such a model may be mutated and used to generate updated
* {@link RecordV2} occurrences for updating purposes.
*
* @return a new initialized model
*/
createMutableModel(): MutableRecordModel;
}
export as namespace diffusion;