@next-core/easyops-runtime 0.12.37 → 0.12.39

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.
@@ -69,7 +69,7 @@ class MessageDispatcher {
69
69
  });
70
70
  }
71
71
  onClose(listener) {
72
- (0, _classPrivateGetter2.default)(_MessageDispatcher_brand, this, _get_ms).onClose(listener);
72
+ return (0, _classPrivateGetter2.default)(_MessageDispatcher_brand, this, _get_ms).onClose(listener);
73
73
  }
74
74
  reset() {
75
75
  var _classPrivateFieldGet2;
@@ -99,7 +99,7 @@ function _subOrUnsub(type, channel, payload, stringifiedPayload) {
99
99
  };
100
100
  const promise = new Promise((resolve, reject) => {
101
101
  const identity = getIdentity(payload);
102
- (0, _classPrivateGetter2.default)(_MessageDispatcher_brand, this, _get_ms).onMessage(response => {
102
+ const disposeOnMessage = (0, _classPrivateGetter2.default)(_MessageDispatcher_brand, this, _get_ms).onMessage(response => {
103
103
  const isSuccess = response.event === (type === "sub" ? "TOPIC.SUB_SUCCESS" : "TOPIC.UNSUB_SUCCESS");
104
104
  const isFailed = response.event === (type === "sub" ? "TOPIC.SUB_FAILED" : "TOPIC.UNSUB_FAILED");
105
105
  if ((isSuccess || isFailed) &&
@@ -107,8 +107,22 @@ function _subOrUnsub(type, channel, payload, stringifiedPayload) {
107
107
  // JSON stringify.
108
108
  identity === getIdentity(response.payload)) {
109
109
  (isSuccess ? resolve : reject)(response);
110
+ disposeOnMessage();
111
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
112
+ disposeOnClose();
110
113
  }
111
114
  });
115
+ // istanbul ignore next: currently can't mock this
116
+ const disposeOnClose = (0, _classPrivateGetter2.default)(_MessageDispatcher_brand, this, _get_ms).onClose(() => {
117
+ // V2 will emit error callback for sub/unsub each time connect failed,
118
+ // while v3 will emit only once after retry limit exceeded.
119
+ // Keep the `EVENT.detail.retryCount` for compatibility.
120
+ reject({
121
+ retryCount: _MessageService.RETRY_LIMIT
122
+ });
123
+ disposeOnMessage();
124
+ disposeOnClose();
125
+ });
112
126
  (0, _classPrivateGetter2.default)(_MessageDispatcher_brand, this, _get_ms).send(request);
113
127
  });
114
128
  if (type === "sub") {
@@ -1 +1 @@
1
- {"version":3,"file":"MessageDispatcher.js","names":["_runtime","require","_lodash","_MessageService","_ms","WeakMap","_memoizedChannels","_channelPayloads","_MessageDispatcher_brand","WeakSet","MessageDispatcher","constructor","_classPrivateMethodInitSpec2","default","_classPrivateFieldInitSpec2","sub","Map","unsub","subscribe","channel","payload","stringifiedPayload","JSON","stringify","_assertClassBrand2","_subOrUnsub","call","unsubscribe","_classPrivateFieldGet3","get","msg","console","error","Promise","reject","Error","parse","result","delete","then","onMessage","listener","warned","_classPrivateGetter2","_get_ms","response","event","matchMessageChannel","message","onClose","reset","_classPrivateFieldGet2","clear","exports","_this","protocol","location","url","window","host","getBasePath","_classPrivateFieldSet2","MessageService","type","hit","request","promise","resolve","identity","getIdentity","isSuccess","isFailed","send","set","system","topic","responsePayload","includes","RegExp","replace","_m","p1","p2","escapeRegExp","test"],"sources":["../../../src/websocket/MessageDispatcher.ts"],"sourcesContent":["import { getBasePath } from \"@next-core/runtime\";\nimport { escapeRegExp } from \"lodash\";\nimport {\n MessageService,\n type MessageListener,\n CloseListener,\n} from \"./MessageService.js\";\n\ninterface MessageResponse {\n event:\n | \"TOPIC.SUB_SUCCESS\"\n | \"TOPIC.SUB_FAILED\"\n | \"TOPIC.UNSUB_SUCCESS\"\n | \"TOPIC.UNSUB_FAILED\"\n | \"MESSAGE.PUSH\";\n payload: MessagePayload;\n}\n\ninterface MessagePayload {\n source?: string;\n system: string;\n topic: string;\n message?: unknown;\n}\n\nexport class MessageDispatcher {\n #_ms: MessageService | undefined;\n #memoizedChannels = {\n sub: new Map<string, Promise<unknown>>(),\n unsub: new Map<string, Promise<unknown>>(),\n };\n #channelPayloads = new Map<string, string>();\n\n get #ms(): MessageService {\n if (!this.#_ms) {\n const protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const url = `${protocol}//${\n window.location.host\n }${getBasePath()}api/websocket_service/v1/ws`;\n this.#_ms = new MessageService(url);\n }\n return this.#_ms;\n }\n\n subscribe(channel: string, payload: MessagePayload): Promise<unknown> {\n const stringifiedPayload = JSON.stringify(payload);\n return this.#subOrUnsub(\"sub\", channel, payload, stringifiedPayload);\n }\n\n unsubscribe(channel: string): Promise<unknown> {\n const stringifiedPayload = this.#channelPayloads.get(channel);\n if (!stringifiedPayload) {\n const msg = `The message channel to unsubscribe \"${channel}\" is not found`;\n // eslint-disable-next-line no-console\n console.error(msg);\n return Promise.reject(new Error(msg));\n }\n\n const payload = JSON.parse(stringifiedPayload);\n const result = this.#subOrUnsub(\n \"unsub\",\n channel,\n payload,\n stringifiedPayload\n );\n\n this.#memoizedChannels.sub.delete(stringifiedPayload);\n\n result.then(() => {\n this.#channelPayloads.delete(channel);\n });\n\n return result;\n }\n\n onMessage(channel: string, listener: MessageListener): void {\n let stringifiedPayload = this.#channelPayloads.get(channel);\n let warned = false;\n\n this.#ms.onMessage<MessageResponse>((response) => {\n if (!stringifiedPayload) {\n stringifiedPayload = this.#channelPayloads.get(channel);\n }\n if (!stringifiedPayload) {\n if (!warned) {\n // eslint-disable-next-line no-console\n console.error(`Message channel: \"${channel}\" not found`);\n warned = true;\n }\n return;\n }\n if (\n response.event === \"MESSAGE.PUSH\" &&\n matchMessageChannel(stringifiedPayload, response.payload)\n ) {\n listener(response.payload.message);\n }\n });\n }\n\n onClose(listener: CloseListener): void {\n this.#ms.onClose(listener);\n }\n\n reset(): void {\n this.#memoizedChannels.sub.clear();\n this.#memoizedChannels.unsub.clear();\n this.#channelPayloads.clear();\n this.#_ms?.reset();\n }\n\n #subOrUnsub(\n type: \"sub\" | \"unsub\",\n channel: string,\n payload: MessagePayload,\n stringifiedPayload: string\n ): Promise<unknown> {\n const hit = this.#memoizedChannels[type].get(stringifiedPayload);\n if (hit) {\n return hit;\n }\n const request = {\n event: type === \"sub\" ? \"TOPIC.SUB\" : \"TOPIC.UNSUB\",\n payload,\n };\n const promise = new Promise((resolve, reject) => {\n const identity = getIdentity(payload);\n this.#ms.onMessage<MessageResponse>((response) => {\n const isSuccess =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_SUCCESS\" : \"TOPIC.UNSUB_SUCCESS\");\n const isFailed =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_FAILED\" : \"TOPIC.UNSUB_FAILED\");\n if (\n (isSuccess || isFailed) &&\n // Put this after event type checks, to prevent unnecessary\n // JSON stringify.\n identity === getIdentity(response.payload)\n ) {\n (isSuccess ? resolve : reject)(response);\n }\n });\n this.#ms.send(request);\n });\n\n if (type === \"sub\") {\n this.#channelPayloads.set(channel, stringifiedPayload);\n }\n this.#memoizedChannels[type].set(stringifiedPayload, promise);\n return promise;\n }\n}\n\nfunction getIdentity(payload: MessagePayload) {\n const { system, topic } = payload;\n return JSON.stringify({ system, topic });\n}\n\nfunction matchMessageChannel(\n stringifiedPayload: string,\n responsePayload: MessagePayload\n): boolean {\n const payload = JSON.parse(stringifiedPayload) as MessagePayload;\n return (\n payload.system === responsePayload.system &&\n // Exact match\n (payload.topic === responsePayload.topic ||\n // Wildcards match\n // For `ab.cd.*`:\n // - Matches `ab.cd.r` or `ab.cd.x.yz`\n // - DOES NOT match `ab.cd.x/yz` or `ab.x.cd` or `x.ab.cd.yz`\n (typeof payload.topic === \"string\" &&\n payload.topic.includes(\"*\") &&\n new RegExp(\n `^${payload.topic.replace(\n /([^*]*)\\*([^*]*)/g,\n (_m, p1, p2) => `${escapeRegExp(p1)}[^/]*${escapeRegExp(p2)}`\n )}$`\n ).test(responsePayload.topic)))\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"MessageDispatcher.js","names":["_runtime","require","_lodash","_MessageService","_ms","WeakMap","_memoizedChannels","_channelPayloads","_MessageDispatcher_brand","WeakSet","MessageDispatcher","constructor","_classPrivateMethodInitSpec2","default","_classPrivateFieldInitSpec2","sub","Map","unsub","subscribe","channel","payload","stringifiedPayload","JSON","stringify","_assertClassBrand2","_subOrUnsub","call","unsubscribe","_classPrivateFieldGet3","get","msg","console","error","Promise","reject","Error","parse","result","delete","then","onMessage","listener","warned","_classPrivateGetter2","_get_ms","response","event","matchMessageChannel","message","onClose","reset","_classPrivateFieldGet2","clear","exports","_this","protocol","location","url","window","host","getBasePath","_classPrivateFieldSet2","MessageService","type","hit","request","promise","resolve","identity","getIdentity","disposeOnMessage","isSuccess","isFailed","disposeOnClose","retryCount","RETRY_LIMIT","send","set","system","topic","responsePayload","includes","RegExp","replace","_m","p1","p2","escapeRegExp","test"],"sources":["../../../src/websocket/MessageDispatcher.ts"],"sourcesContent":["import { getBasePath } from \"@next-core/runtime\";\nimport { escapeRegExp } from \"lodash\";\nimport {\n MessageService,\n type MessageListener,\n CloseListener,\n RETRY_LIMIT,\n} from \"./MessageService.js\";\n\ninterface MessageResponse {\n event:\n | \"TOPIC.SUB_SUCCESS\"\n | \"TOPIC.SUB_FAILED\"\n | \"TOPIC.UNSUB_SUCCESS\"\n | \"TOPIC.UNSUB_FAILED\"\n | \"MESSAGE.PUSH\";\n payload: MessagePayload;\n}\n\ninterface MessagePayload {\n source?: string;\n system: string;\n topic: string;\n message?: unknown;\n}\n\nexport class MessageDispatcher {\n #_ms: MessageService | undefined;\n #memoizedChannels = {\n sub: new Map<string, Promise<unknown>>(),\n unsub: new Map<string, Promise<unknown>>(),\n };\n #channelPayloads = new Map<string, string>();\n\n get #ms(): MessageService {\n if (!this.#_ms) {\n const protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const url = `${protocol}//${\n window.location.host\n }${getBasePath()}api/websocket_service/v1/ws`;\n this.#_ms = new MessageService(url);\n }\n return this.#_ms;\n }\n\n subscribe(channel: string, payload: MessagePayload): Promise<unknown> {\n const stringifiedPayload = JSON.stringify(payload);\n return this.#subOrUnsub(\"sub\", channel, payload, stringifiedPayload);\n }\n\n unsubscribe(channel: string): Promise<unknown> {\n const stringifiedPayload = this.#channelPayloads.get(channel);\n if (!stringifiedPayload) {\n const msg = `The message channel to unsubscribe \"${channel}\" is not found`;\n // eslint-disable-next-line no-console\n console.error(msg);\n return Promise.reject(new Error(msg));\n }\n\n const payload = JSON.parse(stringifiedPayload);\n const result = this.#subOrUnsub(\n \"unsub\",\n channel,\n payload,\n stringifiedPayload\n );\n\n this.#memoizedChannels.sub.delete(stringifiedPayload);\n\n result.then(() => {\n this.#channelPayloads.delete(channel);\n });\n\n return result;\n }\n\n onMessage(channel: string, listener: MessageListener): void {\n let stringifiedPayload = this.#channelPayloads.get(channel);\n let warned = false;\n\n this.#ms.onMessage<MessageResponse>((response) => {\n if (!stringifiedPayload) {\n stringifiedPayload = this.#channelPayloads.get(channel);\n }\n if (!stringifiedPayload) {\n if (!warned) {\n // eslint-disable-next-line no-console\n console.error(`Message channel: \"${channel}\" not found`);\n warned = true;\n }\n return;\n }\n if (\n response.event === \"MESSAGE.PUSH\" &&\n matchMessageChannel(stringifiedPayload, response.payload)\n ) {\n listener(response.payload.message);\n }\n });\n }\n\n onClose(listener: CloseListener) {\n return this.#ms.onClose(listener);\n }\n\n reset(): void {\n this.#memoizedChannels.sub.clear();\n this.#memoizedChannels.unsub.clear();\n this.#channelPayloads.clear();\n this.#_ms?.reset();\n }\n\n #subOrUnsub(\n type: \"sub\" | \"unsub\",\n channel: string,\n payload: MessagePayload,\n stringifiedPayload: string\n ): Promise<unknown> {\n const hit = this.#memoizedChannels[type].get(stringifiedPayload);\n if (hit) {\n return hit;\n }\n const request = {\n event: type === \"sub\" ? \"TOPIC.SUB\" : \"TOPIC.UNSUB\",\n payload,\n };\n const promise = new Promise((resolve, reject) => {\n const identity = getIdentity(payload);\n const disposeOnMessage = this.#ms.onMessage<MessageResponse>(\n (response) => {\n const isSuccess =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_SUCCESS\" : \"TOPIC.UNSUB_SUCCESS\");\n const isFailed =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_FAILED\" : \"TOPIC.UNSUB_FAILED\");\n if (\n (isSuccess || isFailed) &&\n // Put this after event type checks, to prevent unnecessary\n // JSON stringify.\n identity === getIdentity(response.payload)\n ) {\n (isSuccess ? resolve : reject)(response);\n disposeOnMessage();\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n disposeOnClose();\n }\n }\n );\n // istanbul ignore next: currently can't mock this\n const disposeOnClose = this.#ms.onClose(() => {\n // V2 will emit error callback for sub/unsub each time connect failed,\n // while v3 will emit only once after retry limit exceeded.\n // Keep the `EVENT.detail.retryCount` for compatibility.\n reject({\n retryCount: RETRY_LIMIT,\n });\n disposeOnMessage();\n disposeOnClose();\n });\n this.#ms.send(request);\n });\n\n if (type === \"sub\") {\n this.#channelPayloads.set(channel, stringifiedPayload);\n }\n this.#memoizedChannels[type].set(stringifiedPayload, promise);\n return promise;\n }\n}\n\nfunction getIdentity(payload: MessagePayload) {\n const { system, topic } = payload;\n return JSON.stringify({ system, topic });\n}\n\nfunction matchMessageChannel(\n stringifiedPayload: string,\n responsePayload: MessagePayload\n): boolean {\n const payload = JSON.parse(stringifiedPayload) as MessagePayload;\n return (\n payload.system === responsePayload.system &&\n // Exact match\n (payload.topic === responsePayload.topic ||\n // Wildcards match\n // For `ab.cd.*`:\n // - Matches `ab.cd.r` or `ab.cd.x.yz`\n // - DOES NOT match `ab.cd.x/yz` or `ab.x.cd` or `x.ab.cd.yz`\n (typeof payload.topic === \"string\" &&\n payload.topic.includes(\"*\") &&\n new RegExp(\n `^${payload.topic.replace(\n /([^*]*)\\*([^*]*)/g,\n (_m, p1, p2) => `${escapeRegExp(p1)}[^/]*${escapeRegExp(p2)}`\n )}$`\n ).test(responsePayload.topic)))\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -4,14 +4,14 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.MessageService = void 0;
7
+ exports.RETRY_LIMIT = exports.MessageService = void 0;
8
8
  var _classPrivateMethodInitSpec2 = _interopRequireDefault(require("@babel/runtime/helpers/classPrivateMethodInitSpec"));
9
9
  var _classPrivateFieldInitSpec2 = _interopRequireDefault(require("@babel/runtime/helpers/classPrivateFieldInitSpec"));
10
10
  var _assertClassBrand2 = _interopRequireDefault(require("@babel/runtime/helpers/assertClassBrand"));
11
11
  var _classPrivateFieldGet3 = _interopRequireDefault(require("@babel/runtime/helpers/classPrivateFieldGet2"));
12
12
  var _classPrivateFieldSet2 = _interopRequireDefault(require("@babel/runtime/helpers/classPrivateFieldSet2"));
13
13
  const RETRY_TIMEOUT_UNIT = 1000;
14
- const RETRY_LIMIT = 5;
14
+ const RETRY_LIMIT = exports.RETRY_LIMIT = 5;
15
15
  var _url = /*#__PURE__*/new WeakMap();
16
16
  var _ws = /*#__PURE__*/new WeakMap();
17
17
  var _queuedMessages = /*#__PURE__*/new WeakMap();
@@ -46,9 +46,15 @@ class MessageService {
46
46
  }
47
47
  onMessage(listener) {
48
48
  (0, _classPrivateFieldGet3.default)(_messageListeners, this).add(listener);
49
+ return () => {
50
+ (0, _classPrivateFieldGet3.default)(_messageListeners, this).delete(listener);
51
+ };
49
52
  }
50
53
  onClose(listener) {
51
54
  (0, _classPrivateFieldGet3.default)(_closeListeners, this).add(listener);
55
+ return () => {
56
+ (0, _classPrivateFieldGet3.default)(_closeListeners, this).delete(listener);
57
+ };
52
58
  }
53
59
  reset() {
54
60
  (0, _classPrivateFieldGet3.default)(_queuedMessages, this).length = 0;
@@ -93,9 +99,6 @@ function _connect() {
93
99
  }
94
100
  // eslint-disable-next-line no-console
95
101
  console.log("WebSocket close:", e);
96
- for (const listener of (0, _classPrivateFieldGet3.default)(_closeListeners, this)) {
97
- listener();
98
- }
99
102
  // Error code 1000 means that the connection was closed normally.
100
103
  if (e.code !== 1000) {
101
104
  (0, _assertClassBrand2.default)(_MessageService_brand, this, _reconnect).call(this);
@@ -120,6 +123,10 @@ function _reconnect() {
120
123
  if ((0, _classPrivateFieldGet3.default)(_retryCount, this) >= RETRY_LIMIT) {
121
124
  // eslint-disable-next-line no-console
122
125
  console.error("WebSocket connect retry limit exceeded");
126
+ // Keep behavior as v2: emit close event only after retry limit exceeded
127
+ for (const listener of (0, _classPrivateFieldGet3.default)(_closeListeners, this)) {
128
+ listener();
129
+ }
123
130
  return;
124
131
  }
125
132
  // Double the timeout for each retry
@@ -1 +1 @@
1
- {"version":3,"file":"MessageService.js","names":["RETRY_TIMEOUT_UNIT","RETRY_LIMIT","_url","WeakMap","_ws","_queuedMessages","_messageListeners","_closeListeners","_retryCount","_closed","_MessageService_brand","WeakSet","MessageService","constructor","url","_classPrivateMethodInitSpec2","default","_classPrivateFieldInitSpec2","Set","_classPrivateFieldSet2","send","data","_classPrivateFieldGet3","_assertClassBrand2","_connect","call","stringifiedData","JSON","stringify","readyState","WebSocket","OPEN","push","onMessage","listener","add","onClose","reset","length","clear","close","_classPrivateFieldGet2","exports","console","log","ws","resetRetryCountTimeout","addEventListener","e","setTimeout","undefined","msg","clearTimeout","code","_reconnect","error","response","parse","delay","Math","pow","_this$retryCount","_this$retryCount2"],"sources":["../../../src/websocket/MessageService.ts"],"sourcesContent":["export type MessageListener<T = unknown> = (response: T) => void;\nexport type CloseListener = () => void;\n\nconst RETRY_TIMEOUT_UNIT = 1000;\nconst RETRY_LIMIT = 5;\n\nexport class MessageService {\n #url: string;\n #ws: WebSocket | undefined;\n #queuedMessages: string[] = [];\n #messageListeners = new Set<MessageListener>();\n #closeListeners = new Set<CloseListener>();\n #retryCount = 0;\n #closed = false;\n\n constructor(url: string) {\n this.#url = url;\n }\n\n #connect(): WebSocket {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket connecting ...\");\n const ws = new WebSocket(this.#url);\n let resetRetryCountTimeout: number | undefined;\n ws.addEventListener(\"open\", (e) => {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket open:\", e);\n\n // If server closes the socket not more than 1 second after it's opened,\n // we should not reset the retry count.\n resetRetryCountTimeout = setTimeout(() => {\n resetRetryCountTimeout = undefined;\n this.#retryCount = 0;\n }, 1e3) as unknown as number;\n\n for (const msg of this.#queuedMessages) {\n ws.send(msg);\n }\n this.#queuedMessages.length = 0;\n });\n ws.addEventListener(\"close\", (e) => {\n if (this.#closed) {\n return;\n }\n if (resetRetryCountTimeout !== undefined) {\n clearTimeout(resetRetryCountTimeout);\n }\n // eslint-disable-next-line no-console\n console.log(\"WebSocket close:\", e);\n for (const listener of this.#closeListeners) {\n listener();\n }\n // Error code 1000 means that the connection was closed normally.\n if (e.code !== 1000) {\n this.#reconnect();\n }\n });\n ws.addEventListener(\"error\", (e) => {\n // No need to reconnect in error event listener,\n // there will always be a close event along with the error event.\n // eslint-disable-next-line no-console\n console.error(\"WebSocket error:\", e);\n });\n ws.addEventListener(\"message\", (e: MessageEvent<string>) => {\n const response = JSON.parse(e.data);\n for (const listener of this.#messageListeners) {\n listener(response);\n }\n });\n return ws;\n }\n\n #reconnect() {\n // istanbul ignore next: currently can't mock this\n if (this.#retryCount >= RETRY_LIMIT) {\n // eslint-disable-next-line no-console\n console.error(\"WebSocket connect retry limit exceeded\");\n return;\n }\n // Double the timeout for each retry\n const delay = Math.pow(2, this.#retryCount) * RETRY_TIMEOUT_UNIT;\n // eslint-disable-next-line no-console\n console.log(\"WebSocket will reconnect after %d seconds\", delay / 1000);\n setTimeout(() => {\n this.#retryCount++;\n this.#ws = this.#connect();\n }, delay);\n }\n\n send(data: unknown): void {\n // Connect when data is sent for the first time\n if (!this.#ws) {\n this.#ws = this.#connect();\n }\n const stringifiedData = JSON.stringify(data);\n if (this.#ws.readyState === WebSocket.OPEN) {\n this.#ws.send(stringifiedData);\n } else {\n this.#queuedMessages.push(stringifiedData);\n }\n }\n\n onMessage<T = unknown>(listener: MessageListener<T>) {\n this.#messageListeners.add(listener as MessageListener<unknown>);\n }\n\n onClose(listener: CloseListener) {\n this.#closeListeners.add(listener);\n }\n\n reset() {\n this.#queuedMessages.length = 0;\n this.#messageListeners.clear();\n this.#closeListeners.clear();\n }\n\n close() {\n this.#closed = true;\n if (this.#ws?.readyState === WebSocket.OPEN) {\n this.#ws.close();\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"MessageService.js","names":["RETRY_TIMEOUT_UNIT","RETRY_LIMIT","exports","_url","WeakMap","_ws","_queuedMessages","_messageListeners","_closeListeners","_retryCount","_closed","_MessageService_brand","WeakSet","MessageService","constructor","url","_classPrivateMethodInitSpec2","default","_classPrivateFieldInitSpec2","Set","_classPrivateFieldSet2","send","data","_classPrivateFieldGet3","_assertClassBrand2","_connect","call","stringifiedData","JSON","stringify","readyState","WebSocket","OPEN","push","onMessage","listener","add","delete","onClose","reset","length","clear","close","_classPrivateFieldGet2","console","log","ws","resetRetryCountTimeout","addEventListener","e","setTimeout","undefined","msg","clearTimeout","code","_reconnect","error","response","parse","delay","Math","pow","_this$retryCount","_this$retryCount2"],"sources":["../../../src/websocket/MessageService.ts"],"sourcesContent":["export type MessageListener<T = unknown> = (response: T) => void;\nexport type CloseListener = () => void;\n\nconst RETRY_TIMEOUT_UNIT = 1000;\nexport const RETRY_LIMIT = 5;\n\nexport class MessageService {\n #url: string;\n #ws: WebSocket | undefined;\n #queuedMessages: string[] = [];\n #messageListeners = new Set<MessageListener>();\n #closeListeners = new Set<CloseListener>();\n #retryCount = 0;\n #closed = false;\n\n constructor(url: string) {\n this.#url = url;\n }\n\n #connect(): WebSocket {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket connecting ...\");\n const ws = new WebSocket(this.#url);\n let resetRetryCountTimeout: number | undefined;\n ws.addEventListener(\"open\", (e) => {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket open:\", e);\n\n // If server closes the socket not more than 1 second after it's opened,\n // we should not reset the retry count.\n resetRetryCountTimeout = setTimeout(() => {\n resetRetryCountTimeout = undefined;\n this.#retryCount = 0;\n }, 1e3) as unknown as number;\n\n for (const msg of this.#queuedMessages) {\n ws.send(msg);\n }\n this.#queuedMessages.length = 0;\n });\n ws.addEventListener(\"close\", (e) => {\n if (this.#closed) {\n return;\n }\n if (resetRetryCountTimeout !== undefined) {\n clearTimeout(resetRetryCountTimeout);\n }\n // eslint-disable-next-line no-console\n console.log(\"WebSocket close:\", e);\n // Error code 1000 means that the connection was closed normally.\n if (e.code !== 1000) {\n this.#reconnect();\n }\n });\n ws.addEventListener(\"error\", (e) => {\n // No need to reconnect in error event listener,\n // there will always be a close event along with the error event.\n // eslint-disable-next-line no-console\n console.error(\"WebSocket error:\", e);\n });\n ws.addEventListener(\"message\", (e: MessageEvent<string>) => {\n const response = JSON.parse(e.data);\n for (const listener of this.#messageListeners) {\n listener(response);\n }\n });\n return ws;\n }\n\n #reconnect() {\n // istanbul ignore next: currently can't mock this\n if (this.#retryCount >= RETRY_LIMIT) {\n // eslint-disable-next-line no-console\n console.error(\"WebSocket connect retry limit exceeded\");\n // Keep behavior as v2: emit close event only after retry limit exceeded\n for (const listener of this.#closeListeners) {\n listener();\n }\n return;\n }\n // Double the timeout for each retry\n const delay = Math.pow(2, this.#retryCount) * RETRY_TIMEOUT_UNIT;\n // eslint-disable-next-line no-console\n console.log(\"WebSocket will reconnect after %d seconds\", delay / 1000);\n setTimeout(() => {\n this.#retryCount++;\n this.#ws = this.#connect();\n }, delay);\n }\n\n send(data: unknown): void {\n // Connect when data is sent for the first time\n if (!this.#ws) {\n this.#ws = this.#connect();\n }\n const stringifiedData = JSON.stringify(data);\n if (this.#ws.readyState === WebSocket.OPEN) {\n this.#ws.send(stringifiedData);\n } else {\n this.#queuedMessages.push(stringifiedData);\n }\n }\n\n onMessage<T = unknown>(listener: MessageListener<T>) {\n this.#messageListeners.add(listener as MessageListener<unknown>);\n\n return () => {\n this.#messageListeners.delete(listener as MessageListener<unknown>);\n };\n }\n\n onClose(listener: CloseListener) {\n this.#closeListeners.add(listener);\n\n return () => {\n this.#closeListeners.delete(listener);\n };\n }\n\n reset() {\n this.#queuedMessages.length = 0;\n this.#messageListeners.clear();\n this.#closeListeners.clear();\n }\n\n close() {\n this.#closed = true;\n if (this.#ws?.readyState === WebSocket.OPEN) {\n this.#ws.close();\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -6,7 +6,7 @@ import _classPrivateFieldSet from "@babel/runtime/helpers/classPrivateFieldSet2"
6
6
  import _classPrivateFieldGet from "@babel/runtime/helpers/classPrivateFieldGet2";
7
7
  import { getBasePath } from "@next-core/runtime";
8
8
  import { escapeRegExp } from "lodash";
9
- import { MessageService } from "./MessageService.js";
9
+ import { MessageService, RETRY_LIMIT } from "./MessageService.js";
10
10
  var _ms = /*#__PURE__*/new WeakMap();
11
11
  var _memoizedChannels = /*#__PURE__*/new WeakMap();
12
12
  var _channelPayloads = /*#__PURE__*/new WeakMap();
@@ -62,7 +62,7 @@ export class MessageDispatcher {
62
62
  });
63
63
  }
64
64
  onClose(listener) {
65
- _classPrivateGetter(_MessageDispatcher_brand, this, _get_ms).onClose(listener);
65
+ return _classPrivateGetter(_MessageDispatcher_brand, this, _get_ms).onClose(listener);
66
66
  }
67
67
  reset() {
68
68
  var _classPrivateFieldGet2;
@@ -91,7 +91,7 @@ function _subOrUnsub(type, channel, payload, stringifiedPayload) {
91
91
  };
92
92
  const promise = new Promise((resolve, reject) => {
93
93
  const identity = getIdentity(payload);
94
- _classPrivateGetter(_MessageDispatcher_brand, this, _get_ms).onMessage(response => {
94
+ const disposeOnMessage = _classPrivateGetter(_MessageDispatcher_brand, this, _get_ms).onMessage(response => {
95
95
  const isSuccess = response.event === (type === "sub" ? "TOPIC.SUB_SUCCESS" : "TOPIC.UNSUB_SUCCESS");
96
96
  const isFailed = response.event === (type === "sub" ? "TOPIC.SUB_FAILED" : "TOPIC.UNSUB_FAILED");
97
97
  if ((isSuccess || isFailed) &&
@@ -99,8 +99,22 @@ function _subOrUnsub(type, channel, payload, stringifiedPayload) {
99
99
  // JSON stringify.
100
100
  identity === getIdentity(response.payload)) {
101
101
  (isSuccess ? resolve : reject)(response);
102
+ disposeOnMessage();
103
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
104
+ disposeOnClose();
102
105
  }
103
106
  });
107
+ // istanbul ignore next: currently can't mock this
108
+ const disposeOnClose = _classPrivateGetter(_MessageDispatcher_brand, this, _get_ms).onClose(() => {
109
+ // V2 will emit error callback for sub/unsub each time connect failed,
110
+ // while v3 will emit only once after retry limit exceeded.
111
+ // Keep the `EVENT.detail.retryCount` for compatibility.
112
+ reject({
113
+ retryCount: RETRY_LIMIT
114
+ });
115
+ disposeOnMessage();
116
+ disposeOnClose();
117
+ });
104
118
  _classPrivateGetter(_MessageDispatcher_brand, this, _get_ms).send(request);
105
119
  });
106
120
  if (type === "sub") {
@@ -1 +1 @@
1
- {"version":3,"file":"MessageDispatcher.js","names":["getBasePath","escapeRegExp","MessageService","_ms","WeakMap","_memoizedChannels","_channelPayloads","_MessageDispatcher_brand","WeakSet","MessageDispatcher","constructor","_classPrivateMethodInitSpec","_classPrivateFieldInitSpec","sub","Map","unsub","subscribe","channel","payload","stringifiedPayload","JSON","stringify","_assertClassBrand","_subOrUnsub","call","unsubscribe","_classPrivateFieldGet","get","msg","console","error","Promise","reject","Error","parse","result","delete","then","onMessage","listener","warned","_classPrivateGetter","_get_ms","response","event","matchMessageChannel","message","onClose","reset","_classPrivateFieldGet2","clear","_this","protocol","location","url","window","host","_classPrivateFieldSet","type","hit","request","promise","resolve","identity","getIdentity","isSuccess","isFailed","send","set","system","topic","responsePayload","includes","RegExp","replace","_m","p1","p2","test"],"sources":["../../../src/websocket/MessageDispatcher.ts"],"sourcesContent":["import { getBasePath } from \"@next-core/runtime\";\nimport { escapeRegExp } from \"lodash\";\nimport {\n MessageService,\n type MessageListener,\n CloseListener,\n} from \"./MessageService.js\";\n\ninterface MessageResponse {\n event:\n | \"TOPIC.SUB_SUCCESS\"\n | \"TOPIC.SUB_FAILED\"\n | \"TOPIC.UNSUB_SUCCESS\"\n | \"TOPIC.UNSUB_FAILED\"\n | \"MESSAGE.PUSH\";\n payload: MessagePayload;\n}\n\ninterface MessagePayload {\n source?: string;\n system: string;\n topic: string;\n message?: unknown;\n}\n\nexport class MessageDispatcher {\n #_ms: MessageService | undefined;\n #memoizedChannels = {\n sub: new Map<string, Promise<unknown>>(),\n unsub: new Map<string, Promise<unknown>>(),\n };\n #channelPayloads = new Map<string, string>();\n\n get #ms(): MessageService {\n if (!this.#_ms) {\n const protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const url = `${protocol}//${\n window.location.host\n }${getBasePath()}api/websocket_service/v1/ws`;\n this.#_ms = new MessageService(url);\n }\n return this.#_ms;\n }\n\n subscribe(channel: string, payload: MessagePayload): Promise<unknown> {\n const stringifiedPayload = JSON.stringify(payload);\n return this.#subOrUnsub(\"sub\", channel, payload, stringifiedPayload);\n }\n\n unsubscribe(channel: string): Promise<unknown> {\n const stringifiedPayload = this.#channelPayloads.get(channel);\n if (!stringifiedPayload) {\n const msg = `The message channel to unsubscribe \"${channel}\" is not found`;\n // eslint-disable-next-line no-console\n console.error(msg);\n return Promise.reject(new Error(msg));\n }\n\n const payload = JSON.parse(stringifiedPayload);\n const result = this.#subOrUnsub(\n \"unsub\",\n channel,\n payload,\n stringifiedPayload\n );\n\n this.#memoizedChannels.sub.delete(stringifiedPayload);\n\n result.then(() => {\n this.#channelPayloads.delete(channel);\n });\n\n return result;\n }\n\n onMessage(channel: string, listener: MessageListener): void {\n let stringifiedPayload = this.#channelPayloads.get(channel);\n let warned = false;\n\n this.#ms.onMessage<MessageResponse>((response) => {\n if (!stringifiedPayload) {\n stringifiedPayload = this.#channelPayloads.get(channel);\n }\n if (!stringifiedPayload) {\n if (!warned) {\n // eslint-disable-next-line no-console\n console.error(`Message channel: \"${channel}\" not found`);\n warned = true;\n }\n return;\n }\n if (\n response.event === \"MESSAGE.PUSH\" &&\n matchMessageChannel(stringifiedPayload, response.payload)\n ) {\n listener(response.payload.message);\n }\n });\n }\n\n onClose(listener: CloseListener): void {\n this.#ms.onClose(listener);\n }\n\n reset(): void {\n this.#memoizedChannels.sub.clear();\n this.#memoizedChannels.unsub.clear();\n this.#channelPayloads.clear();\n this.#_ms?.reset();\n }\n\n #subOrUnsub(\n type: \"sub\" | \"unsub\",\n channel: string,\n payload: MessagePayload,\n stringifiedPayload: string\n ): Promise<unknown> {\n const hit = this.#memoizedChannels[type].get(stringifiedPayload);\n if (hit) {\n return hit;\n }\n const request = {\n event: type === \"sub\" ? \"TOPIC.SUB\" : \"TOPIC.UNSUB\",\n payload,\n };\n const promise = new Promise((resolve, reject) => {\n const identity = getIdentity(payload);\n this.#ms.onMessage<MessageResponse>((response) => {\n const isSuccess =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_SUCCESS\" : \"TOPIC.UNSUB_SUCCESS\");\n const isFailed =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_FAILED\" : \"TOPIC.UNSUB_FAILED\");\n if (\n (isSuccess || isFailed) &&\n // Put this after event type checks, to prevent unnecessary\n // JSON stringify.\n identity === getIdentity(response.payload)\n ) {\n (isSuccess ? resolve : reject)(response);\n }\n });\n this.#ms.send(request);\n });\n\n if (type === \"sub\") {\n this.#channelPayloads.set(channel, stringifiedPayload);\n }\n this.#memoizedChannels[type].set(stringifiedPayload, promise);\n return promise;\n }\n}\n\nfunction getIdentity(payload: MessagePayload) {\n const { system, topic } = payload;\n return JSON.stringify({ system, topic });\n}\n\nfunction matchMessageChannel(\n stringifiedPayload: string,\n responsePayload: MessagePayload\n): boolean {\n const payload = JSON.parse(stringifiedPayload) as MessagePayload;\n return (\n payload.system === responsePayload.system &&\n // Exact match\n (payload.topic === responsePayload.topic ||\n // Wildcards match\n // For `ab.cd.*`:\n // - Matches `ab.cd.r` or `ab.cd.x.yz`\n // - DOES NOT match `ab.cd.x/yz` or `ab.x.cd` or `x.ab.cd.yz`\n (typeof payload.topic === \"string\" &&\n payload.topic.includes(\"*\") &&\n new RegExp(\n `^${payload.topic.replace(\n /([^*]*)\\*([^*]*)/g,\n (_m, p1, p2) => `${escapeRegExp(p1)}[^/]*${escapeRegExp(p2)}`\n )}$`\n ).test(responsePayload.topic)))\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"MessageDispatcher.js","names":["getBasePath","escapeRegExp","MessageService","RETRY_LIMIT","_ms","WeakMap","_memoizedChannels","_channelPayloads","_MessageDispatcher_brand","WeakSet","MessageDispatcher","constructor","_classPrivateMethodInitSpec","_classPrivateFieldInitSpec","sub","Map","unsub","subscribe","channel","payload","stringifiedPayload","JSON","stringify","_assertClassBrand","_subOrUnsub","call","unsubscribe","_classPrivateFieldGet","get","msg","console","error","Promise","reject","Error","parse","result","delete","then","onMessage","listener","warned","_classPrivateGetter","_get_ms","response","event","matchMessageChannel","message","onClose","reset","_classPrivateFieldGet2","clear","_this","protocol","location","url","window","host","_classPrivateFieldSet","type","hit","request","promise","resolve","identity","getIdentity","disposeOnMessage","isSuccess","isFailed","disposeOnClose","retryCount","send","set","system","topic","responsePayload","includes","RegExp","replace","_m","p1","p2","test"],"sources":["../../../src/websocket/MessageDispatcher.ts"],"sourcesContent":["import { getBasePath } from \"@next-core/runtime\";\nimport { escapeRegExp } from \"lodash\";\nimport {\n MessageService,\n type MessageListener,\n CloseListener,\n RETRY_LIMIT,\n} from \"./MessageService.js\";\n\ninterface MessageResponse {\n event:\n | \"TOPIC.SUB_SUCCESS\"\n | \"TOPIC.SUB_FAILED\"\n | \"TOPIC.UNSUB_SUCCESS\"\n | \"TOPIC.UNSUB_FAILED\"\n | \"MESSAGE.PUSH\";\n payload: MessagePayload;\n}\n\ninterface MessagePayload {\n source?: string;\n system: string;\n topic: string;\n message?: unknown;\n}\n\nexport class MessageDispatcher {\n #_ms: MessageService | undefined;\n #memoizedChannels = {\n sub: new Map<string, Promise<unknown>>(),\n unsub: new Map<string, Promise<unknown>>(),\n };\n #channelPayloads = new Map<string, string>();\n\n get #ms(): MessageService {\n if (!this.#_ms) {\n const protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const url = `${protocol}//${\n window.location.host\n }${getBasePath()}api/websocket_service/v1/ws`;\n this.#_ms = new MessageService(url);\n }\n return this.#_ms;\n }\n\n subscribe(channel: string, payload: MessagePayload): Promise<unknown> {\n const stringifiedPayload = JSON.stringify(payload);\n return this.#subOrUnsub(\"sub\", channel, payload, stringifiedPayload);\n }\n\n unsubscribe(channel: string): Promise<unknown> {\n const stringifiedPayload = this.#channelPayloads.get(channel);\n if (!stringifiedPayload) {\n const msg = `The message channel to unsubscribe \"${channel}\" is not found`;\n // eslint-disable-next-line no-console\n console.error(msg);\n return Promise.reject(new Error(msg));\n }\n\n const payload = JSON.parse(stringifiedPayload);\n const result = this.#subOrUnsub(\n \"unsub\",\n channel,\n payload,\n stringifiedPayload\n );\n\n this.#memoizedChannels.sub.delete(stringifiedPayload);\n\n result.then(() => {\n this.#channelPayloads.delete(channel);\n });\n\n return result;\n }\n\n onMessage(channel: string, listener: MessageListener): void {\n let stringifiedPayload = this.#channelPayloads.get(channel);\n let warned = false;\n\n this.#ms.onMessage<MessageResponse>((response) => {\n if (!stringifiedPayload) {\n stringifiedPayload = this.#channelPayloads.get(channel);\n }\n if (!stringifiedPayload) {\n if (!warned) {\n // eslint-disable-next-line no-console\n console.error(`Message channel: \"${channel}\" not found`);\n warned = true;\n }\n return;\n }\n if (\n response.event === \"MESSAGE.PUSH\" &&\n matchMessageChannel(stringifiedPayload, response.payload)\n ) {\n listener(response.payload.message);\n }\n });\n }\n\n onClose(listener: CloseListener) {\n return this.#ms.onClose(listener);\n }\n\n reset(): void {\n this.#memoizedChannels.sub.clear();\n this.#memoizedChannels.unsub.clear();\n this.#channelPayloads.clear();\n this.#_ms?.reset();\n }\n\n #subOrUnsub(\n type: \"sub\" | \"unsub\",\n channel: string,\n payload: MessagePayload,\n stringifiedPayload: string\n ): Promise<unknown> {\n const hit = this.#memoizedChannels[type].get(stringifiedPayload);\n if (hit) {\n return hit;\n }\n const request = {\n event: type === \"sub\" ? \"TOPIC.SUB\" : \"TOPIC.UNSUB\",\n payload,\n };\n const promise = new Promise((resolve, reject) => {\n const identity = getIdentity(payload);\n const disposeOnMessage = this.#ms.onMessage<MessageResponse>(\n (response) => {\n const isSuccess =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_SUCCESS\" : \"TOPIC.UNSUB_SUCCESS\");\n const isFailed =\n response.event ===\n (type === \"sub\" ? \"TOPIC.SUB_FAILED\" : \"TOPIC.UNSUB_FAILED\");\n if (\n (isSuccess || isFailed) &&\n // Put this after event type checks, to prevent unnecessary\n // JSON stringify.\n identity === getIdentity(response.payload)\n ) {\n (isSuccess ? resolve : reject)(response);\n disposeOnMessage();\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n disposeOnClose();\n }\n }\n );\n // istanbul ignore next: currently can't mock this\n const disposeOnClose = this.#ms.onClose(() => {\n // V2 will emit error callback for sub/unsub each time connect failed,\n // while v3 will emit only once after retry limit exceeded.\n // Keep the `EVENT.detail.retryCount` for compatibility.\n reject({\n retryCount: RETRY_LIMIT,\n });\n disposeOnMessage();\n disposeOnClose();\n });\n this.#ms.send(request);\n });\n\n if (type === \"sub\") {\n this.#channelPayloads.set(channel, stringifiedPayload);\n }\n this.#memoizedChannels[type].set(stringifiedPayload, promise);\n return promise;\n }\n}\n\nfunction getIdentity(payload: MessagePayload) {\n const { system, topic } = payload;\n return JSON.stringify({ system, topic });\n}\n\nfunction matchMessageChannel(\n stringifiedPayload: string,\n responsePayload: MessagePayload\n): boolean {\n const payload = JSON.parse(stringifiedPayload) as MessagePayload;\n return (\n payload.system === responsePayload.system &&\n // Exact match\n (payload.topic === responsePayload.topic ||\n // Wildcards match\n // For `ab.cd.*`:\n // - Matches `ab.cd.r` or `ab.cd.x.yz`\n // - DOES NOT match `ab.cd.x/yz` or `ab.x.cd` or `x.ab.cd.yz`\n (typeof payload.topic === \"string\" &&\n payload.topic.includes(\"*\") &&\n new RegExp(\n `^${payload.topic.replace(\n /([^*]*)\\*([^*]*)/g,\n (_m, p1, p2) => `${escapeRegExp(p1)}[^/]*${escapeRegExp(p2)}`\n )}$`\n ).test(responsePayload.topic)))\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -4,7 +4,7 @@ import _assertClassBrand from "@babel/runtime/helpers/assertClassBrand";
4
4
  import _classPrivateFieldGet from "@babel/runtime/helpers/classPrivateFieldGet2";
5
5
  import _classPrivateFieldSet from "@babel/runtime/helpers/classPrivateFieldSet2";
6
6
  const RETRY_TIMEOUT_UNIT = 1000;
7
- const RETRY_LIMIT = 5;
7
+ export const RETRY_LIMIT = 5;
8
8
  var _url = /*#__PURE__*/new WeakMap();
9
9
  var _ws = /*#__PURE__*/new WeakMap();
10
10
  var _queuedMessages = /*#__PURE__*/new WeakMap();
@@ -39,9 +39,15 @@ export class MessageService {
39
39
  }
40
40
  onMessage(listener) {
41
41
  _classPrivateFieldGet(_messageListeners, this).add(listener);
42
+ return () => {
43
+ _classPrivateFieldGet(_messageListeners, this).delete(listener);
44
+ };
42
45
  }
43
46
  onClose(listener) {
44
47
  _classPrivateFieldGet(_closeListeners, this).add(listener);
48
+ return () => {
49
+ _classPrivateFieldGet(_closeListeners, this).delete(listener);
50
+ };
45
51
  }
46
52
  reset() {
47
53
  _classPrivateFieldGet(_queuedMessages, this).length = 0;
@@ -85,9 +91,6 @@ function _connect() {
85
91
  }
86
92
  // eslint-disable-next-line no-console
87
93
  console.log("WebSocket close:", e);
88
- for (const listener of _classPrivateFieldGet(_closeListeners, this)) {
89
- listener();
90
- }
91
94
  // Error code 1000 means that the connection was closed normally.
92
95
  if (e.code !== 1000) {
93
96
  _assertClassBrand(_MessageService_brand, this, _reconnect).call(this);
@@ -112,6 +115,10 @@ function _reconnect() {
112
115
  if (_classPrivateFieldGet(_retryCount, this) >= RETRY_LIMIT) {
113
116
  // eslint-disable-next-line no-console
114
117
  console.error("WebSocket connect retry limit exceeded");
118
+ // Keep behavior as v2: emit close event only after retry limit exceeded
119
+ for (const listener of _classPrivateFieldGet(_closeListeners, this)) {
120
+ listener();
121
+ }
115
122
  return;
116
123
  }
117
124
  // Double the timeout for each retry
@@ -1 +1 @@
1
- {"version":3,"file":"MessageService.js","names":["RETRY_TIMEOUT_UNIT","RETRY_LIMIT","_url","WeakMap","_ws","_queuedMessages","_messageListeners","_closeListeners","_retryCount","_closed","_MessageService_brand","WeakSet","MessageService","constructor","url","_classPrivateMethodInitSpec","_classPrivateFieldInitSpec","Set","_classPrivateFieldSet","send","data","_classPrivateFieldGet","_assertClassBrand","_connect","call","stringifiedData","JSON","stringify","readyState","WebSocket","OPEN","push","onMessage","listener","add","onClose","reset","length","clear","close","_classPrivateFieldGet2","console","log","ws","resetRetryCountTimeout","addEventListener","e","setTimeout","undefined","msg","clearTimeout","code","_reconnect","error","response","parse","delay","Math","pow","_this$retryCount","_this$retryCount2"],"sources":["../../../src/websocket/MessageService.ts"],"sourcesContent":["export type MessageListener<T = unknown> = (response: T) => void;\nexport type CloseListener = () => void;\n\nconst RETRY_TIMEOUT_UNIT = 1000;\nconst RETRY_LIMIT = 5;\n\nexport class MessageService {\n #url: string;\n #ws: WebSocket | undefined;\n #queuedMessages: string[] = [];\n #messageListeners = new Set<MessageListener>();\n #closeListeners = new Set<CloseListener>();\n #retryCount = 0;\n #closed = false;\n\n constructor(url: string) {\n this.#url = url;\n }\n\n #connect(): WebSocket {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket connecting ...\");\n const ws = new WebSocket(this.#url);\n let resetRetryCountTimeout: number | undefined;\n ws.addEventListener(\"open\", (e) => {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket open:\", e);\n\n // If server closes the socket not more than 1 second after it's opened,\n // we should not reset the retry count.\n resetRetryCountTimeout = setTimeout(() => {\n resetRetryCountTimeout = undefined;\n this.#retryCount = 0;\n }, 1e3) as unknown as number;\n\n for (const msg of this.#queuedMessages) {\n ws.send(msg);\n }\n this.#queuedMessages.length = 0;\n });\n ws.addEventListener(\"close\", (e) => {\n if (this.#closed) {\n return;\n }\n if (resetRetryCountTimeout !== undefined) {\n clearTimeout(resetRetryCountTimeout);\n }\n // eslint-disable-next-line no-console\n console.log(\"WebSocket close:\", e);\n for (const listener of this.#closeListeners) {\n listener();\n }\n // Error code 1000 means that the connection was closed normally.\n if (e.code !== 1000) {\n this.#reconnect();\n }\n });\n ws.addEventListener(\"error\", (e) => {\n // No need to reconnect in error event listener,\n // there will always be a close event along with the error event.\n // eslint-disable-next-line no-console\n console.error(\"WebSocket error:\", e);\n });\n ws.addEventListener(\"message\", (e: MessageEvent<string>) => {\n const response = JSON.parse(e.data);\n for (const listener of this.#messageListeners) {\n listener(response);\n }\n });\n return ws;\n }\n\n #reconnect() {\n // istanbul ignore next: currently can't mock this\n if (this.#retryCount >= RETRY_LIMIT) {\n // eslint-disable-next-line no-console\n console.error(\"WebSocket connect retry limit exceeded\");\n return;\n }\n // Double the timeout for each retry\n const delay = Math.pow(2, this.#retryCount) * RETRY_TIMEOUT_UNIT;\n // eslint-disable-next-line no-console\n console.log(\"WebSocket will reconnect after %d seconds\", delay / 1000);\n setTimeout(() => {\n this.#retryCount++;\n this.#ws = this.#connect();\n }, delay);\n }\n\n send(data: unknown): void {\n // Connect when data is sent for the first time\n if (!this.#ws) {\n this.#ws = this.#connect();\n }\n const stringifiedData = JSON.stringify(data);\n if (this.#ws.readyState === WebSocket.OPEN) {\n this.#ws.send(stringifiedData);\n } else {\n this.#queuedMessages.push(stringifiedData);\n }\n }\n\n onMessage<T = unknown>(listener: MessageListener<T>) {\n this.#messageListeners.add(listener as MessageListener<unknown>);\n }\n\n onClose(listener: CloseListener) {\n this.#closeListeners.add(listener);\n }\n\n reset() {\n this.#queuedMessages.length = 0;\n this.#messageListeners.clear();\n this.#closeListeners.clear();\n }\n\n close() {\n this.#closed = true;\n if (this.#ws?.readyState === WebSocket.OPEN) {\n this.#ws.close();\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"MessageService.js","names":["RETRY_TIMEOUT_UNIT","RETRY_LIMIT","_url","WeakMap","_ws","_queuedMessages","_messageListeners","_closeListeners","_retryCount","_closed","_MessageService_brand","WeakSet","MessageService","constructor","url","_classPrivateMethodInitSpec","_classPrivateFieldInitSpec","Set","_classPrivateFieldSet","send","data","_classPrivateFieldGet","_assertClassBrand","_connect","call","stringifiedData","JSON","stringify","readyState","WebSocket","OPEN","push","onMessage","listener","add","delete","onClose","reset","length","clear","close","_classPrivateFieldGet2","console","log","ws","resetRetryCountTimeout","addEventListener","e","setTimeout","undefined","msg","clearTimeout","code","_reconnect","error","response","parse","delay","Math","pow","_this$retryCount","_this$retryCount2"],"sources":["../../../src/websocket/MessageService.ts"],"sourcesContent":["export type MessageListener<T = unknown> = (response: T) => void;\nexport type CloseListener = () => void;\n\nconst RETRY_TIMEOUT_UNIT = 1000;\nexport const RETRY_LIMIT = 5;\n\nexport class MessageService {\n #url: string;\n #ws: WebSocket | undefined;\n #queuedMessages: string[] = [];\n #messageListeners = new Set<MessageListener>();\n #closeListeners = new Set<CloseListener>();\n #retryCount = 0;\n #closed = false;\n\n constructor(url: string) {\n this.#url = url;\n }\n\n #connect(): WebSocket {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket connecting ...\");\n const ws = new WebSocket(this.#url);\n let resetRetryCountTimeout: number | undefined;\n ws.addEventListener(\"open\", (e) => {\n // eslint-disable-next-line no-console\n console.log(\"WebSocket open:\", e);\n\n // If server closes the socket not more than 1 second after it's opened,\n // we should not reset the retry count.\n resetRetryCountTimeout = setTimeout(() => {\n resetRetryCountTimeout = undefined;\n this.#retryCount = 0;\n }, 1e3) as unknown as number;\n\n for (const msg of this.#queuedMessages) {\n ws.send(msg);\n }\n this.#queuedMessages.length = 0;\n });\n ws.addEventListener(\"close\", (e) => {\n if (this.#closed) {\n return;\n }\n if (resetRetryCountTimeout !== undefined) {\n clearTimeout(resetRetryCountTimeout);\n }\n // eslint-disable-next-line no-console\n console.log(\"WebSocket close:\", e);\n // Error code 1000 means that the connection was closed normally.\n if (e.code !== 1000) {\n this.#reconnect();\n }\n });\n ws.addEventListener(\"error\", (e) => {\n // No need to reconnect in error event listener,\n // there will always be a close event along with the error event.\n // eslint-disable-next-line no-console\n console.error(\"WebSocket error:\", e);\n });\n ws.addEventListener(\"message\", (e: MessageEvent<string>) => {\n const response = JSON.parse(e.data);\n for (const listener of this.#messageListeners) {\n listener(response);\n }\n });\n return ws;\n }\n\n #reconnect() {\n // istanbul ignore next: currently can't mock this\n if (this.#retryCount >= RETRY_LIMIT) {\n // eslint-disable-next-line no-console\n console.error(\"WebSocket connect retry limit exceeded\");\n // Keep behavior as v2: emit close event only after retry limit exceeded\n for (const listener of this.#closeListeners) {\n listener();\n }\n return;\n }\n // Double the timeout for each retry\n const delay = Math.pow(2, this.#retryCount) * RETRY_TIMEOUT_UNIT;\n // eslint-disable-next-line no-console\n console.log(\"WebSocket will reconnect after %d seconds\", delay / 1000);\n setTimeout(() => {\n this.#retryCount++;\n this.#ws = this.#connect();\n }, delay);\n }\n\n send(data: unknown): void {\n // Connect when data is sent for the first time\n if (!this.#ws) {\n this.#ws = this.#connect();\n }\n const stringifiedData = JSON.stringify(data);\n if (this.#ws.readyState === WebSocket.OPEN) {\n this.#ws.send(stringifiedData);\n } else {\n this.#queuedMessages.push(stringifiedData);\n }\n }\n\n onMessage<T = unknown>(listener: MessageListener<T>) {\n this.#messageListeners.add(listener as MessageListener<unknown>);\n\n return () => {\n this.#messageListeners.delete(listener as MessageListener<unknown>);\n };\n }\n\n onClose(listener: CloseListener) {\n this.#closeListeners.add(listener);\n\n return () => {\n this.#closeListeners.delete(listener);\n };\n }\n\n reset() {\n this.#queuedMessages.length = 0;\n this.#messageListeners.clear();\n this.#closeListeners.clear();\n }\n\n close() {\n this.#closed = true;\n if (this.#ws?.readyState === WebSocket.OPEN) {\n this.#ws.close();\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -10,7 +10,7 @@ export declare class MessageDispatcher {
10
10
  subscribe(channel: string, payload: MessagePayload): Promise<unknown>;
11
11
  unsubscribe(channel: string): Promise<unknown>;
12
12
  onMessage(channel: string, listener: MessageListener): void;
13
- onClose(listener: CloseListener): void;
13
+ onClose(listener: CloseListener): () => void;
14
14
  reset(): void;
15
15
  }
16
16
  export {};
@@ -1,11 +1,12 @@
1
1
  export type MessageListener<T = unknown> = (response: T) => void;
2
2
  export type CloseListener = () => void;
3
+ export declare const RETRY_LIMIT = 5;
3
4
  export declare class MessageService {
4
5
  #private;
5
6
  constructor(url: string);
6
7
  send(data: unknown): void;
7
- onMessage<T = unknown>(listener: MessageListener<T>): void;
8
- onClose(listener: CloseListener): void;
8
+ onMessage<T = unknown>(listener: MessageListener<T>): () => void;
9
+ onClose(listener: CloseListener): () => void;
9
10
  reset(): void;
10
11
  close(): void;
11
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next-core/easyops-runtime",
3
- "version": "0.12.37",
3
+ "version": "0.12.39",
4
4
  "homepage": "https://github.com/easyops-cn/next-core/tree/v3/packages/easyops-runtime",
5
5
  "license": "GPL-3.0",
6
6
  "repository": {
@@ -48,7 +48,7 @@
48
48
  "@next-core/cook": "^2.5.2",
49
49
  "@next-core/http": "^1.2.8",
50
50
  "@next-core/pipes": "^2.0.27",
51
- "@next-core/runtime": "^1.57.3",
51
+ "@next-core/runtime": "^1.57.4",
52
52
  "@next-core/types": "^1.13.0",
53
53
  "@next-core/utils": "^1.7.27",
54
54
  "js-yaml": "^3.14.1",
@@ -60,5 +60,5 @@
60
60
  "jest-websocket-mock": "^2.5.0",
61
61
  "whatwg-fetch": "^3.6.20"
62
62
  },
63
- "gitHead": "39d27d474ec5eb8a21930801fac39eaf471e04e8"
63
+ "gitHead": "62daee3c6ea1f6d0767c3516b72fa859f124391c"
64
64
  }