@rc-ex/ws 1.2.1 → 1.2.2

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.
Files changed (52) hide show
  1. package/lib/exceptions/ClosedException.js.map +1 -1
  2. package/lib/exceptions/ClosedException.ts +7 -0
  3. package/lib/exceptions/ConnectionException.js.map +1 -1
  4. package/lib/exceptions/ConnectionException.ts +17 -0
  5. package/lib/exceptions/TimeoutException.js.map +1 -1
  6. package/lib/exceptions/TimeoutException.ts +7 -0
  7. package/lib/index.d.ts +2 -2
  8. package/lib/index.js +2 -2
  9. package/lib/index.js.map +1 -1
  10. package/lib/index.ts +418 -0
  11. package/lib/rest.d.ts +1 -1
  12. package/lib/rest.js +1 -1
  13. package/lib/rest.js.map +1 -1
  14. package/lib/rest.ts +71 -0
  15. package/lib/subscription.d.ts +2 -2
  16. package/lib/subscription.js.map +1 -1
  17. package/lib/subscription.ts +131 -0
  18. package/lib/types.d.ts +1 -1
  19. package/lib/types.js.map +1 -1
  20. package/lib/types.ts +85 -0
  21. package/lib/utils.js.map +1 -1
  22. package/lib/utils.ts +82 -0
  23. package/package.json +5 -5
  24. package/src/exceptions/ClosedException.d.ts +4 -0
  25. package/src/exceptions/ClosedException.js +9 -0
  26. package/src/exceptions/ClosedException.js.map +1 -0
  27. package/src/exceptions/ConnectionException.d.ts +7 -0
  28. package/src/exceptions/ConnectionException.js +16 -0
  29. package/src/exceptions/ConnectionException.js.map +1 -0
  30. package/src/exceptions/TimeoutException.d.ts +4 -0
  31. package/src/exceptions/TimeoutException.js +9 -0
  32. package/src/exceptions/TimeoutException.js.map +1 -0
  33. package/src/index.d.ts +44 -0
  34. package/src/index.js +329 -0
  35. package/src/index.js.map +1 -0
  36. package/src/index.ts +4 -4
  37. package/src/rest.d.ts +3 -0
  38. package/src/rest.js +55 -0
  39. package/src/rest.js.map +1 -0
  40. package/src/rest.ts +2 -2
  41. package/src/subscription.d.ts +20 -0
  42. package/src/subscription.js +91 -0
  43. package/src/subscription.js.map +1 -0
  44. package/src/subscription.ts +3 -3
  45. package/src/types.d.ts +61 -0
  46. package/src/types.js +3 -0
  47. package/src/types.js.map +1 -0
  48. package/src/types.ts +1 -1
  49. package/src/utils.d.ts +8 -0
  50. package/src/utils.js +72 -0
  51. package/src/utils.js.map +1 -0
  52. package/tsconfig.json +0 -3
@@ -0,0 +1,131 @@
1
+ import type CreateSubscriptionRequest from "@rc-ex/core/src/definitions/CreateSubscriptionRequest";
2
+ import type SubscriptionInfo from "@rc-ex/core/src/definitions/SubscriptionInfo";
3
+ import type { RestResponse } from "@rc-ex/core/src/types";
4
+ import type { MessageEvent } from "ws";
5
+
6
+ import type { WebSocketExtensionInterface, WsgEvent, WsgMeta } from "./types";
7
+ import Utils from "./utils";
8
+
9
+ class Subscription {
10
+ public subscriptionInfo?: SubscriptionInfo;
11
+
12
+ public wse: WebSocketExtensionInterface;
13
+
14
+ public eventFilters: string[];
15
+
16
+ public eventListener: (event: MessageEvent) => void;
17
+
18
+ public timeout?: NodeJS.Timeout;
19
+
20
+ public enabled = true;
21
+
22
+ public constructor(
23
+ wse: WebSocketExtensionInterface,
24
+ eventFilters: string[],
25
+ callback: (event: {}) => void,
26
+ ) {
27
+ this.wse = wse;
28
+ this.eventFilters = eventFilters;
29
+ this.eventListener = (mEvent: MessageEvent) => {
30
+ const event = mEvent as WsgEvent;
31
+ const [meta, body]: [WsgMeta, { subscriptionId: string }] = Utils
32
+ .splitWsgData(event.data);
33
+ if (
34
+ this.enabled && meta.type === "ServerNotification" &&
35
+ body.subscriptionId === this.subscriptionInfo!.id
36
+ ) {
37
+ callback(body);
38
+ }
39
+ };
40
+ this.setupWsEventListener();
41
+ }
42
+
43
+ public setupWsEventListener() {
44
+ this.wse.ws.addEventListener("message", this.eventListener);
45
+ }
46
+
47
+ public get requestBody(): CreateSubscriptionRequest {
48
+ return {
49
+ deliveryMode: { transportType: "WebSocket" as any }, // because WebSocket is not in spec
50
+ eventFilters: this.eventFilters,
51
+ };
52
+ }
53
+
54
+ public async subscribe() {
55
+ this.subscriptionInfo = (
56
+ await this.wse.request<SubscriptionInfo>(
57
+ "POST",
58
+ "/restapi/v1.0/subscription",
59
+ this.requestBody,
60
+ )
61
+ ).data;
62
+ }
63
+
64
+ public async refresh() {
65
+ if (!this.subscriptionInfo) {
66
+ return;
67
+ }
68
+ try {
69
+ this.subscriptionInfo = (
70
+ await this.wse.request<SubscriptionInfo>(
71
+ "PUT",
72
+ `/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`,
73
+ this.requestBody,
74
+ )
75
+ ).data;
76
+ } catch (e) {
77
+ const re = e as { response: RestResponse };
78
+ if (re.response && re.response.status === 404) {
79
+ // subscription expired
80
+ await this.subscribe();
81
+ }
82
+ }
83
+ }
84
+
85
+ public async revoke() {
86
+ if (!this.subscriptionInfo) {
87
+ return;
88
+ }
89
+ try {
90
+ await this.wse.request<SubscriptionInfo>(
91
+ "DELETE",
92
+ `/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`,
93
+ );
94
+ } catch (e) {
95
+ const re = e as { response: RestResponse };
96
+ if (re.response && re.response.status === 404) {
97
+ // ignore
98
+ if (this.wse.options.debugMode) {
99
+ console.debug(
100
+ `Subscription ${
101
+ this.subscriptionInfo!.id
102
+ } doesn't exist on server side`,
103
+ );
104
+ }
105
+ } else if (re.response && re.response.status === 401) {
106
+ // ignore
107
+ if (this.wse.options.debugMode) {
108
+ console.debug("Token invalid when trying to revoke subscription");
109
+ }
110
+ } else {
111
+ throw e;
112
+ }
113
+ }
114
+ this.remove();
115
+ }
116
+
117
+ public remove() {
118
+ if (this.timeout) {
119
+ global.clearTimeout(this.timeout);
120
+ this.timeout = undefined;
121
+ }
122
+ this.enabled = false;
123
+ this.subscriptionInfo = undefined;
124
+ if (this.wse.ws) {
125
+ this.wse.ws.removeEventListener("message", this.eventListener);
126
+ }
127
+ this.wse.subscription = undefined;
128
+ }
129
+ }
130
+
131
+ export default Subscription;
package/lib/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type RingCentral from "@rc-ex/core";
2
- import type { RestMethod, RestRequestConfig, RestResponse } from "@rc-ex/core/lib/types";
2
+ import type { RestMethod, RestRequestConfig, RestResponse } from "@rc-ex/core/src/types";
3
3
  import type WS from "isomorphic-ws";
4
4
  export interface WsToken {
5
5
  uri: string;
package/lib/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":""}
package/lib/types.ts ADDED
@@ -0,0 +1,85 @@
1
+ import type RingCentral from "@rc-ex/core";
2
+ import type {
3
+ RestMethod,
4
+ RestRequestConfig,
5
+ RestResponse,
6
+ } from "@rc-ex/core/src/types";
7
+ import type WS from "isomorphic-ws";
8
+
9
+ export interface WsToken {
10
+ uri: string;
11
+ ws_access_token: string;
12
+ expires_in: number;
13
+ }
14
+
15
+ export type CheckInterval = (retriesAttempted: number) => number;
16
+ export interface WebSocketOptions {
17
+ restOverWebSocket?: boolean;
18
+ debugMode?: boolean;
19
+ autoRecover?: {
20
+ enabled: boolean;
21
+ checkInterval?: CheckInterval;
22
+ pingServerInterval?: number;
23
+ };
24
+ wscToken?: string;
25
+ }
26
+
27
+ export interface WsgEvent {
28
+ data: string;
29
+ }
30
+
31
+ export interface Wsc {
32
+ token: string;
33
+ sequence: number;
34
+ }
35
+
36
+ export interface WsgMeta {
37
+ type:
38
+ | "ClientRequest"
39
+ | "ServerNotification"
40
+ | "Error"
41
+ | "ConnectionDetails"
42
+ | "Heartbeat";
43
+ messageId: string;
44
+ status: number;
45
+ headers: {
46
+ [key: string]: string;
47
+ };
48
+ wsc?: Wsc;
49
+ }
50
+
51
+ export interface WsgError {
52
+ errorCode: string;
53
+ message: string;
54
+ }
55
+
56
+ export interface ConnectionDetails {
57
+ creationTime: string;
58
+ maxConnectionsPerSession: number;
59
+ recoveryBufferSize: number;
60
+ recoveryTimeout: number;
61
+ idleTimeout: number;
62
+ absoluteTimeout: number;
63
+ maxActiveRequests: number;
64
+ recoveryState?: "Successful" | "Failed";
65
+ recoveryErrorCode?: string;
66
+ }
67
+
68
+ export interface WebSocketExtensionInterface {
69
+ options: WebSocketOptions;
70
+ subscription?: SubscriptionInterface;
71
+ ws: WS;
72
+ wsToken?: WsToken;
73
+ rc: RingCentral;
74
+ request: <T>(
75
+ method: RestMethod,
76
+ endpoint: string,
77
+ content?: {},
78
+ queryParams?: {},
79
+ config?: RestRequestConfig,
80
+ ) => Promise<RestResponse<T>>;
81
+ }
82
+
83
+ export interface SubscriptionInterface {
84
+ eventFilters: string[];
85
+ }
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"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"}
package/lib/utils.ts ADDED
@@ -0,0 +1,82 @@
1
+ import type { MessageEvent } from "isomorphic-ws";
2
+ import type WS from "isomorphic-ws";
3
+
4
+ import type { WsgEvent, WsgMeta } from "./types";
5
+ import ClosedException from "./exceptions/ClosedException";
6
+ import TimeoutException from "./exceptions/TimeoutException";
7
+
8
+ class Utils {
9
+ public static splitWsgData(wsgData: string): [WsgMeta, any] {
10
+ if (wsgData.includes(",--Boundary")) {
11
+ const index = wsgData.indexOf(",--Boundary");
12
+ return [
13
+ JSON.parse(wsgData.substring(1, index)),
14
+ wsgData.substring(index + 1, wsgData.length - 1),
15
+ ];
16
+ }
17
+ return JSON.parse(wsgData);
18
+ }
19
+
20
+ public static debugWebSocket(_ws: WS) {
21
+ const ws = _ws;
22
+ const send = ws.send.bind(ws);
23
+ ws.send = async (str: string) => {
24
+ await send(str);
25
+ console.debug(
26
+ `*** WebSocket outgoing message: ***
27
+ ${JSON.stringify(JSON.parse(str), null, 2)}
28
+ ******`,
29
+ );
30
+ };
31
+ ws.addEventListener("message", (mEvent: MessageEvent) => {
32
+ const event = mEvent as WsgEvent;
33
+ console.debug(
34
+ `*** WebSocket incoming message: ***
35
+ ${JSON.stringify(JSON.parse(event.data), null, 2)}
36
+ ******`,
37
+ );
38
+ });
39
+ ws.addEventListener("open", (event) => {
40
+ console.debug("WebSocket open event:", event);
41
+ });
42
+ ws.addEventListener("error", (event) => {
43
+ console.debug("WebSocket error event:", event);
44
+ });
45
+ ws.addEventListener("close", (event) => {
46
+ console.debug("WebSocket close event:", event);
47
+ });
48
+ }
49
+
50
+ public static waitForWebSocketMessage(
51
+ ws: WS,
52
+ matchCondition: (meta: WsgMeta) => boolean,
53
+ timeout = 60000,
54
+ ) {
55
+ return new Promise<[WsgMeta, any, WsgEvent]>((resolve, reject) => {
56
+ const checkHandle = setInterval(() => {
57
+ if (ws.readyState === ws.CLOSED) {
58
+ clearInterval(checkHandle);
59
+ reject(new ClosedException());
60
+ }
61
+ }, 1000);
62
+ const timeoutHandle = setTimeout(() => {
63
+ ws.removeEventListener("message", handler);
64
+ clearInterval(checkHandle);
65
+ reject(new TimeoutException());
66
+ }, timeout);
67
+ const handler = (mEvent: MessageEvent) => {
68
+ const event = mEvent as WsgEvent;
69
+ const [meta, body] = Utils.splitWsgData(event.data);
70
+ if (matchCondition(meta)) {
71
+ ws.removeEventListener("message", handler);
72
+ clearInterval(checkHandle);
73
+ clearTimeout(timeoutHandle);
74
+ resolve([meta, body, event]);
75
+ }
76
+ };
77
+ ws.addEventListener("message", handler);
78
+ });
79
+ }
80
+ }
81
+
82
+ export default Utils;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@rc-ex/ws",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "WebSocket extension for ringcentral-extensible project",
5
5
  "author": "Tyler Liu <tyler.liu@ringcentral.com>",
6
6
  "homepage": "https://github.com/ringcentral/ringcentral-extensible/tree/master/packages/extensions/ws",
7
7
  "license": "MIT",
8
- "main": "lib/index.js",
9
- "types": "lib/index.d.ts",
8
+ "main": "src/index.js",
9
+ "types": "src/index.d.ts",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git+https://github.com/ringcentral/ringcentral-extensible.git"
@@ -26,7 +26,7 @@
26
26
  "ws": "^8.18.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@rc-ex/core": "^1.5.1"
29
+ "@rc-ex/core": "^1.5.2"
30
30
  },
31
- "gitHead": "1a8a5becc832b92af73f1ad1f58b87f38fee3650"
31
+ "gitHead": "a0e465fd1f5d4b0758e6c3641635d5d2ee6c9a3a"
32
32
  }
@@ -0,0 +1,4 @@
1
+ declare class ClosedException extends Error {
2
+ constructor(message?: string);
3
+ }
4
+ export default ClosedException;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class ClosedException extends Error {
4
+ constructor(message) {
5
+ super(message !== null && message !== void 0 ? message : "WebSocket has been closed");
6
+ }
7
+ }
8
+ exports.default = ClosedException;
9
+ //# sourceMappingURL=ClosedException.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClosedException.js","sourceRoot":"","sources":["ClosedException.ts"],"names":[],"mappings":";;AAAA,MAAM,eAAgB,SAAQ,KAAK;IACjC,YAAmB,OAAgB;QACjC,KAAK,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,2BAA2B,CAAC,CAAC;IAChD,CAAC;CACF;AAED,kBAAe,eAAe,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { WsgError, WsgEvent } from "../types";
2
+ declare class ConnectionException extends Error {
3
+ wsgEvent: WsgEvent;
4
+ wsgError: WsgError;
5
+ constructor(wsgEvent: WsgEvent);
6
+ }
7
+ export default ConnectionException;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = __importDefault(require("../utils"));
7
+ class ConnectionException extends Error {
8
+ constructor(wsgEvent) {
9
+ const [, wsgError] = utils_1.default.splitWsgData(wsgEvent.data);
10
+ super(JSON.stringify(wsgError, null, 2));
11
+ this.wsgEvent = wsgEvent;
12
+ this.wsgError = wsgError;
13
+ }
14
+ }
15
+ exports.default = ConnectionException;
16
+ //# sourceMappingURL=ConnectionException.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionException.js","sourceRoot":"","sources":["ConnectionException.ts"],"names":[],"mappings":";;;;;AACA,qDAA6B;AAE7B,MAAM,mBAAoB,SAAQ,KAAK;IAKrC,YAAmB,QAAkB;QACnC,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAwB,eAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5E,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED,kBAAe,mBAAmB,CAAC"}
@@ -0,0 +1,4 @@
1
+ declare class TimeoutException extends Error {
2
+ constructor(message?: string);
3
+ }
4
+ export default TimeoutException;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class TimeoutException extends Error {
4
+ constructor(message) {
5
+ super(message !== null && message !== void 0 ? message : "Failed to receive expected WebSocket message in time.");
6
+ }
7
+ }
8
+ exports.default = TimeoutException;
9
+ //# sourceMappingURL=TimeoutException.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeoutException.js","sourceRoot":"","sources":["TimeoutException.ts"],"names":[],"mappings":";;AAAA,MAAM,gBAAiB,SAAQ,KAAK;IAClC,YAAmB,OAAgB;QACjC,KAAK,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,uDAAuD,CAAC,CAAC;IAC5E,CAAC;CACF;AAED,kBAAe,gBAAgB,CAAC"}
package/src/index.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import type RingCentral from "@rc-ex/core";
2
+ import SdkExtension from "@rc-ex/core/src/SdkExtension";
3
+ import WS from "isomorphic-ws";
4
+ import { EventEmitter } from "events";
5
+ import type SubscriptionInfo from "@rc-ex/core/src/definitions/SubscriptionInfo";
6
+ import { request } from "./rest";
7
+ import type { ConnectionDetails, WebSocketOptions, Wsc, WsToken } from "./types";
8
+ import Subscription from "./subscription";
9
+ export declare enum Events {
10
+ autoRecoverSuccess = "autoRecoverSuccess",
11
+ autoRecoverFailed = "autoRecoverFailed",
12
+ autoRecoverError = "autoRecoverError",
13
+ newWebSocketObject = "newWebSocketObject",
14
+ newWsc = "newWsc",
15
+ connectionReady = "connectionReady"
16
+ }
17
+ declare class WebSocketExtension extends SdkExtension {
18
+ eventEmitter: EventEmitter<[never]>;
19
+ options: WebSocketOptions;
20
+ rc: RingCentral;
21
+ wsToken?: WsToken;
22
+ wsTokenExpiresAt: number;
23
+ ws: WS;
24
+ connectionDetails: ConnectionDetails;
25
+ wsc?: Wsc;
26
+ subscription?: Subscription;
27
+ intervalHandle?: NodeJS.Timeout;
28
+ recoverTimestamp?: number;
29
+ pingServerHandle?: NodeJS.Timeout;
30
+ _recoverPromise?: Promise<void>;
31
+ _connectPromise?: Promise<void>;
32
+ request: typeof request;
33
+ constructor(options?: WebSocketOptions);
34
+ disable(): void;
35
+ install(rc: RingCentral): Promise<void>;
36
+ recover(): Promise<void>;
37
+ _recover(): Promise<void>;
38
+ pingServer(): Promise<void>;
39
+ connect(recoverSession?: boolean): Promise<void>;
40
+ _connect(recoverSession?: boolean): Promise<void>;
41
+ revoke(keepInterval?: boolean): Promise<void>;
42
+ subscribe(eventFilters: string[], callback: (event: {}) => void, cache?: SubscriptionInfo | undefined | null): Promise<Subscription>;
43
+ }
44
+ export default WebSocketExtension;