@elliemae/pui-websocket-so 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.html +758 -0
- package/dist/cjs/index.js +24 -0
- package/dist/cjs/messageRouter.js +111 -0
- package/dist/cjs/package.json +7 -0
- package/dist/cjs/subscriptionManager.js +224 -0
- package/dist/cjs/types.js +16 -0
- package/dist/cjs/websocketSO.js +338 -0
- package/dist/esm/index.html +758 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/messageRouter.js +91 -0
- package/dist/esm/package.json +7 -0
- package/dist/esm/subscriptionManager.js +204 -0
- package/dist/esm/types.js +0 -0
- package/dist/esm/websocketSO.js +318 -0
- package/dist/public/guest.html +523 -0
- package/dist/public/index.html +1 -0
- package/dist/public/js/emuiWebsocketSo.cc1f5b5e1d095fc3a34e.js +3 -0
- package/dist/public/js/emuiWebsocketSo.cc1f5b5e1d095fc3a34e.js.br +0 -0
- package/dist/public/js/emuiWebsocketSo.cc1f5b5e1d095fc3a34e.js.gz +0 -0
- package/dist/public/js/emuiWebsocketSo.cc1f5b5e1d095fc3a34e.js.map +1 -0
- package/dist/types/lib/index.d.ts +2 -0
- package/dist/types/lib/messageRouter.d.ts +30 -0
- package/dist/types/lib/subscriptionManager.d.ts +101 -0
- package/dist/types/lib/tests/messageRouter.test.d.ts +1 -0
- package/dist/types/lib/tests/subscriptionManager.test.d.ts +1 -0
- package/dist/types/lib/tests/websocketSO.test.d.ts +1 -0
- package/dist/types/lib/types.d.ts +118 -0
- package/dist/types/lib/websocketSO.d.ts +56 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/dist/umd/guest.html +523 -0
- package/dist/umd/index.html +1 -0
- package/dist/umd/index.js +3 -0
- package/dist/umd/index.js.br +0 -0
- package/dist/umd/index.js.gz +0 -0
- package/dist/umd/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"js/emuiWebsocketSo.cc1f5b5e1d095fc3a34e.js","mappings":"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","sources":["webpack://emuiWebsocketSo/webpack/universalModuleDefinition","webpack://emuiWebsocketSo/webpack/bootstrap","webpack://emuiWebsocketSo/webpack/runtime/define property getters","webpack://emuiWebsocketSo/webpack/runtime/hasOwnProperty shorthand","webpack://emuiWebsocketSo/webpack/runtime/make namespace object","webpack://emuiWebsocketSo/../../node_modules/.pnpm/@elliemae+microfe-common@2.24.0_@elliemae+pui-diagnostics@3.12.1_uuid@9.0.1/node_modules/@elliemae/microfe-common/dist/esm/event.js","webpack://emuiWebsocketSo/../../node_modules/.pnpm/@elliemae+microfe-common@2.24.0_@elliemae+pui-diagnostics@3.12.1_uuid@9.0.1/node_modules/@elliemae/microfe-common/dist/esm/scriptingObject.js","webpack://emuiWebsocketSo/../wsclient/dist/esm/types.js","webpack://emuiWebsocketSo/../wsclient/dist/esm/client.js","webpack://emuiWebsocketSo/./lib/subscriptionManager.ts","webpack://emuiWebsocketSo/./lib/messageRouter.ts","webpack://emuiWebsocketSo/./lib/websocketSO.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"emuiWebsocketSo\"] = factory();\n\telse\n\t\troot[\"emuiWebsocketSo\"] = factory();\n})(globalThis, () => {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","class Event {\n /* eslint-enable indent */\n /**\n * name of the event\n */\n name;\n /**\n * scripting object id that owns this event\n */\n objectId;\n /**\n * unique id of the event\n */\n id;\n /**\n * Create an event object\n * @param {EventParam} param - parameters for creating an event\n */\n constructor(param) {\n const { name, objectId } = param;\n if (!name) throw new Error(\"Event name is required\");\n if (!objectId) throw new Error(\"Scripting object id is required\");\n this.objectId = objectId;\n this.name = name;\n this.id = `${this.objectId}.${this.name}`.toLowerCase();\n }\n}\nclass ProxyEvent {\n /**\n * check if given object is an instance of ProxyEvent\n * @param obj object to be compared\n * @returns true if given object is an instance of ProxyEvent\n */\n static [Symbol.hasInstance](obj) {\n return typeof obj === \"object\" && obj !== null && \"getType\" in obj && typeof obj.getType === \"function\" && obj.getType() === \"ProxyEvent\";\n }\n /* eslint-enable indent */\n /**\n * module that owns this event management. SSF Guest or App Bridge host\n */\n #eventSrc;\n /**\n * unique id of scripting object\n */\n objectId;\n /**\n * name of the event\n */\n name;\n /**\n * unique id of the event\n */\n id;\n /**\n * get type of the object\n * @returns type of the object\n */\n getType() {\n return \"ProxyEvent\";\n }\n /**\n * Create a new instance of the Scripting Object Proxy Event\n * @param {ProxyEventParam} param - parameter for the constructor\n */\n constructor(param) {\n const { name, objectId, eventSrc } = param;\n if (!name) throw new Error(\"Event name is required\");\n if (!objectId) throw new Error(\"Scripting object id is required\");\n if (!eventSrc) throw new Error(\"Event source is required\");\n this.objectId = objectId;\n this.name = name;\n this.#eventSrc = eventSrc;\n this.id = `${this.objectId}.${this.name}`.toLowerCase();\n }\n /**\n * subscribe to an scripting object event\n * @param callback event listener\n * @returns subscription token\n */\n subscribe = (callback) => this.#eventSrc.subscribe({\n eventId: this.id,\n callback\n });\n /**\n * unsubscribe from an scripting object event\n * @param token subscription token\n */\n unsubscribe = (token) => {\n this.#eventSrc.unsubscribe({\n eventId: this.id,\n token\n });\n };\n}\nconst isEvent = (value) => value instanceof Event;\nconst getEventId = (objectId, eventName) => `${objectId.toLowerCase()}.${eventName.toLowerCase()}`;\nexport {\n Event,\n ProxyEvent,\n getEventId,\n isEvent\n};\n","import { isEvent } from \"./event.js\";\nconst FUNCTION = \"function\";\nconst isPublicFunction = (value, fnName) => typeof value === FUNCTION && !!fnName && !fnName.startsWith(\"_\");\nclass ScriptingObject {\n /**\n * unique id of the scripting object\n */\n #id;\n /**\n * type of the scripting object\n */\n #objectType = \"Object\";\n /**\n * Creates an instance of ScriptingObject.\n * @param objectId unique id of the scripting object\n * @param objectType type of the scripting object\n */\n constructor(objectId, objectType) {\n this.#id = objectId;\n this.#objectType = objectType || this.#objectType;\n }\n /**\n * get unique id of the scripting object\n */\n get id() {\n return this.#id;\n }\n /**\n * get type of the scripting object\n */\n get objectType() {\n return this.#objectType;\n }\n /**\n * transform the scripting object to a format suitable for transmitting over window.postMessage\n * @returns marshalled scripting object\n */\n // eslint-disable-next-line no-underscore-dangle\n _toJSON = () => {\n const functions = [];\n const events = [];\n Object.keys(this).forEach((property) => {\n const value = this[property];\n if (isEvent(value)) {\n events.push(property);\n } else if (isPublicFunction(value, property)) {\n functions.push(property);\n }\n });\n return {\n objectId: this.#id,\n objectType: this.#objectType,\n functions,\n events\n };\n };\n /**\n * dispose the scripting object\n */\n // eslint-disable-next-line no-underscore-dangle\n _dispose = () => {\n };\n /**\n * dispose the scripting object\n */\n dispose = () => {\n };\n}\nexport {\n ScriptingObject,\n isPublicFunction\n};\n","var WSContentType = /* @__PURE__ */ ((WSContentType2) => {\n WSContentType2[\"JSON\"] = \"application/json\";\n WSContentType2[\"BINARY\"] = \"application/octet-stream\";\n WSContentType2[\"RAW\"] = \"\";\n return WSContentType2;\n})(WSContentType || {});\nvar ReadyState = /* @__PURE__ */ ((ReadyState2) => {\n ReadyState2[ReadyState2[\"UNINSTANTIATED\"] = -1] = \"UNINSTANTIATED\";\n ReadyState2[ReadyState2[\"CONNECTING\"] = 0] = \"CONNECTING\";\n ReadyState2[ReadyState2[\"OPEN\"] = 1] = \"OPEN\";\n ReadyState2[ReadyState2[\"CLOSING\"] = 2] = \"CLOSING\";\n ReadyState2[ReadyState2[\"CLOSED\"] = 3] = \"CLOSED\";\n return ReadyState2;\n})(ReadyState || {});\nexport {\n ReadyState,\n WSContentType\n};\n","import {\n WSContentType\n} from \"./types.js\";\nconst RETRY_TIME_INTERVAL = 1 * 60 * 60;\nconst MAX_RETRY = 5;\nclass WSClient {\n /**\n * reference to WebSocket instance\n */\n #socket = null;\n /**\n * reference to existing ui platform logger instance\n */\n #logger;\n /**\n * type of messages transferred. Default: `application/json`\n */\n #contentType = WSContentType.JSON;\n /**\n * time interval between retries to connect to server\n */\n #retryTimeInterval = RETRY_TIME_INTERVAL;\n /**\n * maximum number of retries to connect to server\n */\n #maxRetry = MAX_RETRY;\n /**\n * url of WebSocket server. Example: `wss://api.elliemae.io/`\n */\n #url;\n /**\n * opaque token to authenticate with PSS\n */\n #token;\n /**\n * callback to handle messages received from server\n */\n #onMessage;\n /**\n * callback to handle errors\n */\n #onError;\n /**\n * callback to handle connection open\n */\n #onOpen;\n /**\n * Creates instance of WSClient\n * @param {Options} options options for connecting to websocket server\n * @returns instance of WSClient\n */\n constructor({\n url,\n token,\n logger,\n contentType = WSContentType.JSON,\n onMessage,\n onError\n }) {\n if (!url) throw new Error(\"url is required\");\n if (!token) throw new Error(\"token is required\");\n if (!logger) throw new Error(\"logger is required\");\n this.#logger = logger;\n this.#contentType = contentType;\n this.#onMessage = onMessage;\n this.#url = url;\n this.#token = token;\n this.#onError = onError;\n }\n /**\n * Handles connection to server\n */\n #handleOpen = () => {\n this.#logger.debug(`Connected to ${this.#url}`);\n setTimeout(() => {\n this.#onOpen?.();\n }, 0);\n };\n /**\n * Handles disconnection from server\n * @param reject\n * @param closeEvent close event received from server\n */\n #onClose = (reject, closeEvent) => {\n const { code, reason } = closeEvent;\n if (`${code}`.startsWith(\"4\") && code !== 4408) {\n this.#logger.error(\n `Connection to ${this.#url} closed with code ${code} and reason ${reason}`\n );\n setTimeout(() => {\n this.#onError?.(new Error(reason));\n }, 0);\n reject(new Error(reason));\n return;\n }\n if (this.#maxRetry <= 0) {\n this.#logger.error(\n `Unable to connect to ${this.#url}. Reason: ${reason}. Max retries reached`\n );\n setTimeout(() => {\n this.#onError?.(\n new Error(`Unable to connect to ${this.#url}. Reason: ${reason}`)\n );\n }, 0);\n return;\n }\n setTimeout(() => {\n this.open().catch(() => {\n });\n this.#maxRetry -= 1;\n this.#retryTimeInterval += this.#retryTimeInterval;\n }, this.#retryTimeInterval);\n };\n /**\n * handles messages received from server\n * @param event message received from server\n */\n #handleMessage = (event) => {\n let message;\n switch (this.#contentType) {\n case WSContentType.JSON:\n try {\n message = JSON.parse(event.data);\n } catch (err) {\n this.#logger.error(\n `Error parsing message: ${err.message}. Received message is not a valid JSON`\n );\n }\n break;\n default:\n message = event.data;\n break;\n }\n setTimeout(() => {\n try {\n this.#onMessage(message);\n } catch (err) {\n this.#logger.debug(\n `User message handler throws error: ${err.message}`\n );\n }\n }, 0);\n };\n /**\n * returns ready state of WebSocket client\n * @returns ready state of WebSocket client\n */\n get readyState() {\n return this.#socket?.readyState;\n }\n /**\n * sets callback to handle connection open\n * @param callback callback to handle connection open\n */\n set onOpen(callback) {\n this.#onOpen = callback;\n }\n // eslint-disable-next-line jsdoc/require-returns-check\n /**\n * Opens connection to WebSocket server\n * @returns Promise that resolves when connection is established\n * @throws Error if connection cannot be established or parameters are invalid\n */\n open = () => new Promise((resolve, reject) => {\n const authToken = `auth--${this.#token}`;\n this.#socket = new WebSocket(this.#url, [authToken]);\n this.#socket.onopen = () => {\n this.#handleOpen();\n resolve();\n };\n this.#socket.onerror = () => {\n this.#logger.error(\n `Error connecting to websocket server at ${this.#url}`\n );\n };\n this.#socket.onclose = this.#onClose.bind(this, reject);\n this.#socket.onmessage = this.#handleMessage;\n });\n /**\n * Closes connection to WebSocket server\n */\n close = () => {\n this.#retryTimeInterval = RETRY_TIME_INTERVAL;\n if (this.#socket) {\n this.#socket.onclose = null;\n this.#socket.onmessage = null;\n this.#socket.onerror = null;\n this.#socket.onopen = null;\n this.#socket.close();\n this.#socket = null;\n }\n };\n /**\n * sends message to server\n * @param data message to send to server\n * @returns Promise that resolves when message is sent\n * @throws Error if connection is not open or message is not serializable as JSON\n */\n send = (data) => new Promise((resolve, reject) => {\n if (!this.#socket) {\n reject(new Error(\"Connection is not open\"));\n return;\n }\n switch (this.#contentType) {\n case WSContentType.JSON:\n try {\n const message = JSON.stringify(data);\n this.#socket.send(message);\n resolve();\n } catch (err) {\n const errMessage = `Error sending message: ${err.message}. Message is not serializable as JSON`;\n this.#logger.error(errMessage);\n reject(new Error(errMessage));\n }\n break;\n default:\n this.#socket.send(data);\n resolve();\n break;\n }\n });\n}\nexport {\n WSClient\n};\n","import { PendingRequest, Subscription } from './types.js';\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * Manages active WebSocket subscriptions and pending command requests.\n *\n * Pending requests are correlated by correlationId and resolved/rejected\n * when the server responds with an ack or error.\n *\n * Active subscriptions are tracked by subscriptionId for event routing\n * and cleanup on unsubscribe. Each subscription stores the guestId of\n * the guest that created it so events can be dispatched to the right guest.\n */\nexport class SubscriptionManager {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #pendingRequests = new Map<string, PendingRequest<any>>();\n\n #subscriptions = new Map<string, Subscription>();\n\n /** Reverse index: composite lookup key → subscriptionId for O(1) duplicate detection. */\n #keyIndex = new Map<string, string>();\n\n #requestTimeoutMs: number;\n\n /**\n * @param {number} [requestTimeoutMs=30000] - timeout in ms before a pending request is auto-rejected\n */\n constructor(requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {\n this.#requestTimeoutMs = requestTimeoutMs;\n }\n\n /**\n * Register a pending request that will be resolved/rejected when the\n * server responds with a message matching the given correlationId.\n * @param {string} correlationId - unique id correlating request to response\n * @param {Function} resolve - callback invoked on success\n * @param {Function} reject - callback invoked on failure or timeout\n */\n addPendingRequest<T>(\n correlationId: string,\n resolve: (value: T) => void,\n reject: (error: Error) => void,\n ): void {\n const existing = this.#pendingRequests.get(correlationId);\n if (existing) {\n clearTimeout(existing.timeoutId);\n existing.reject(\n new Error(`Pending request replaced (correlationId: ${correlationId})`),\n );\n }\n\n const timeoutId = setTimeout(() => {\n this.#pendingRequests.delete(correlationId);\n reject(\n new Error(\n `Request timed out after ${\n this.#requestTimeoutMs\n }ms (correlationId: ${correlationId})`,\n ),\n );\n }, this.#requestTimeoutMs);\n\n this.#pendingRequests.set(correlationId, { resolve, reject, timeoutId });\n }\n\n /**\n * Resolve a pending request with a successful result.\n * @param {string} correlationId - unique id of the pending request\n * @param {*} value - the value to resolve with\n * @returns {boolean} true if the request was found and resolved\n */\n resolvePendingRequest<T>(correlationId: string, value: T): boolean {\n const pending = this.#pendingRequests.get(correlationId);\n if (!pending) return false;\n clearTimeout(pending.timeoutId);\n this.#pendingRequests.delete(correlationId);\n pending.resolve(value);\n return true;\n }\n\n /**\n * Reject a pending request with an error.\n * @param {string} correlationId - unique id of the pending request\n * @param {Error} error - the error to reject with\n * @returns {boolean} true if the request was found and rejected\n */\n rejectPendingRequest(correlationId: string, error: Error): boolean {\n const pending = this.#pendingRequests.get(correlationId);\n if (!pending) return false;\n clearTimeout(pending.timeoutId);\n this.#pendingRequests.delete(correlationId);\n pending.reject(error);\n return true;\n }\n\n /**\n * Find an existing subscription matching the given resource criteria and guest.\n * Uses a secondary key index for O(1) lookup.\n * @param {Omit<Subscription, 'subscriptionId' | 'refCount'>} criteria - fields to match\n * @returns {Subscription | undefined} matching subscription or undefined\n */\n findExistingSubscription(\n criteria: Omit<Subscription, 'subscriptionId' | 'refCount'>,\n ): Subscription | undefined {\n const key = SubscriptionManager.#buildLookupKey(criteria);\n const subscriptionId = this.#keyIndex.get(key);\n if (!subscriptionId) return undefined;\n return this.#subscriptions.get(subscriptionId);\n }\n\n /**\n * Register a new active subscription. Initialises refCount to 1.\n * @param {Omit<Subscription, 'refCount'>} subscription - subscription data (refCount is set internally)\n */\n addSubscription(subscription: Omit<Subscription, 'refCount'>): void {\n const entry: Subscription = {\n ...subscription,\n filter: subscription.filter\n ? (JSON.parse(JSON.stringify(subscription.filter)) as Record<\n string,\n string[]\n >)\n : undefined,\n refCount: 1,\n };\n this.#subscriptions.set(subscription.subscriptionId, entry);\n this.#keyIndex.set(\n SubscriptionManager.#buildLookupKey(entry),\n subscription.subscriptionId,\n );\n }\n\n /**\n * Increment the reference count for an existing subscription.\n * @param {string} subscriptionId - subscription to increment\n * @returns {number} the new refCount, or -1 if the subscription was not found\n */\n incrementRefCount(subscriptionId: string): number {\n const sub = this.#subscriptions.get(subscriptionId);\n if (!sub) return -1;\n sub.refCount += 1;\n return sub.refCount;\n }\n\n /**\n * Decrement the reference count and remove when it reaches 0.\n * @param {string} subscriptionId - subscription to decrement\n * @returns {number} the new refCount (0 means removed), or -1 if not found\n */\n decrementRefCount(subscriptionId: string): number {\n const sub = this.#subscriptions.get(subscriptionId);\n if (!sub) return -1;\n sub.refCount -= 1;\n if (sub.refCount <= 0) {\n this.#keyIndex.delete(SubscriptionManager.#buildLookupKey(sub));\n this.#subscriptions.delete(subscriptionId);\n return 0;\n }\n return sub.refCount;\n }\n\n /**\n * Unconditionally remove a subscription regardless of refCount.\n * Used during reconnection to replace old entries.\n * @param {string} subscriptionId - subscription to remove\n * @returns {boolean} true if the subscription existed and was removed\n */\n removeSubscription(subscriptionId: string): boolean {\n const sub = this.#subscriptions.get(subscriptionId);\n if (sub) {\n this.#keyIndex.delete(SubscriptionManager.#buildLookupKey(sub));\n }\n return this.#subscriptions.delete(subscriptionId);\n }\n\n /**\n * Retrieve subscription metadata by id.\n * @param {string} subscriptionId - subscription to look up\n * @returns {Subscription | undefined} the subscription, or undefined if not found\n */\n getSubscription(subscriptionId: string): Subscription | undefined {\n return this.#subscriptions.get(subscriptionId);\n }\n\n /**\n * Check whether a subscription is currently active.\n * @param {string} subscriptionId - subscription to check\n * @returns {boolean} true if the subscription exists\n */\n hasSubscription(subscriptionId: string): boolean {\n return this.#subscriptions.has(subscriptionId);\n }\n\n /**\n * Returns all active subscriptions.\n * Used for re-subscribing after a reconnection.\n * @returns {Subscription[]} array of active subscriptions\n */\n getAllSubscriptions(): Subscription[] {\n return Array.from(this.#subscriptions.values());\n }\n\n /**\n * Clean up all pending requests and subscriptions.\n * Rejects any outstanding pending requests.\n */\n dispose(): void {\n this.#pendingRequests.forEach((pending) => {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error('WebSocket scripting object disposed'));\n });\n this.#pendingRequests.clear();\n this.#subscriptions.clear();\n this.#keyIndex.clear();\n }\n\n /**\n * Compute the canonical lookup key for a set of subscription criteria.\n * Exposed so callers can track in-flight subscribes by the same key.\n * @param {Omit<Subscription, 'subscriptionId' | 'refCount'>} criteria - subscription fields\n * @returns {string} composite lookup key\n */\n static buildLookupKey(\n criteria: Omit<Subscription, 'subscriptionId' | 'refCount'>,\n ): string {\n return SubscriptionManager.#buildLookupKey(criteria);\n }\n\n /**\n * Builds a canonical composite key for O(1) subscription lookup.\n * Uses NUL (\\0) as separator to avoid collisions with real values.\n * Filter keys are sorted for order-independent comparison.\n * @param {Pick<Subscription, 'guestId' | 'resource' | 'resourceId' | 'filter'>} sub - subscription fields\n * @returns {string} composite lookup key\n */\n static #buildLookupKey(\n sub: Pick<Subscription, 'guestId' | 'resource' | 'resourceId' | 'filter'>,\n ): string {\n const { guestId, resource, resourceId, filter } = sub;\n if (resourceId != null) {\n return `${guestId}\\0${resource}\\0rid:${resourceId}`;\n }\n if (filter != null) {\n const sortedKeys = Object.keys(filter).sort();\n const canonical = sortedKeys\n .map((k) => `${k}=${filter[k].join(',')}`)\n .join('&');\n return `${guestId}\\0${resource}\\0f:${canonical}`;\n }\n return `${guestId}\\0${resource}`;\n }\n}\n","import { Logger } from '@elliemae/pui-diagnostics';\nimport { SubscriptionManager } from './subscriptionManager.js';\nimport {\n ServerMessage,\n SubscribeAck,\n UnsubscribeAck,\n ServerError,\n EventMessage,\n Subscription,\n} from './types.js';\n\n/**\n * Callback invoked when a server event message matches an active subscription.\n * Includes the full Subscription (with guestId) so the caller can\n * dispatch to the correct guest.\n */\nexport type EventCallback = (\n event: EventMessage,\n subscription: Subscription,\n) => void;\n\n/**\n * Routes incoming WebSocket server messages to the appropriate handler:\n * - subscribe_ack / unsubscribe_ack → resolves the pending request\n * - error → rejects the pending request\n * - event → forwards to the event callback with the owning subscription\n */\nexport class MessageRouter {\n #subscriptionManager: SubscriptionManager;\n\n #onEvent: EventCallback;\n\n #logger: Logger;\n\n /**\n * @param {SubscriptionManager} subscriptionManager - manages pending requests and active subscriptions\n * @param {EventCallback} onEvent - callback invoked when a server event matches an active subscription\n * @param {Logger} logger - logger instance for debug/error output\n */\n constructor(\n subscriptionManager: SubscriptionManager,\n onEvent: EventCallback,\n logger: Logger,\n ) {\n this.#subscriptionManager = subscriptionManager;\n this.#onEvent = onEvent;\n this.#logger = logger;\n }\n\n /**\n * Entry point for all messages received from the WebSocket server.\n * Dispatches to the correct handler based on message type.\n * @param {ServerMessage} message - incoming server message\n */\n handleMessage = (message: ServerMessage): void => {\n switch (message.type) {\n case 'subscribe_ack':\n this.#handleSubscribeAck(message);\n break;\n case 'unsubscribe_ack':\n this.#handleUnsubscribeAck(message);\n break;\n case 'error':\n this.#handleError(message);\n break;\n case 'event':\n this.#handleEvent(message);\n break;\n default:\n this.#logger.debug(\n `Unknown message type received: ${\n (message as unknown as { type: string }).type\n }`,\n );\n }\n };\n\n #handleSubscribeAck(message: SubscribeAck): void {\n const { correlationId, subscriptionId } = message;\n const resolved = this.#subscriptionManager.resolvePendingRequest(\n correlationId,\n { subscriptionId },\n );\n if (!resolved) {\n this.#logger.debug(\n `Received subscribe_ack for unknown correlationId: ${correlationId}`,\n );\n }\n }\n\n #handleUnsubscribeAck(message: UnsubscribeAck): void {\n const { correlationId } = message;\n const resolved = this.#subscriptionManager.resolvePendingRequest(\n correlationId,\n undefined,\n );\n if (!resolved) {\n this.#logger.debug(\n `Received unsubscribe_ack for unknown correlationId: ${correlationId}`,\n );\n }\n }\n\n #handleError(message: ServerError): void {\n const { correlationId, errors } = message;\n const errorMessages = errors\n .map((e) => `${e.code}: ${e.message}`)\n .join('; ');\n const rejected = this.#subscriptionManager.rejectPendingRequest(\n correlationId,\n new Error(errorMessages),\n );\n if (!rejected) {\n this.#logger.debug(\n `Received error for unknown correlationId: ${correlationId}. Errors: ${errorMessages}`,\n );\n }\n }\n\n #handleEvent(message: EventMessage): void {\n const { subscriptionId } = message;\n const subscription =\n this.#subscriptionManager.getSubscription(subscriptionId);\n if (!subscription) {\n this.#logger.debug(\n `Received event for unknown subscriptionId: ${subscriptionId}`,\n );\n return;\n }\n this.#onEvent(message, subscription);\n }\n}\n","/* eslint-disable max-lines */\nimport { ScriptingObject, Event } from '@elliemae/ssf-host';\nimport { Logger } from '@elliemae/pui-diagnostics';\nimport {\n IWebSocket,\n SubscribeOptions,\n SubscribeResult,\n} from '@elliemae/pui-scripting-object';\nimport { WSClient, WSContentType, OutgoingMsg } from '@elliemae/pui-wsclient';\nimport { SubscriptionManager } from './subscriptionManager.js';\nimport { MessageRouter } from './messageRouter.js';\nimport {\n ClientMessage,\n ServerMessage,\n SubscribeCommand,\n UnsubscribeCommand,\n EventMessage,\n Subscription,\n MicroFEHost,\n WebSocketSOOptions,\n} from './types.js';\n\nconst SCRIPTING_OBJECT_NAME = 'websocket';\nconst EVENT_NAME = 'message';\nconst EVENT_ID = `${SCRIPTING_OBJECT_NAME}.${EVENT_NAME}`;\n\n/**\n * WebSocket scripting object implementation.\n *\n * The microapp host creates an instance of this class and registers it\n * with the SSF Host or App Bridge. Guest microapps interact with the\n * WebSocket server through subscribe/unsubscribe methods.\n *\n * This SO owns the WSClient lifecycle — it creates the connection\n * internally and routes incoming server messages to the correct guest.\n */\nexport class WebSocketSO extends ScriptingObject implements IWebSocket {\n #client: WSClient;\n\n #logger: Logger;\n\n #host: MicroFEHost;\n\n #subscriptionManager: SubscriptionManager;\n\n #messageRouter: MessageRouter;\n\n #isOpen = false;\n\n /**\n * Tracks in-flight subscribe promises keyed by lookup key.\n * Prevents concurrent identical subscribes from creating duplicate\n * server-side subscriptions.\n */\n #pendingSubscribes = new Map<string, Promise<SubscribeResult>>();\n\n /** Event dispatched to subscribed guests when the server sends an event message. */\n readonly Message = new Event({\n name: EVENT_NAME,\n objectId: SCRIPTING_OBJECT_NAME,\n });\n\n /**\n * Creates a new WebSocket scripting object.\n * @param {WebSocketSOOptions} options - configuration options\n */\n constructor({ logger, host, url, token, onError }: WebSocketSOOptions) {\n super(SCRIPTING_OBJECT_NAME);\n if (!logger) throw new Error('logger is required');\n if (!host) throw new Error('host is required');\n if (!url) throw new Error('url is required');\n if (!token) throw new Error('token is required');\n\n this.#logger = logger;\n this.#host = host;\n this.#subscriptionManager = new SubscriptionManager();\n this.#messageRouter = new MessageRouter(\n this.#subscriptionManager,\n this.#handleEvent,\n this.#logger,\n );\n\n this.#client = new WSClient({\n url,\n token,\n logger,\n contentType: WSContentType.JSON,\n onMessage: (message) => {\n this.#messageRouter.handleMessage(message as unknown as ServerMessage);\n },\n onError,\n });\n\n this.#client.onOpen = this.#handleReconnect;\n\n // Hide host-only lifecycle methods from guest proxies.\n // Both SSF Host (_toJSON) and App Bridge use Object.keys() which\n // only returns enumerable properties; non-enumerable methods are\n // invisible to guests but still callable by the host app directly.\n Object.defineProperty(this, 'open', { enumerable: false });\n Object.defineProperty(this, 'close', { enumerable: false });\n }\n\n /**\n * Opens the WebSocket connection to the server.\n * Must be called before guests can subscribe. Idempotent — calling\n * while already open is a no-op.\n * @returns {Promise<void>} promise that resolves when the connection is established\n */\n open = async (): Promise<void> => {\n if (this.#isOpen) return;\n await this.#client.open();\n this.#isOpen = true;\n };\n\n /**\n * Closes the WebSocket connection and cleans up all subscriptions.\n * Idempotent — calling while already closed is a no-op.\n */\n close = (): void => {\n if (!this.#isOpen) return;\n this.#isOpen = false;\n this.#pendingSubscribes.clear();\n this.#client.close();\n this.#subscriptionManager.dispose();\n };\n\n /**\n * Validates subscribe preconditions and returns the guestId + destructured options.\n * @param {SubscribeOptions} options - subscribe options to validate\n * @returns {{ guestId: string; resource: string; resourceId?: string; filter?: Record<string, string[]> }} validated fields\n * @throws {Error} if any validation fails\n */\n #validateSubscribe = (\n options: SubscribeOptions,\n ): {\n guestId: string;\n resource: string;\n resourceId?: string;\n filter?: Record<string, string[]>;\n } => {\n const guestId = this.subscribe.callContext?.guest?.id;\n if (!guestId) {\n throw new Error('unable to identify calling guest from callContext');\n }\n if (!this.#isOpen) {\n throw new Error('WebSocket connection is not open. Call open() first.');\n }\n const { resource, resourceId, filter } = options;\n if (!resource) {\n throw new Error('resource is required');\n }\n if (!resourceId && !filter) {\n throw new Error('either resourceId or filter must be provided');\n }\n return { guestId, resource, resourceId, filter };\n };\n\n /**\n * Subscribe to a WebSocket resource on behalf of the calling guest.\n * If an identical subscription already exists for this guest, returns\n * the existing subscriptionId and increments the reference count.\n * @param {SubscribeOptions} options - resource, resourceId or filter\n * @returns {Promise<SubscribeResult>} resolves with the subscriptionId\n */\n subscribe = (options: SubscribeOptions): Promise<SubscribeResult> => {\n let validated;\n try {\n validated = this.#validateSubscribe(options);\n } catch (err) {\n return Promise.reject(err);\n }\n const { guestId, resource, resourceId, filter } = validated;\n const criteria = { resource, guestId, resourceId, filter };\n\n const existing =\n this.#subscriptionManager.findExistingSubscription(criteria);\n if (existing) {\n this.#subscriptionManager.incrementRefCount(existing.subscriptionId);\n return Promise.resolve({ subscriptionId: existing.subscriptionId });\n }\n\n const lookupKey = SubscriptionManager.buildLookupKey(criteria);\n const inflight = this.#pendingSubscribes.get(lookupKey);\n if (inflight) {\n return inflight.then((result) => {\n this.#subscriptionManager.incrementRefCount(result.subscriptionId);\n return result;\n });\n }\n\n return this.#sendSubscribeCommand(criteria, lookupKey);\n };\n\n /**\n * Sends the subscribe command to the server and tracks the in-flight promise.\n * @param {Omit<Subscription, 'subscriptionId' | 'refCount'>} criteria - subscription criteria\n * @param {string} lookupKey - key for in-flight dedup\n * @returns {Promise<SubscribeResult>} resolves with the subscriptionId\n */\n #sendSubscribeCommand = (\n criteria: Omit<Subscription, 'subscriptionId' | 'refCount'>,\n lookupKey: string,\n ): Promise<SubscribeResult> => {\n const { guestId, resource, resourceId, filter } = criteria;\n const correlationId = crypto.randomUUID();\n const command: SubscribeCommand = {\n type: 'subscribe',\n correlationId,\n resource,\n ...(resourceId != null && { resourceId }),\n ...(filter != null && { filter }),\n };\n\n const promise = new Promise<SubscribeResult>((resolve, reject) => {\n this.#subscriptionManager.addPendingRequest<SubscribeResult>(\n correlationId,\n (result) => {\n this.#subscriptionManager.addSubscription({\n subscriptionId: result.subscriptionId,\n resource,\n guestId,\n resourceId,\n filter,\n });\n this.#logger.debug(\n `Guest ${guestId} subscribed to ${resource} with subscriptionId: ${result.subscriptionId}`,\n );\n resolve(result);\n },\n reject,\n );\n\n this.#sendCommand(command).catch((err: Error) => {\n this.#subscriptionManager.rejectPendingRequest(correlationId, err);\n });\n });\n\n this.#pendingSubscribes.set(lookupKey, promise);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n promise\n .finally(() => this.#pendingSubscribes.delete(lookupKey))\n .catch(() => {});\n\n return promise;\n };\n\n /**\n * Unsubscribe from an active subscription. Decrements the reference\n * count; the server-side unsubscribe is only sent when the last\n * consumer releases the subscription.\n * @param {string} subscriptionId - id of the subscription to release\n * @returns {Promise<void>} resolves when the unsubscribe completes\n */\n unsubscribe = (subscriptionId: string): Promise<void> => {\n if (!subscriptionId) {\n return Promise.reject(new Error('subscriptionId is required'));\n }\n\n if (!this.#isOpen) {\n return Promise.reject(\n new Error('WebSocket connection is not open. Call open() first.'),\n );\n }\n\n const guestId = this.unsubscribe.callContext?.guest?.id;\n if (!guestId) {\n return Promise.reject(\n new Error('unable to identify calling guest from callContext'),\n );\n }\n\n const subscription =\n this.#subscriptionManager.getSubscription(subscriptionId);\n if (!subscription || subscription.guestId !== guestId) {\n return Promise.reject(\n new Error(\n `subscription ${subscriptionId} is not available for this guest`,\n ),\n );\n }\n\n const remaining =\n this.#subscriptionManager.decrementRefCount(subscriptionId);\n if (remaining > 0) {\n this.#logger.debug(\n `Decremented refCount for ${subscriptionId} to ${remaining}`,\n );\n return Promise.resolve();\n }\n\n const correlationId = crypto.randomUUID();\n const command: UnsubscribeCommand = {\n type: 'unsubscribe',\n correlationId,\n subscriptionId,\n };\n\n return new Promise<void>((resolve, reject) => {\n this.#subscriptionManager.addPendingRequest<void>(\n correlationId,\n () => {\n this.#logger.debug(\n `Unsubscribed from subscriptionId: ${subscriptionId}`,\n );\n resolve();\n },\n reject,\n );\n\n this.#sendCommand(command).catch((err: Error) => {\n this.#subscriptionManager.rejectPendingRequest(correlationId, err);\n });\n });\n };\n\n /**\n * Sends a command to the WebSocket server via the underlying WSClient.\n * @param {ClientMessage} command - subscribe or unsubscribe command\n * @returns {Promise<void>} resolves when the message is sent\n */\n #sendCommand = (command: ClientMessage): Promise<void> =>\n this.#client.send(command as unknown as OutgoingMsg);\n\n /**\n * Re-subscribes all active subscriptions after a WSClient reconnection.\n * Server-side subscription state is lost on disconnect, so we must\n * re-establish them.\n */\n #handleReconnect = (): void => {\n const subscriptions = this.#subscriptionManager.getAllSubscriptions();\n if (subscriptions.length === 0) return;\n\n this.#logger.debug(\n `WebSocket reconnected — re-subscribing ${subscriptions.length} subscription(s)`,\n );\n\n subscriptions.forEach((sub) => {\n const correlationId = crypto.randomUUID();\n const command: SubscribeCommand = {\n type: 'subscribe',\n correlationId,\n resource: sub.resource,\n ...(sub.resourceId != null && { resourceId: sub.resourceId }),\n ...(sub.filter != null && { filter: sub.filter }),\n };\n\n this.#subscriptionManager.addPendingRequest<SubscribeResult>(\n correlationId,\n (result) => {\n this.#subscriptionManager.removeSubscription(sub.subscriptionId);\n this.#subscriptionManager.addSubscription({\n ...sub,\n subscriptionId: result.subscriptionId,\n });\n this.#logger.debug(\n `Re-subscribed guest ${sub.guestId} to ${sub.resource}: ${sub.subscriptionId} → ${result.subscriptionId}`,\n );\n },\n (err: Error) => {\n this.#subscriptionManager.removeSubscription(sub.subscriptionId);\n this.#logger.error(\n `Failed to re-subscribe guest ${sub.guestId} to ${sub.resource}: ${err.message}. Subscription removed.`,\n );\n },\n );\n\n this.#sendCommand(command).catch((err: Error) => {\n this.#subscriptionManager.rejectPendingRequest(correlationId, err);\n });\n });\n };\n\n /**\n * Dispatches a server event to the owning guest via the host's dispatchEvent.\n * @param {EventMessage} event - the server event message\n * @param {Subscription} subscription - the matching subscription with guestId\n */\n #handleEvent = (event: EventMessage, subscription: Subscription): void => {\n const eventParams = {\n subscriptionId: event.subscriptionId,\n resource: event.resource,\n payload: event.payload,\n };\n\n this.#host\n .dispatchEvent({\n event: { id: EVENT_ID, name: EVENT_NAME },\n eventParams,\n eventOptions: { guestId: subscription.guestId },\n })\n .catch((err: Error) => {\n this.#logger.error(\n `Failed to dispatch event to guest ${subscription.guestId}: ${err.message}`,\n );\n });\n };\n\n /**\n * Lifecycle hook called by the host framework when the SO is removed.\n * Closes the WebSocket connection and cleans up all state.\n */\n // eslint-disable-next-line no-underscore-dangle\n _dispose = (): void => {\n this.close();\n };\n}\n"],"names":["root","factory","__webpack_require__","exports","definition","key","obj","prop","Event","param","name","objectId","ProxyEvent","#eventSrc","eventSrc","callback","token","isEvent","value","getEventId","eventName","FUNCTION","isPublicFunction","fnName","ScriptingObject","#id","#objectType","objectType","functions","events","property","WSContentType","WSContentType2","ReadyState","ReadyState2","RETRY_TIME_INTERVAL","MAX_RETRY","WSClient","#socket","#logger","#contentType","#retryTimeInterval","#maxRetry","#url","#token","#onMessage","#onError","#onOpen","url","logger","contentType","onMessage","onError","#handleOpen","#onClose","reject","closeEvent","code","reason","#handleMessage","event","message","err","resolve","authToken","data","errMessage","DEFAULT_REQUEST_TIMEOUT_MS","SubscriptionManager","#pendingRequests","#subscriptions","#keyIndex","#requestTimeoutMs","requestTimeoutMs","correlationId","existing","timeoutId","pending","error","criteria","#buildLookupKey","subscriptionId","subscription","entry","sub","guestId","resource","resourceId","filter","canonical","k","MessageRouter","#subscriptionManager","#onEvent","subscriptionManager","onEvent","#handleSubscribeAck","#handleUnsubscribeAck","#handleError","#handleEvent","errors","errorMessages","e","SCRIPTING_OBJECT_NAME","EVENT_NAME","EVENT_ID","WebSocketSO","#client","#host","#messageRouter","#isOpen","#pendingSubscribes","host","#handleReconnect","#validateSubscribe","options","validated","lookupKey","inflight","result","#sendSubscribeCommand","command","promise","#sendCommand","remaining","subscriptions","eventParams"],"sourceRoot":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Logger } from '@elliemae/pui-diagnostics';
|
|
2
|
+
import { SubscriptionManager } from './subscriptionManager.js';
|
|
3
|
+
import { ServerMessage, EventMessage, Subscription } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Callback invoked when a server event message matches an active subscription.
|
|
6
|
+
* Includes the full Subscription (with guestId) so the caller can
|
|
7
|
+
* dispatch to the correct guest.
|
|
8
|
+
*/
|
|
9
|
+
export type EventCallback = (event: EventMessage, subscription: Subscription) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Routes incoming WebSocket server messages to the appropriate handler:
|
|
12
|
+
* - subscribe_ack / unsubscribe_ack → resolves the pending request
|
|
13
|
+
* - error → rejects the pending request
|
|
14
|
+
* - event → forwards to the event callback with the owning subscription
|
|
15
|
+
*/
|
|
16
|
+
export declare class MessageRouter {
|
|
17
|
+
#private;
|
|
18
|
+
/**
|
|
19
|
+
* @param {SubscriptionManager} subscriptionManager - manages pending requests and active subscriptions
|
|
20
|
+
* @param {EventCallback} onEvent - callback invoked when a server event matches an active subscription
|
|
21
|
+
* @param {Logger} logger - logger instance for debug/error output
|
|
22
|
+
*/
|
|
23
|
+
constructor(subscriptionManager: SubscriptionManager, onEvent: EventCallback, logger: Logger);
|
|
24
|
+
/**
|
|
25
|
+
* Entry point for all messages received from the WebSocket server.
|
|
26
|
+
* Dispatches to the correct handler based on message type.
|
|
27
|
+
* @param {ServerMessage} message - incoming server message
|
|
28
|
+
*/
|
|
29
|
+
handleMessage: (message: ServerMessage) => void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Subscription } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Manages active WebSocket subscriptions and pending command requests.
|
|
4
|
+
*
|
|
5
|
+
* Pending requests are correlated by correlationId and resolved/rejected
|
|
6
|
+
* when the server responds with an ack or error.
|
|
7
|
+
*
|
|
8
|
+
* Active subscriptions are tracked by subscriptionId for event routing
|
|
9
|
+
* and cleanup on unsubscribe. Each subscription stores the guestId of
|
|
10
|
+
* the guest that created it so events can be dispatched to the right guest.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SubscriptionManager {
|
|
13
|
+
#private;
|
|
14
|
+
/**
|
|
15
|
+
* @param {number} [requestTimeoutMs=30000] - timeout in ms before a pending request is auto-rejected
|
|
16
|
+
*/
|
|
17
|
+
constructor(requestTimeoutMs?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Register a pending request that will be resolved/rejected when the
|
|
20
|
+
* server responds with a message matching the given correlationId.
|
|
21
|
+
* @param {string} correlationId - unique id correlating request to response
|
|
22
|
+
* @param {Function} resolve - callback invoked on success
|
|
23
|
+
* @param {Function} reject - callback invoked on failure or timeout
|
|
24
|
+
*/
|
|
25
|
+
addPendingRequest<T>(correlationId: string, resolve: (value: T) => void, reject: (error: Error) => void): void;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a pending request with a successful result.
|
|
28
|
+
* @param {string} correlationId - unique id of the pending request
|
|
29
|
+
* @param {*} value - the value to resolve with
|
|
30
|
+
* @returns {boolean} true if the request was found and resolved
|
|
31
|
+
*/
|
|
32
|
+
resolvePendingRequest<T>(correlationId: string, value: T): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Reject a pending request with an error.
|
|
35
|
+
* @param {string} correlationId - unique id of the pending request
|
|
36
|
+
* @param {Error} error - the error to reject with
|
|
37
|
+
* @returns {boolean} true if the request was found and rejected
|
|
38
|
+
*/
|
|
39
|
+
rejectPendingRequest(correlationId: string, error: Error): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Find an existing subscription matching the given resource criteria and guest.
|
|
42
|
+
* Uses a secondary key index for O(1) lookup.
|
|
43
|
+
* @param {Omit<Subscription, 'subscriptionId' | 'refCount'>} criteria - fields to match
|
|
44
|
+
* @returns {Subscription | undefined} matching subscription or undefined
|
|
45
|
+
*/
|
|
46
|
+
findExistingSubscription(criteria: Omit<Subscription, 'subscriptionId' | 'refCount'>): Subscription | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Register a new active subscription. Initialises refCount to 1.
|
|
49
|
+
* @param {Omit<Subscription, 'refCount'>} subscription - subscription data (refCount is set internally)
|
|
50
|
+
*/
|
|
51
|
+
addSubscription(subscription: Omit<Subscription, 'refCount'>): void;
|
|
52
|
+
/**
|
|
53
|
+
* Increment the reference count for an existing subscription.
|
|
54
|
+
* @param {string} subscriptionId - subscription to increment
|
|
55
|
+
* @returns {number} the new refCount, or -1 if the subscription was not found
|
|
56
|
+
*/
|
|
57
|
+
incrementRefCount(subscriptionId: string): number;
|
|
58
|
+
/**
|
|
59
|
+
* Decrement the reference count and remove when it reaches 0.
|
|
60
|
+
* @param {string} subscriptionId - subscription to decrement
|
|
61
|
+
* @returns {number} the new refCount (0 means removed), or -1 if not found
|
|
62
|
+
*/
|
|
63
|
+
decrementRefCount(subscriptionId: string): number;
|
|
64
|
+
/**
|
|
65
|
+
* Unconditionally remove a subscription regardless of refCount.
|
|
66
|
+
* Used during reconnection to replace old entries.
|
|
67
|
+
* @param {string} subscriptionId - subscription to remove
|
|
68
|
+
* @returns {boolean} true if the subscription existed and was removed
|
|
69
|
+
*/
|
|
70
|
+
removeSubscription(subscriptionId: string): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Retrieve subscription metadata by id.
|
|
73
|
+
* @param {string} subscriptionId - subscription to look up
|
|
74
|
+
* @returns {Subscription | undefined} the subscription, or undefined if not found
|
|
75
|
+
*/
|
|
76
|
+
getSubscription(subscriptionId: string): Subscription | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Check whether a subscription is currently active.
|
|
79
|
+
* @param {string} subscriptionId - subscription to check
|
|
80
|
+
* @returns {boolean} true if the subscription exists
|
|
81
|
+
*/
|
|
82
|
+
hasSubscription(subscriptionId: string): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Returns all active subscriptions.
|
|
85
|
+
* Used for re-subscribing after a reconnection.
|
|
86
|
+
* @returns {Subscription[]} array of active subscriptions
|
|
87
|
+
*/
|
|
88
|
+
getAllSubscriptions(): Subscription[];
|
|
89
|
+
/**
|
|
90
|
+
* Clean up all pending requests and subscriptions.
|
|
91
|
+
* Rejects any outstanding pending requests.
|
|
92
|
+
*/
|
|
93
|
+
dispose(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Compute the canonical lookup key for a set of subscription criteria.
|
|
96
|
+
* Exposed so callers can track in-flight subscribes by the same key.
|
|
97
|
+
* @param {Omit<Subscription, 'subscriptionId' | 'refCount'>} criteria - subscription fields
|
|
98
|
+
* @returns {string} composite lookup key
|
|
99
|
+
*/
|
|
100
|
+
static buildLookupKey(criteria: Omit<Subscription, 'subscriptionId' | 'refCount'>): string;
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Logger } from '@elliemae/pui-diagnostics';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal host interface satisfied by both SSFHost and AppBridge.
|
|
4
|
+
*
|
|
5
|
+
* Both frameworks expose `dispatchEvent` with the same signature.
|
|
6
|
+
* The WebSocket SO only needs this method to push events to guests.
|
|
7
|
+
*/
|
|
8
|
+
export type MicroFEHost = {
|
|
9
|
+
dispatchEvent: (params: {
|
|
10
|
+
event: {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
eventParams: Record<string, unknown>;
|
|
15
|
+
eventOptions?: {
|
|
16
|
+
guestId?: string;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
};
|
|
19
|
+
}) => Promise<unknown[] | void>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Options for creating the WebSocket scripting object
|
|
23
|
+
*/
|
|
24
|
+
export type WebSocketSOOptions = {
|
|
25
|
+
/**
|
|
26
|
+
* Reference to existing UI Platform logger instance.
|
|
27
|
+
*/
|
|
28
|
+
logger: Logger;
|
|
29
|
+
/**
|
|
30
|
+
* SSFHost or AppBridge instance.
|
|
31
|
+
* Used to dispatch events to specific guest microapps.
|
|
32
|
+
*/
|
|
33
|
+
host: MicroFEHost;
|
|
34
|
+
/**
|
|
35
|
+
* URL of the WebSocket server.
|
|
36
|
+
* @example 'wss://api.elliemae.io/encompass/v1/stream'
|
|
37
|
+
*/
|
|
38
|
+
url: string;
|
|
39
|
+
/**
|
|
40
|
+
* Opaque access token used to authenticate with PSS.
|
|
41
|
+
*/
|
|
42
|
+
token: string;
|
|
43
|
+
/**
|
|
44
|
+
* Optional callback invoked when the WebSocket connection encounters an error.
|
|
45
|
+
*/
|
|
46
|
+
onError?: (error: Error) => void;
|
|
47
|
+
};
|
|
48
|
+
/** Command sent by a guest to subscribe to a WebSocket resource. */
|
|
49
|
+
export type SubscribeCommand = {
|
|
50
|
+
type: 'subscribe';
|
|
51
|
+
correlationId: string;
|
|
52
|
+
resource: string;
|
|
53
|
+
resourceId?: string;
|
|
54
|
+
filter?: Record<string, string[]>;
|
|
55
|
+
};
|
|
56
|
+
/** Command sent by a guest to unsubscribe from an active subscription. */
|
|
57
|
+
export type UnsubscribeCommand = {
|
|
58
|
+
type: 'unsubscribe';
|
|
59
|
+
correlationId: string;
|
|
60
|
+
subscriptionId: string;
|
|
61
|
+
};
|
|
62
|
+
/** Union of all client-to-server command messages. */
|
|
63
|
+
export type ClientMessage = SubscribeCommand | UnsubscribeCommand;
|
|
64
|
+
/** Server acknowledgement of a successful subscribe. */
|
|
65
|
+
export type SubscribeAck = {
|
|
66
|
+
type: 'subscribe_ack';
|
|
67
|
+
correlationId: string;
|
|
68
|
+
subscriptionId: string;
|
|
69
|
+
};
|
|
70
|
+
/** Server acknowledgement of a successful unsubscribe. */
|
|
71
|
+
export type UnsubscribeAck = {
|
|
72
|
+
type: 'unsubscribe_ack';
|
|
73
|
+
correlationId: string;
|
|
74
|
+
};
|
|
75
|
+
/** Server error response for a failed command. */
|
|
76
|
+
export type ServerError = {
|
|
77
|
+
type: 'error';
|
|
78
|
+
correlationId: string;
|
|
79
|
+
errors: Array<{
|
|
80
|
+
code: string;
|
|
81
|
+
message: string;
|
|
82
|
+
}>;
|
|
83
|
+
};
|
|
84
|
+
/** Server-pushed event message for an active subscription. */
|
|
85
|
+
export type EventMessage = {
|
|
86
|
+
type: 'event';
|
|
87
|
+
correlationId: string;
|
|
88
|
+
subscriptionId: string;
|
|
89
|
+
resource: string;
|
|
90
|
+
payload: Record<string, unknown>;
|
|
91
|
+
};
|
|
92
|
+
/** Union of all server-to-client response messages. */
|
|
93
|
+
export type ServerMessage = SubscribeAck | UnsubscribeAck | ServerError | EventMessage;
|
|
94
|
+
/** Tracks an in-flight request awaiting a correlated server response. */
|
|
95
|
+
export type PendingRequest<T> = {
|
|
96
|
+
resolve: (value: T) => void;
|
|
97
|
+
reject: (error: Error) => void;
|
|
98
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
99
|
+
};
|
|
100
|
+
/** Represents an active server-side subscription with client-side metadata. */
|
|
101
|
+
export type Subscription = {
|
|
102
|
+
subscriptionId: string;
|
|
103
|
+
resource: string;
|
|
104
|
+
resourceId?: string;
|
|
105
|
+
filter?: Record<string, string[]>;
|
|
106
|
+
/**
|
|
107
|
+
* Id of the guest that created this subscription.
|
|
108
|
+
* Used to dispatch incoming events only to the owning guest.
|
|
109
|
+
*/
|
|
110
|
+
guestId: string;
|
|
111
|
+
/**
|
|
112
|
+
* Number of active consumers sharing this subscription.
|
|
113
|
+
* In nested microapp hierarchies (Host → A → B), both A and B
|
|
114
|
+
* appear under the same guestId. Reference counting ensures
|
|
115
|
+
* the server subscription stays alive until all consumers unsubscribe.
|
|
116
|
+
*/
|
|
117
|
+
refCount: number;
|
|
118
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ScriptingObject, Event } from '@elliemae/ssf-host';
|
|
2
|
+
import { IWebSocket, SubscribeOptions, SubscribeResult } from '@elliemae/pui-scripting-object';
|
|
3
|
+
import { WebSocketSOOptions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* WebSocket scripting object implementation.
|
|
6
|
+
*
|
|
7
|
+
* The microapp host creates an instance of this class and registers it
|
|
8
|
+
* with the SSF Host or App Bridge. Guest microapps interact with the
|
|
9
|
+
* WebSocket server through subscribe/unsubscribe methods.
|
|
10
|
+
*
|
|
11
|
+
* This SO owns the WSClient lifecycle — it creates the connection
|
|
12
|
+
* internally and routes incoming server messages to the correct guest.
|
|
13
|
+
*/
|
|
14
|
+
export declare class WebSocketSO extends ScriptingObject implements IWebSocket {
|
|
15
|
+
#private;
|
|
16
|
+
/** Event dispatched to subscribed guests when the server sends an event message. */
|
|
17
|
+
readonly Message: Event<import("@elliemae/pui-scripting-object").Events>;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new WebSocket scripting object.
|
|
20
|
+
* @param {WebSocketSOOptions} options - configuration options
|
|
21
|
+
*/
|
|
22
|
+
constructor({ logger, host, url, token, onError }: WebSocketSOOptions);
|
|
23
|
+
/**
|
|
24
|
+
* Opens the WebSocket connection to the server.
|
|
25
|
+
* Must be called before guests can subscribe. Idempotent — calling
|
|
26
|
+
* while already open is a no-op.
|
|
27
|
+
* @returns {Promise<void>} promise that resolves when the connection is established
|
|
28
|
+
*/
|
|
29
|
+
open: () => Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Closes the WebSocket connection and cleans up all subscriptions.
|
|
32
|
+
* Idempotent — calling while already closed is a no-op.
|
|
33
|
+
*/
|
|
34
|
+
close: () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Subscribe to a WebSocket resource on behalf of the calling guest.
|
|
37
|
+
* If an identical subscription already exists for this guest, returns
|
|
38
|
+
* the existing subscriptionId and increments the reference count.
|
|
39
|
+
* @param {SubscribeOptions} options - resource, resourceId or filter
|
|
40
|
+
* @returns {Promise<SubscribeResult>} resolves with the subscriptionId
|
|
41
|
+
*/
|
|
42
|
+
subscribe: (options: SubscribeOptions) => Promise<SubscribeResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Unsubscribe from an active subscription. Decrements the reference
|
|
45
|
+
* count; the server-side unsubscribe is only sent when the last
|
|
46
|
+
* consumer releases the subscription.
|
|
47
|
+
* @param {string} subscriptionId - id of the subscription to release
|
|
48
|
+
* @returns {Promise<void>} resolves when the unsubscribe completes
|
|
49
|
+
*/
|
|
50
|
+
unsubscribe: (subscriptionId: string) => Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Lifecycle hook called by the host framework when the SO is removed.
|
|
53
|
+
* Closes the WebSocket connection and cleans up all state.
|
|
54
|
+
*/
|
|
55
|
+
_dispose: () => void;
|
|
56
|
+
}
|