@salesforce/core
Version:
Core libraries to interact with SFDX projects, orgs, and APIs.
319 lines (318 loc) • 11.4 kB
TypeScript
/// <reference types="node" />
import { EventEmitter } from 'events';
import { AsyncOptionalCreatable, Duration, Env } from '@salesforce/kit/lib';
import { AnyFunction, AnyJson, JsonMap } from '@salesforce/ts-types/lib';
import { Org } from '../org';
import { StatusResult } from './client';
/**
* Types for defining extensions.
*/
export interface StreamingExtension {
/**
* Extension for outgoing message.
*
* @param message The message.
* @param callback The callback to invoke after the message is processed.
*/
outgoing?: (message: JsonMap, callback: AnyFunction) => void;
/**
* Extension for the incoming message.
*
* @param message The message.
* @param callback The callback to invoke after the message is processed.
*/
incoming?: (message: JsonMap, callback: AnyFunction) => void;
}
/**
* Function type for processing messages
*/
export declare type StreamProcessor = (message: JsonMap) => StatusResult;
/**
* Comet client interface. The is to allow for mocking the inner streaming Cometd implementation.
* The Faye implementation is used by default but it could be used to adapt another Cometd impl.
*/
export declare abstract class CometClient extends EventEmitter {
/**
* Disable polling features.
*
* @param label Polling feature label.
*/
abstract disable(label: string): void;
/**
* Add a custom extension to the underlying client.
*
* @param extension The json function for the extension.
*/
abstract addExtension(extension: StreamingExtension): void;
/**
* Sets an http header name/value.
*
* @param name The header name.
* @param value The header value.
*/
abstract setHeader(name: string, value: string): void;
/**
* handshake with the streaming channel
*
* @param callback Callback for the handshake when it successfully completes. The handshake should throw
* errors when errors are encountered.
*/
abstract handshake(callback: () => void): void;
/**
* Subscribes to Comet topics. Subscribe should perform a handshake if one hasn't been performed yet.
*
* @param channel The topic to subscribe to.
* @param callback The callback to execute once a message has been received.
*/
abstract subscribe(channel: string, callback: (message: JsonMap) => void): CometSubscription;
/**
* Method to call to disconnect the client from the server.
*/
abstract disconnect(): void;
}
/**
* Inner streaming client interface. This implements the Cometd behavior.
* Also allows for mocking the functional behavior.
*/
export interface StreamingClientIfc {
/**
* Returns a comet client implementation.
*
* @param url The target url of the streaming service endpoint.
*/
getCometClient: (url: string) => CometClient;
/**
* Sets the logger function for the CometClient.
*
* @param logLine A log message passed to the the assigned function.
*/
setLogger: (logLine: (message: string) => void) => void;
}
/**
* The subscription object returned from the cometd subscribe object.
*/
export interface CometSubscription {
callback(callback: () => void): void;
errback(callback: (error: Error) => void): void;
}
/**
* Api wrapper to support Salesforce streaming. The client contains an internal implementation of a cometd specification.
*
* Salesforce client and timeout information
*
* Streaming API imposes two timeouts, as supported in the Bayeux protocol.
*
* Socket timeout: 110 seconds
* A client receives events (JSON-formatted HTTP responses) while it waits on a connection. If no events are generated
* and the client is still waiting, the connection times out after 110 seconds and the server closes the connection.
* Clients should reconnect before two minutes to avoid the connection timeout.
*
* Reconnect timeout: 40 seconds
* After receiving the events, a client needs to reconnect to receive the next set of events. If the reconnection
* doesn't happen within 40 seconds, the server expires the subscription and the connection is closed. If this happens,
* the client must start again and handshake, subscribe, and connect. Each Streaming API client logs into an instance
* and maintains a session. When the client handshakes, connects, or subscribes, the session timeout is restarted. A
* client session times out if the client doesn’t reconnect to the server within 40 seconds after receiving a response
* (an event, subscribe result, and so on).
*
* Note that these timeouts apply to the Streaming API client session and not the Salesforce authentication session. If
* the client session times out, the authentication session remains active until the organization-specific timeout
* policy goes into effect.
*
* ```
* const streamProcessor = (message: JsonMap): StatusResult => {
* const payload = ensureJsonMap(message.payload);
* const id = ensureString(payload.id);
*
* if (payload.status !== 'Active') {
* return { completed: false };
* }
*
* return {
* completed: true,
* payload: id
* };
* };
*
* const org = await Org.create({});
* const options = new StreamingClient.DefaultOptions(org, 'MyPushTopics', streamProcessor);
*
* const asyncStatusClient = await StreamingClient.create(options);
*
* await asyncStatusClient.handshake();
*
* const info: RequestInfo = {
* method: 'POST',
* url: `${org.getField(OrgFields.INSTANCE_URL)}/SomeService`,
* headers: { HEADER: 'HEADER_VALUE'},
* body: 'My content'
* };
*
* await asyncStatusClient.subscribe(async () => {
* const connection = await org.getConnection();
* // Now that we are subscribed, we can initiate the request that will cause the events to start streaming.
* const requestResponse: JsonCollection = await connection.request(info);
* const id = ensureJsonMap(requestResponse).id;
* console.log(`this.id: ${JSON.stringify(ensureString(id), null, 4)}`);
* });
* ```
*/
export declare class StreamingClient extends AsyncOptionalCreatable<StreamingClient.Options> {
private readonly targetUrl;
private readonly options;
private logger;
private cometClient;
/**
* Constructor
*
* @param options Streaming client options
* {@link AsyncCreatable.create}
*/
constructor(options?: StreamingClient.Options);
/**
* Asynchronous initializer.
*/
init(): Promise<void>;
/**
* Allows replaying of of Streaming events starting with replayId.
*
* @param replayId The starting message id to replay from.
*/
replay(replayId: number): void;
/**
* Provides a convenient way to handshake with the server endpoint before trying to subscribe.
*/
handshake(): Promise<StreamingClient.ConnectionState>;
/**
* Subscribe to streaming events. When the streaming processor that's set in the options completes execution it
* returns a payload in the StatusResult object. The payload is just echoed here for convenience.
*
* **Throws** *{@link SfdxError}{ name: '{@link StreamingClient.TimeoutErrorType.SUBSCRIBE}'}* When the subscribe timeout occurs.
*
* @param streamInit This function should call the platform apis that result in streaming updates on push topics.
* {@link StatusResult}
*/
subscribe(streamInit?: () => Promise<void>): Promise<AnyJson | void>;
/**
* Handler for incoming streaming messages.
*
* @param message The message to process.
* @param cb The callback. Failure to call this can cause the internal comet client to hang.
*/
private incoming;
private doTimeout;
private disconnectClient;
private disconnect;
/**
* Simple inner log wrapper
*
* @param message The message to log
*/
private log;
}
export declare namespace StreamingClient {
/**
* Options for the StreamingClient
*
* @interface
*/
interface Options {
/**
* The org streaming target.
*/
org: Org;
/**
* The hard timeout that happens with subscribe
*/
subscribeTimeout: Duration;
/**
* The hard timeout that happens with a handshake.
*/
handshakeTimeout: Duration;
/**
* The streaming channel aka topic
*/
channel: string;
/**
* The salesforce api version
*/
apiVersion: string;
/**
* The function for processing streaming messages
*/
streamProcessor: StreamProcessor;
/**
* The function for build the inner client impl. Allows for mocking.
*/
streamingImpl: StreamingClientIfc;
}
/**
* Default Streaming Options. Uses Faye as the cometd impl.
*/
class DefaultOptions implements StreamingClient.Options {
static readonly SFDX_ENABLE_FAYE_COOKIES_ALLOW_ALL_PATHS = "SFDX_ENABLE_FAYE_REQUEST_RESPONSE_LOGGING";
static readonly SFDX_ENABLE_FAYE_REQUEST_RESPONSE_LOGGING = "SFDX_ENABLE_FAYE_REQUEST_RESPONSE_LOGGING";
static readonly DEFAULT_SUBSCRIBE_TIMEOUT: Duration;
static readonly DEFAULT_HANDSHAKE_TIMEOUT: Duration;
apiVersion: string;
org: Org;
streamProcessor: StreamProcessor;
subscribeTimeout: Duration;
handshakeTimeout: Duration;
channel: string;
streamingImpl: StreamingClientIfc;
/**
* Constructor for DefaultStreamingOptions
*
* @param org The streaming target org
* @param channel The streaming channel or topic. If the topic is a system topic then api 36.0 is used.
* System topics are deprecated.
* @param streamProcessor The function called that can process streaming messages.
* @param envDep
* @see {@link StatusResult}
*/
constructor(org: Org, channel: string, streamProcessor: StreamProcessor, envDep?: Env);
/**
* Setter for the subscribe timeout.
*
* **Throws** An error if the newTime is less than the default time.
*
* @param newTime The new subscribe timeout.
* {@link DefaultOptions.DEFAULT_SUBSCRIBE_TIMEOUT}
*/
setSubscribeTimeout(newTime: Duration): void;
/**
* Setter for the handshake timeout.
*
* **Throws** An error if the newTime is less than the default time.
*
* @param newTime The new handshake timeout
* {@link DefaultOptions.DEFAULT_HANDSHAKE_TIMEOUT}
*/
setHandshakeTimeout(newTime: Duration): void;
}
/**
* Connection state
*
* @see {@link StreamingClient.handshake}
*/
enum ConnectionState {
/**
* Used to indicated that the streaming client is connected.
*/
CONNECTED = 0
}
/**
* Indicators to test error names for StreamingTimeouts
*/
enum TimeoutErrorType {
/**
* To indicate the error occurred on handshake
*/
HANDSHAKE = "genericHandshakeTimeoutMessage",
/**
* To indicate the error occurred on subscribe
*/
SUBSCRIBE = "genericTimeoutMessage"
}
}