@rc-ex/ws 1.2.0 → 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 (63) hide show
  1. package/README.md +49 -22
  2. package/lib/exceptions/ClosedException.js +1 -1
  3. package/lib/exceptions/ClosedException.js.map +1 -1
  4. package/lib/exceptions/ClosedException.ts +7 -0
  5. package/lib/exceptions/ConnectionException.d.ts +1 -1
  6. package/lib/exceptions/ConnectionException.js.map +1 -1
  7. package/lib/exceptions/ConnectionException.ts +17 -0
  8. package/lib/exceptions/TimeoutException.js +1 -1
  9. package/lib/exceptions/TimeoutException.js.map +1 -1
  10. package/lib/exceptions/TimeoutException.ts +7 -0
  11. package/lib/index.d.ts +8 -8
  12. package/lib/index.js +23 -23
  13. package/lib/index.js.map +1 -1
  14. package/lib/index.ts +418 -0
  15. package/lib/rest.d.ts +2 -2
  16. package/lib/rest.js +5 -6
  17. package/lib/rest.js.map +1 -1
  18. package/lib/rest.ts +71 -0
  19. package/lib/subscription.d.ts +4 -4
  20. package/lib/subscription.js +11 -9
  21. package/lib/subscription.js.map +1 -1
  22. package/lib/subscription.ts +131 -0
  23. package/lib/types.d.ts +5 -5
  24. package/lib/types.js.map +1 -1
  25. package/lib/types.ts +85 -0
  26. package/lib/utils.d.ts +2 -2
  27. package/lib/utils.js +16 -16
  28. package/lib/utils.js.map +1 -1
  29. package/lib/utils.ts +82 -0
  30. package/package.json +6 -6
  31. package/src/exceptions/ClosedException.d.ts +4 -0
  32. package/src/exceptions/ClosedException.js +9 -0
  33. package/src/exceptions/ClosedException.js.map +1 -0
  34. package/src/exceptions/ClosedException.ts +1 -1
  35. package/src/exceptions/ConnectionException.d.ts +7 -0
  36. package/src/exceptions/ConnectionException.js +16 -0
  37. package/src/exceptions/ConnectionException.js.map +1 -0
  38. package/src/exceptions/ConnectionException.ts +2 -2
  39. package/src/exceptions/TimeoutException.d.ts +4 -0
  40. package/src/exceptions/TimeoutException.js +9 -0
  41. package/src/exceptions/TimeoutException.js.map +1 -0
  42. package/src/exceptions/TimeoutException.ts +1 -1
  43. package/src/index.d.ts +44 -0
  44. package/src/index.js +329 -0
  45. package/src/index.js.map +1 -0
  46. package/src/index.ts +81 -51
  47. package/src/rest.d.ts +3 -0
  48. package/src/rest.js +55 -0
  49. package/src/rest.js.map +1 -0
  50. package/src/rest.ts +22 -12
  51. package/src/subscription.d.ts +20 -0
  52. package/src/subscription.js +91 -0
  53. package/src/subscription.js.map +1 -0
  54. package/src/subscription.ts +36 -18
  55. package/src/types.d.ts +61 -0
  56. package/src/types.js +3 -0
  57. package/src/types.js.map +1 -0
  58. package/src/types.ts +14 -5
  59. package/src/utils.d.ts +8 -0
  60. package/src/utils.js +72 -0
  61. package/src/utils.js.map +1 -0
  62. package/src/utils.ts +26 -23
  63. package/tsconfig.json +0 -3
package/src/rest.js ADDED
@@ -0,0 +1,55 @@
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
+ exports.request = request;
7
+ const RestException_1 = __importDefault(require("@rc-ex/core/src/RestException"));
8
+ const hyperid_1 = __importDefault(require("hyperid"));
9
+ const http_status_codes_1 = require("http-status-codes");
10
+ const utils_1 = __importDefault(require("./utils"));
11
+ const version = "0.16";
12
+ const uuid = (0, hyperid_1.default)();
13
+ async function request(method, endpoint, content, queryParams, config) {
14
+ var _a;
15
+ const newConfig = {
16
+ method,
17
+ baseURL: (_a = this.wsToken) === null || _a === void 0 ? void 0 : _a.uri,
18
+ url: endpoint,
19
+ data: content,
20
+ params: queryParams,
21
+ ...config,
22
+ };
23
+ newConfig.headers = {
24
+ ...newConfig.headers,
25
+ "X-User-Agent": `${this.rc.rest.appName}/${this.rc.rest.appVersion} ringcentral-extensible/ws/${version}`,
26
+ };
27
+ const messageId = uuid();
28
+ const requestBody = [
29
+ {
30
+ type: "ClientRequest",
31
+ messageId,
32
+ method: newConfig.method,
33
+ path: newConfig.url,
34
+ headers: newConfig.headers,
35
+ query: newConfig.params,
36
+ },
37
+ ];
38
+ if (newConfig.data) {
39
+ requestBody.push(newConfig.data);
40
+ }
41
+ await this.ws.send(JSON.stringify(requestBody));
42
+ const [meta, body] = await utils_1.default.waitForWebSocketMessage(this.ws, (_meta) => _meta.messageId === messageId);
43
+ const response = {
44
+ data: body,
45
+ status: meta.status,
46
+ statusText: (0, http_status_codes_1.getReasonPhrase)(meta.status),
47
+ headers: meta.headers,
48
+ config: newConfig,
49
+ };
50
+ if (meta.type === "ClientRequest" && meta.status >= 200 && meta.status < 300) {
51
+ return response;
52
+ }
53
+ throw new RestException_1.default(response);
54
+ }
55
+ //# sourceMappingURL=rest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.js","sourceRoot":"","sources":["rest.ts"],"names":[],"mappings":";;;;;AAgBA,0BAsDC;AAjED,kFAA0D;AAC1D,sDAA8B;AAC9B,yDAAoD;AAEpD,oDAA4B;AAG5B,MAAM,OAAO,GAAG,MAAM,CAAC;AAEvB,MAAM,IAAI,GAAG,IAAA,iBAAO,GAAE,CAAC;AAEhB,KAAK,UAAU,OAAO,CAE3B,MAAkB,EAClB,QAAgB,EAChB,OAAY,EACZ,WAAgB,EAChB,MAA0B;;IAE1B,MAAM,SAAS,GAAsB;QACnC,MAAM;QACN,OAAO,EAAE,MAAA,IAAI,CAAC,OAAO,0CAAE,GAAG;QAC1B,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,WAAW;QACnB,GAAG,MAAM;KACV,CAAC;IACF,SAAS,CAAC,OAAO,GAAG;QAClB,GAAG,SAAS,CAAC,OAAO;QACpB,cAAc,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,IAAK,CAAC,OAAO,IACtC,IAAI,CAAC,EAAE,CAAC,IAAK,CAAC,UAChB,8BAA8B,OAAO,EAAE;KACjC,CAAC;IACT,MAAM,SAAS,GAAG,IAAI,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG;QAClB;YACE,IAAI,EAAE,eAAe;YACrB,SAAS;YACT,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,IAAI,EAAE,SAAS,CAAC,GAAG;YACnB,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,KAAK,EAAE,SAAS,CAAC,MAAM;SACxB;KACF,CAAC;IACF,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;QACnB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,eAAK,CAAC,uBAAuB,CACtD,IAAI,CAAC,EAAE,EACP,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CACzC,CAAC;IACF,MAAM,QAAQ,GAAiB;QAC7B,IAAI,EAAE,IAAS;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAA,mCAAe,EAAC,IAAI,CAAC,MAAM,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,SAAgB;KACzB,CAAC;IACF,IACE,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,EACxE,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,uBAAa,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC"}
package/src/rest.ts CHANGED
@@ -1,16 +1,19 @@
1
- import type { RestMethod, RestRequestConfig, RestResponse } from '@rc-ex/core/lib/types';
2
- import RestException from '@rc-ex/core/lib/RestException';
3
- import hyperid from 'hyperid';
4
- import { getReasonPhrase } from 'http-status-codes';
1
+ import type {
2
+ RestMethod,
3
+ RestRequestConfig,
4
+ RestResponse,
5
+ } from "@rc-ex/core/src/types";
6
+ import RestException from "@rc-ex/core/src/RestException";
7
+ import hyperid from "hyperid";
8
+ import { getReasonPhrase } from "http-status-codes";
5
9
 
6
- import Utils from './utils';
7
- import type { WebSocketExtensionInterface } from './types';
10
+ import Utils from "./utils";
11
+ import type { WebSocketExtensionInterface } from "./types";
8
12
 
9
- const version = '0.16';
13
+ const version = "0.16";
10
14
 
11
15
  const uuid = hyperid();
12
16
 
13
- // eslint-disable-next-line max-params
14
17
  export async function request<T>(
15
18
  this: WebSocketExtensionInterface,
16
19
  method: RestMethod,
@@ -29,12 +32,14 @@ export async function request<T>(
29
32
  };
30
33
  newConfig.headers = {
31
34
  ...newConfig.headers,
32
- 'X-User-Agent': `${this.rc.rest!.appName}/${this.rc.rest!.appVersion} ringcentral-extensible/ws/${version}`,
35
+ "X-User-Agent": `${this.rc.rest!.appName}/${
36
+ this.rc.rest!.appVersion
37
+ } ringcentral-extensible/ws/${version}`,
33
38
  } as any;
34
39
  const messageId = uuid();
35
40
  const requestBody = [
36
41
  {
37
- type: 'ClientRequest',
42
+ type: "ClientRequest",
38
43
  messageId,
39
44
  method: newConfig.method,
40
45
  path: newConfig.url,
@@ -46,7 +51,10 @@ export async function request<T>(
46
51
  requestBody.push(newConfig.data);
47
52
  }
48
53
  await this.ws.send(JSON.stringify(requestBody));
49
- const [meta, body] = await Utils.waitForWebSocketMessage(this.ws, (_meta) => _meta.messageId === messageId);
54
+ const [meta, body] = await Utils.waitForWebSocketMessage(
55
+ this.ws,
56
+ (_meta) => _meta.messageId === messageId,
57
+ );
50
58
  const response: RestResponse = {
51
59
  data: body as T,
52
60
  status: meta.status,
@@ -54,7 +62,9 @@ export async function request<T>(
54
62
  headers: meta.headers,
55
63
  config: newConfig as any,
56
64
  };
57
- if (meta.type === 'ClientRequest' && meta.status >= 200 && meta.status < 300) {
65
+ if (
66
+ meta.type === "ClientRequest" && meta.status >= 200 && meta.status < 300
67
+ ) {
58
68
  return response;
59
69
  }
60
70
  throw new RestException(response);
@@ -0,0 +1,20 @@
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 { MessageEvent } from "ws";
4
+ import type { WebSocketExtensionInterface } from "./types";
5
+ declare class Subscription {
6
+ subscriptionInfo?: SubscriptionInfo;
7
+ wse: WebSocketExtensionInterface;
8
+ eventFilters: string[];
9
+ eventListener: (event: MessageEvent) => void;
10
+ timeout?: NodeJS.Timeout;
11
+ enabled: boolean;
12
+ constructor(wse: WebSocketExtensionInterface, eventFilters: string[], callback: (event: {}) => void);
13
+ setupWsEventListener(): void;
14
+ get requestBody(): CreateSubscriptionRequest;
15
+ subscribe(): Promise<void>;
16
+ refresh(): Promise<void>;
17
+ revoke(): Promise<void>;
18
+ remove(): void;
19
+ }
20
+ export default Subscription;
@@ -0,0 +1,91 @@
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 Subscription {
8
+ constructor(wse, eventFilters, callback) {
9
+ this.enabled = true;
10
+ this.wse = wse;
11
+ this.eventFilters = eventFilters;
12
+ this.eventListener = (mEvent) => {
13
+ const event = mEvent;
14
+ const [meta, body] = utils_1.default
15
+ .splitWsgData(event.data);
16
+ if (this.enabled && meta.type === "ServerNotification" &&
17
+ body.subscriptionId === this.subscriptionInfo.id) {
18
+ callback(body);
19
+ }
20
+ };
21
+ this.setupWsEventListener();
22
+ }
23
+ setupWsEventListener() {
24
+ this.wse.ws.addEventListener("message", this.eventListener);
25
+ }
26
+ get requestBody() {
27
+ return {
28
+ deliveryMode: { transportType: "WebSocket" }, // because WebSocket is not in spec
29
+ eventFilters: this.eventFilters,
30
+ };
31
+ }
32
+ async subscribe() {
33
+ this.subscriptionInfo = (await this.wse.request("POST", "/restapi/v1.0/subscription", this.requestBody)).data;
34
+ }
35
+ async refresh() {
36
+ if (!this.subscriptionInfo) {
37
+ return;
38
+ }
39
+ try {
40
+ this.subscriptionInfo = (await this.wse.request("PUT", `/restapi/v1.0/subscription/${this.subscriptionInfo.id}`, this.requestBody)).data;
41
+ }
42
+ catch (e) {
43
+ const re = e;
44
+ if (re.response && re.response.status === 404) {
45
+ // subscription expired
46
+ await this.subscribe();
47
+ }
48
+ }
49
+ }
50
+ async revoke() {
51
+ if (!this.subscriptionInfo) {
52
+ return;
53
+ }
54
+ try {
55
+ await this.wse.request("DELETE", `/restapi/v1.0/subscription/${this.subscriptionInfo.id}`);
56
+ }
57
+ catch (e) {
58
+ const re = e;
59
+ if (re.response && re.response.status === 404) {
60
+ // ignore
61
+ if (this.wse.options.debugMode) {
62
+ console.debug(`Subscription ${this.subscriptionInfo.id} doesn't exist on server side`);
63
+ }
64
+ }
65
+ else if (re.response && re.response.status === 401) {
66
+ // ignore
67
+ if (this.wse.options.debugMode) {
68
+ console.debug("Token invalid when trying to revoke subscription");
69
+ }
70
+ }
71
+ else {
72
+ throw e;
73
+ }
74
+ }
75
+ this.remove();
76
+ }
77
+ remove() {
78
+ if (this.timeout) {
79
+ global.clearTimeout(this.timeout);
80
+ this.timeout = undefined;
81
+ }
82
+ this.enabled = false;
83
+ this.subscriptionInfo = undefined;
84
+ if (this.wse.ws) {
85
+ this.wse.ws.removeEventListener("message", this.eventListener);
86
+ }
87
+ this.wse.subscription = undefined;
88
+ }
89
+ }
90
+ exports.default = Subscription;
91
+ //# sourceMappingURL=subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["subscription.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,10 @@
1
- /* eslint-disable no-console */
2
- import type CreateSubscriptionRequest from '@rc-ex/core/lib/definitions/CreateSubscriptionRequest';
3
- import type SubscriptionInfo from '@rc-ex/core/lib/definitions/SubscriptionInfo';
4
- import type { RestResponse } from '@rc-ex/core/lib/types';
5
- import type { MessageEvent } from 'ws';
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";
6
5
 
7
- import type { WsgEvent, WsgMeta, WebSocketExtensionInterface } from './types';
8
- import Utils from './utils';
6
+ import type { WebSocketExtensionInterface, WsgEvent, WsgMeta } from "./types";
7
+ import Utils from "./utils";
9
8
 
10
9
  class Subscription {
11
10
  public subscriptionInfo?: SubscriptionInfo;
@@ -20,13 +19,21 @@ class Subscription {
20
19
 
21
20
  public enabled = true;
22
21
 
23
- public constructor(wse: WebSocketExtensionInterface, eventFilters: string[], callback: (event: {}) => void) {
22
+ public constructor(
23
+ wse: WebSocketExtensionInterface,
24
+ eventFilters: string[],
25
+ callback: (event: {}) => void,
26
+ ) {
24
27
  this.wse = wse;
25
28
  this.eventFilters = eventFilters;
26
29
  this.eventListener = (mEvent: MessageEvent) => {
27
30
  const event = mEvent as WsgEvent;
28
- const [meta, body]: [WsgMeta, { subscriptionId: string }] = Utils.splitWsgData(event.data);
29
- if (this.enabled && meta.type === 'ServerNotification' && body.subscriptionId === this.subscriptionInfo!.id) {
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
+ ) {
30
37
  callback(body);
31
38
  }
32
39
  };
@@ -34,19 +41,23 @@ class Subscription {
34
41
  }
35
42
 
36
43
  public setupWsEventListener() {
37
- this.wse.ws.addEventListener('message', this.eventListener);
44
+ this.wse.ws.addEventListener("message", this.eventListener);
38
45
  }
39
46
 
40
47
  public get requestBody(): CreateSubscriptionRequest {
41
48
  return {
42
- deliveryMode: { transportType: 'WebSocket' as any }, // because WebSocket is not in spec
49
+ deliveryMode: { transportType: "WebSocket" as any }, // because WebSocket is not in spec
43
50
  eventFilters: this.eventFilters,
44
51
  };
45
52
  }
46
53
 
47
54
  public async subscribe() {
48
55
  this.subscriptionInfo = (
49
- await this.wse.request<SubscriptionInfo>('POST', '/restapi/v1.0/subscription', this.requestBody)
56
+ await this.wse.request<SubscriptionInfo>(
57
+ "POST",
58
+ "/restapi/v1.0/subscription",
59
+ this.requestBody,
60
+ )
50
61
  ).data;
51
62
  }
52
63
 
@@ -57,7 +68,7 @@ class Subscription {
57
68
  try {
58
69
  this.subscriptionInfo = (
59
70
  await this.wse.request<SubscriptionInfo>(
60
- 'PUT',
71
+ "PUT",
61
72
  `/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`,
62
73
  this.requestBody,
63
74
  )
@@ -76,18 +87,25 @@ class Subscription {
76
87
  return;
77
88
  }
78
89
  try {
79
- await this.wse.request<SubscriptionInfo>('DELETE', `/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`);
90
+ await this.wse.request<SubscriptionInfo>(
91
+ "DELETE",
92
+ `/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`,
93
+ );
80
94
  } catch (e) {
81
95
  const re = e as { response: RestResponse };
82
96
  if (re.response && re.response.status === 404) {
83
97
  // ignore
84
98
  if (this.wse.options.debugMode) {
85
- console.debug(`Subscription ${this.subscriptionInfo!.id} doesn't exist on server side`);
99
+ console.debug(
100
+ `Subscription ${
101
+ this.subscriptionInfo!.id
102
+ } doesn't exist on server side`,
103
+ );
86
104
  }
87
105
  } else if (re.response && re.response.status === 401) {
88
106
  // ignore
89
107
  if (this.wse.options.debugMode) {
90
- console.debug('Token invalid when trying to revoke subscription');
108
+ console.debug("Token invalid when trying to revoke subscription");
91
109
  }
92
110
  } else {
93
111
  throw e;
@@ -104,7 +122,7 @@ class Subscription {
104
122
  this.enabled = false;
105
123
  this.subscriptionInfo = undefined;
106
124
  if (this.wse.ws) {
107
- this.wse.ws.removeEventListener('message', this.eventListener);
125
+ this.wse.ws.removeEventListener("message", this.eventListener);
108
126
  }
109
127
  this.wse.subscription = undefined;
110
128
  }
package/src/types.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import type RingCentral from "@rc-ex/core";
2
+ import type { RestMethod, RestRequestConfig, RestResponse } from "@rc-ex/core/src/types";
3
+ import type WS from "isomorphic-ws";
4
+ export interface WsToken {
5
+ uri: string;
6
+ ws_access_token: string;
7
+ expires_in: number;
8
+ }
9
+ export type CheckInterval = (retriesAttempted: number) => number;
10
+ export interface WebSocketOptions {
11
+ restOverWebSocket?: boolean;
12
+ debugMode?: boolean;
13
+ autoRecover?: {
14
+ enabled: boolean;
15
+ checkInterval?: CheckInterval;
16
+ pingServerInterval?: number;
17
+ };
18
+ wscToken?: string;
19
+ }
20
+ export interface WsgEvent {
21
+ data: string;
22
+ }
23
+ export interface Wsc {
24
+ token: string;
25
+ sequence: number;
26
+ }
27
+ export interface WsgMeta {
28
+ type: "ClientRequest" | "ServerNotification" | "Error" | "ConnectionDetails" | "Heartbeat";
29
+ messageId: string;
30
+ status: number;
31
+ headers: {
32
+ [key: string]: string;
33
+ };
34
+ wsc?: Wsc;
35
+ }
36
+ export interface WsgError {
37
+ errorCode: string;
38
+ message: string;
39
+ }
40
+ export interface ConnectionDetails {
41
+ creationTime: string;
42
+ maxConnectionsPerSession: number;
43
+ recoveryBufferSize: number;
44
+ recoveryTimeout: number;
45
+ idleTimeout: number;
46
+ absoluteTimeout: number;
47
+ maxActiveRequests: number;
48
+ recoveryState?: "Successful" | "Failed";
49
+ recoveryErrorCode?: string;
50
+ }
51
+ export interface WebSocketExtensionInterface {
52
+ options: WebSocketOptions;
53
+ subscription?: SubscriptionInterface;
54
+ ws: WS;
55
+ wsToken?: WsToken;
56
+ rc: RingCentral;
57
+ request: <T>(method: RestMethod, endpoint: string, content?: {}, queryParams?: {}, config?: RestRequestConfig) => Promise<RestResponse<T>>;
58
+ }
59
+ export interface SubscriptionInterface {
60
+ eventFilters: string[];
61
+ }
package/src/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":""}
package/src/types.ts CHANGED
@@ -1,6 +1,10 @@
1
- import type RingCentral from '@rc-ex/core';
2
- import type { RestMethod, RestRequestConfig, RestResponse } from '@rc-ex/core/lib/types';
3
- import type WS from 'isomorphic-ws';
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";
4
8
 
5
9
  export interface WsToken {
6
10
  uri: string;
@@ -30,7 +34,12 @@ export interface Wsc {
30
34
  }
31
35
 
32
36
  export interface WsgMeta {
33
- type: 'ClientRequest' | 'ServerNotification' | 'Error' | 'ConnectionDetails' | 'Heartbeat';
37
+ type:
38
+ | "ClientRequest"
39
+ | "ServerNotification"
40
+ | "Error"
41
+ | "ConnectionDetails"
42
+ | "Heartbeat";
34
43
  messageId: string;
35
44
  status: number;
36
45
  headers: {
@@ -52,7 +61,7 @@ export interface ConnectionDetails {
52
61
  idleTimeout: number;
53
62
  absoluteTimeout: number;
54
63
  maxActiveRequests: number;
55
- recoveryState?: 'Successful' | 'Failed';
64
+ recoveryState?: "Successful" | "Failed";
56
65
  recoveryErrorCode?: string;
57
66
  }
58
67
 
package/src/utils.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type WS from "isomorphic-ws";
2
+ import type { WsgEvent, WsgMeta } from "./types";
3
+ declare class Utils {
4
+ static splitWsgData(wsgData: string): [WsgMeta, any];
5
+ static debugWebSocket(_ws: WS): void;
6
+ static waitForWebSocketMessage(ws: WS, matchCondition: (meta: WsgMeta) => boolean, timeout?: number): Promise<[WsgMeta, any, WsgEvent]>;
7
+ }
8
+ export default Utils;
package/src/utils.js ADDED
@@ -0,0 +1,72 @@
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 ClosedException_1 = __importDefault(require("./exceptions/ClosedException"));
7
+ const TimeoutException_1 = __importDefault(require("./exceptions/TimeoutException"));
8
+ class Utils {
9
+ static splitWsgData(wsgData) {
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
+ static debugWebSocket(_ws) {
20
+ const ws = _ws;
21
+ const send = ws.send.bind(ws);
22
+ ws.send = async (str) => {
23
+ await send(str);
24
+ console.debug(`*** WebSocket outgoing message: ***
25
+ ${JSON.stringify(JSON.parse(str), null, 2)}
26
+ ******`);
27
+ };
28
+ ws.addEventListener("message", (mEvent) => {
29
+ const event = mEvent;
30
+ console.debug(`*** WebSocket incoming message: ***
31
+ ${JSON.stringify(JSON.parse(event.data), null, 2)}
32
+ ******`);
33
+ });
34
+ ws.addEventListener("open", (event) => {
35
+ console.debug("WebSocket open event:", event);
36
+ });
37
+ ws.addEventListener("error", (event) => {
38
+ console.debug("WebSocket error event:", event);
39
+ });
40
+ ws.addEventListener("close", (event) => {
41
+ console.debug("WebSocket close event:", event);
42
+ });
43
+ }
44
+ static waitForWebSocketMessage(ws, matchCondition, timeout = 60000) {
45
+ return new Promise((resolve, reject) => {
46
+ const checkHandle = setInterval(() => {
47
+ if (ws.readyState === ws.CLOSED) {
48
+ clearInterval(checkHandle);
49
+ reject(new ClosedException_1.default());
50
+ }
51
+ }, 1000);
52
+ const timeoutHandle = setTimeout(() => {
53
+ ws.removeEventListener("message", handler);
54
+ clearInterval(checkHandle);
55
+ reject(new TimeoutException_1.default());
56
+ }, timeout);
57
+ const handler = (mEvent) => {
58
+ const event = mEvent;
59
+ const [meta, body] = Utils.splitWsgData(event.data);
60
+ if (matchCondition(meta)) {
61
+ ws.removeEventListener("message", handler);
62
+ clearInterval(checkHandle);
63
+ clearTimeout(timeoutHandle);
64
+ resolve([meta, body, event]);
65
+ }
66
+ };
67
+ ws.addEventListener("message", handler);
68
+ });
69
+ }
70
+ }
71
+ exports.default = Utils;
72
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"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"}
package/src/utils.ts CHANGED
@@ -1,17 +1,18 @@
1
- /* eslint-disable no-console */
2
- import type { MessageEvent } from 'isomorphic-ws';
3
- import type WS from 'isomorphic-ws';
1
+ import type { MessageEvent } from "isomorphic-ws";
2
+ import type WS from "isomorphic-ws";
4
3
 
5
- import type { WsgMeta, WsgEvent } from './types';
6
- import ClosedException from './exceptions/ClosedException';
7
- import TimeoutException from './exceptions/TimeoutException';
4
+ import type { WsgEvent, WsgMeta } from "./types";
5
+ import ClosedException from "./exceptions/ClosedException";
6
+ import TimeoutException from "./exceptions/TimeoutException";
8
7
 
9
8
  class Utils {
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
9
  public static splitWsgData(wsgData: string): [WsgMeta, any] {
12
- if (wsgData.includes(',--Boundary')) {
13
- const index = wsgData.indexOf(',--Boundary');
14
- return [JSON.parse(wsgData.substring(1, index)), wsgData.substring(index + 1, wsgData.length - 1)];
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
+ ];
15
16
  }
16
17
  return JSON.parse(wsgData);
17
18
  }
@@ -27,7 +28,7 @@ ${JSON.stringify(JSON.parse(str), null, 2)}
27
28
  ******`,
28
29
  );
29
30
  };
30
- ws.addEventListener('message', (mEvent: MessageEvent) => {
31
+ ws.addEventListener("message", (mEvent: MessageEvent) => {
31
32
  const event = mEvent as WsgEvent;
32
33
  console.debug(
33
34
  `*** WebSocket incoming message: ***
@@ -35,19 +36,22 @@ ${JSON.stringify(JSON.parse(event.data), null, 2)}
35
36
  ******`,
36
37
  );
37
38
  });
38
- ws.addEventListener('open', (event) => {
39
- console.debug('WebSocket open event:', event);
39
+ ws.addEventListener("open", (event) => {
40
+ console.debug("WebSocket open event:", event);
40
41
  });
41
- ws.addEventListener('error', (event) => {
42
- console.debug('WebSocket error event:', event);
42
+ ws.addEventListener("error", (event) => {
43
+ console.debug("WebSocket error event:", event);
43
44
  });
44
- ws.addEventListener('close', (event) => {
45
- console.debug('WebSocket close event:', event);
45
+ ws.addEventListener("close", (event) => {
46
+ console.debug("WebSocket close event:", event);
46
47
  });
47
48
  }
48
49
 
49
- public static waitForWebSocketMessage(ws: WS, matchCondition: (meta: WsgMeta) => boolean, timeout = 60000) {
50
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
+ public static waitForWebSocketMessage(
51
+ ws: WS,
52
+ matchCondition: (meta: WsgMeta) => boolean,
53
+ timeout = 60000,
54
+ ) {
51
55
  return new Promise<[WsgMeta, any, WsgEvent]>((resolve, reject) => {
52
56
  const checkHandle = setInterval(() => {
53
57
  if (ws.readyState === ws.CLOSED) {
@@ -56,8 +60,7 @@ ${JSON.stringify(JSON.parse(event.data), null, 2)}
56
60
  }
57
61
  }, 1000);
58
62
  const timeoutHandle = setTimeout(() => {
59
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
60
- ws.removeEventListener('message', handler);
63
+ ws.removeEventListener("message", handler);
61
64
  clearInterval(checkHandle);
62
65
  reject(new TimeoutException());
63
66
  }, timeout);
@@ -65,13 +68,13 @@ ${JSON.stringify(JSON.parse(event.data), null, 2)}
65
68
  const event = mEvent as WsgEvent;
66
69
  const [meta, body] = Utils.splitWsgData(event.data);
67
70
  if (matchCondition(meta)) {
68
- ws.removeEventListener('message', handler);
71
+ ws.removeEventListener("message", handler);
69
72
  clearInterval(checkHandle);
70
73
  clearTimeout(timeoutHandle);
71
74
  resolve([meta, body, event]);
72
75
  }
73
76
  };
74
- ws.addEventListener('message', handler);
77
+ ws.addEventListener("message", handler);
75
78
  });
76
79
  }
77
80
  }
package/tsconfig.json CHANGED
@@ -1,7 +1,4 @@
1
1
  {
2
2
  "extends": "../../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "lib"
5
- },
6
3
  "include": ["src"]
7
4
  }