@portal-hq/connect 0.3.1 → 0.3.3

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.
@@ -11,6 +11,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  class PortalConnect {
13
13
  constructor({ portal, websocketServer = 'connect.portalhq.io', }) {
14
+ this.connected = false;
15
+ this.events = {};
14
16
  this.portal = portal;
15
17
  this.websocketServer = websocketServer;
16
18
  }
@@ -25,10 +27,93 @@ class PortalConnect {
25
27
  if (this.socket) {
26
28
  this.socket.close();
27
29
  }
28
- this.socket = new WebSocket(`wss://${this.websocketServer}`);
30
+ const protocol = this.websocketServer.startsWith('localhost') ? 'ws' : 'wss';
31
+ // @ts-ignore
32
+ this.socket = new WebSocket(`${protocol}://${this.websocketServer}/`, null,
33
+ // @ts-ignore
34
+ {
35
+ headers: {
36
+ Authorization: `Bearer ${this.portal.apiKey}`,
37
+ },
38
+ });
29
39
  this.bindToSocketEvents(this.socket, uri);
30
40
  });
31
41
  }
42
+ /**
43
+ * Invokes all registered event handlers with the data provided
44
+ * - If any `once` handlers exist, they are removed after all handlers are invoked
45
+ *
46
+ * @param event The name of the event to be handled
47
+ * @param data The data to be passed to registered event handlers
48
+ * @returns BaseProvider
49
+ */
50
+ emit(event, data) {
51
+ // Grab the registered event handlers if any are available
52
+ const handlers = this.events[event] || [];
53
+ // Execute every event handler
54
+ for (const registeredEventHandler of handlers) {
55
+ registeredEventHandler.handler(data);
56
+ }
57
+ // Remove any registered event handlers with the `once` flag
58
+ this.events[event] = handlers.filter((handler) => !handler.once);
59
+ return this;
60
+ }
61
+ /**
62
+ * Registers an event handler for the provided event
63
+ *
64
+ * @param event The event name to add a handler to
65
+ * @param callback The callback to be invoked when the event is emitted
66
+ * @returns BaseProvider
67
+ */
68
+ on(event, callback) {
69
+ // If no handlers are registered for this event, create an entry for the event
70
+ if (!this.events[event]) {
71
+ this.events[event] = [];
72
+ }
73
+ // Register event handler with the rudimentary event bus
74
+ if (typeof callback !== 'undefined') {
75
+ this.events[event].push({
76
+ handler: callback,
77
+ once: false,
78
+ });
79
+ }
80
+ return this;
81
+ }
82
+ /**
83
+ * Registers a single-execution event handler for the provided event
84
+ *
85
+ * @param event The event name to add a handler to
86
+ * @param callback The callback to be invoked the next time the event is emitted
87
+ * @returns BaseProvider
88
+ */
89
+ once(event, callback) {
90
+ // If no handlers are registered for this event, create an entry for the event
91
+ if (!this.events[event]) {
92
+ this.events[event] = [];
93
+ }
94
+ // Register event handler with the rudimentary event bus
95
+ if (typeof callback !== 'undefined') {
96
+ this.events[event].push({
97
+ handler: callback,
98
+ once: true,
99
+ });
100
+ }
101
+ return this;
102
+ }
103
+ removeEventListener(event, listenerToRemove) {
104
+ if (!this.events[event]) {
105
+ return;
106
+ }
107
+ if (!listenerToRemove) {
108
+ this.events[event] = [];
109
+ }
110
+ else {
111
+ const filterEventHandlers = (registeredEventHandler) => {
112
+ return registeredEventHandler.handler !== listenerToRemove;
113
+ };
114
+ this.events[event] = this.events[event].filter(filterEventHandlers);
115
+ }
116
+ }
32
117
  /**
33
118
  * Adds event bindings to a websocket connection
34
119
  * - on open, a `connect` event is dispatched via the socket to establish a bridge connection
@@ -72,6 +157,17 @@ class PortalConnect {
72
157
  console.warn(`PortalConnect could not establish a connection to the relay.`);
73
158
  return;
74
159
  }
160
+ this.connected = true;
161
+ this.emit('connect', {
162
+ uri,
163
+ });
164
+ break;
165
+ case 'disconnect':
166
+ socket.close();
167
+ this.connected = false;
168
+ this.emit('disconnect', {
169
+ uri,
170
+ });
75
171
  break;
76
172
  case 'session_request':
77
173
  const { id, params, topic } = message.data;
package/lib/esm/index.js CHANGED
@@ -9,6 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  class PortalConnect {
11
11
  constructor({ portal, websocketServer = 'connect.portalhq.io', }) {
12
+ this.connected = false;
13
+ this.events = {};
12
14
  this.portal = portal;
13
15
  this.websocketServer = websocketServer;
14
16
  }
@@ -23,10 +25,93 @@ class PortalConnect {
23
25
  if (this.socket) {
24
26
  this.socket.close();
25
27
  }
26
- this.socket = new WebSocket(`wss://${this.websocketServer}`);
28
+ const protocol = this.websocketServer.startsWith('localhost') ? 'ws' : 'wss';
29
+ // @ts-ignore
30
+ this.socket = new WebSocket(`${protocol}://${this.websocketServer}/`, null,
31
+ // @ts-ignore
32
+ {
33
+ headers: {
34
+ Authorization: `Bearer ${this.portal.apiKey}`,
35
+ },
36
+ });
27
37
  this.bindToSocketEvents(this.socket, uri);
28
38
  });
29
39
  }
40
+ /**
41
+ * Invokes all registered event handlers with the data provided
42
+ * - If any `once` handlers exist, they are removed after all handlers are invoked
43
+ *
44
+ * @param event The name of the event to be handled
45
+ * @param data The data to be passed to registered event handlers
46
+ * @returns BaseProvider
47
+ */
48
+ emit(event, data) {
49
+ // Grab the registered event handlers if any are available
50
+ const handlers = this.events[event] || [];
51
+ // Execute every event handler
52
+ for (const registeredEventHandler of handlers) {
53
+ registeredEventHandler.handler(data);
54
+ }
55
+ // Remove any registered event handlers with the `once` flag
56
+ this.events[event] = handlers.filter((handler) => !handler.once);
57
+ return this;
58
+ }
59
+ /**
60
+ * Registers an event handler for the provided event
61
+ *
62
+ * @param event The event name to add a handler to
63
+ * @param callback The callback to be invoked when the event is emitted
64
+ * @returns BaseProvider
65
+ */
66
+ on(event, callback) {
67
+ // If no handlers are registered for this event, create an entry for the event
68
+ if (!this.events[event]) {
69
+ this.events[event] = [];
70
+ }
71
+ // Register event handler with the rudimentary event bus
72
+ if (typeof callback !== 'undefined') {
73
+ this.events[event].push({
74
+ handler: callback,
75
+ once: false,
76
+ });
77
+ }
78
+ return this;
79
+ }
80
+ /**
81
+ * Registers a single-execution event handler for the provided event
82
+ *
83
+ * @param event The event name to add a handler to
84
+ * @param callback The callback to be invoked the next time the event is emitted
85
+ * @returns BaseProvider
86
+ */
87
+ once(event, callback) {
88
+ // If no handlers are registered for this event, create an entry for the event
89
+ if (!this.events[event]) {
90
+ this.events[event] = [];
91
+ }
92
+ // Register event handler with the rudimentary event bus
93
+ if (typeof callback !== 'undefined') {
94
+ this.events[event].push({
95
+ handler: callback,
96
+ once: true,
97
+ });
98
+ }
99
+ return this;
100
+ }
101
+ removeEventListener(event, listenerToRemove) {
102
+ if (!this.events[event]) {
103
+ return;
104
+ }
105
+ if (!listenerToRemove) {
106
+ this.events[event] = [];
107
+ }
108
+ else {
109
+ const filterEventHandlers = (registeredEventHandler) => {
110
+ return registeredEventHandler.handler !== listenerToRemove;
111
+ };
112
+ this.events[event] = this.events[event].filter(filterEventHandlers);
113
+ }
114
+ }
30
115
  /**
31
116
  * Adds event bindings to a websocket connection
32
117
  * - on open, a `connect` event is dispatched via the socket to establish a bridge connection
@@ -70,6 +155,17 @@ class PortalConnect {
70
155
  console.warn(`PortalConnect could not establish a connection to the relay.`);
71
156
  return;
72
157
  }
158
+ this.connected = true;
159
+ this.emit('connect', {
160
+ uri,
161
+ });
162
+ break;
163
+ case 'disconnect':
164
+ socket.close();
165
+ this.connected = false;
166
+ this.emit('disconnect', {
167
+ uri,
168
+ });
73
169
  break;
74
170
  case 'session_request':
75
171
  const { id, params, topic } = message.data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portal-hq/connect",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "main": "lib/commonjs/index",
5
5
  "module": "lib/esm/index",
6
6
  "source": "src/index",
@@ -21,6 +21,7 @@
21
21
  "devDependencies": {
22
22
  "@babel/preset-typescript": "^7.18.6",
23
23
  "@types/jest": "^29.2.0",
24
+ "@types/ws": "^8.5.4",
24
25
  "jest": "^29.2.1",
25
26
  "jest-environment-jsdom": "^29.2.2",
26
27
  "ts-jest": "^29.0.3",
package/src/index.ts CHANGED
@@ -1,20 +1,27 @@
1
1
  import Portal from '@portal-hq/core'
2
2
  import type {
3
3
  ConnectResult,
4
+ EventHandler,
4
5
  PortalConnectOptions,
6
+ RegisteredEventHandler,
5
7
  SessionRequest,
6
8
  WebsocketMessage,
7
- } from '../types'
9
+ } from '../types.d'
8
10
 
9
11
  class PortalConnect {
12
+ public connected: boolean
10
13
  public portal: Portal
11
14
  public socket?: WebSocket
12
15
  public websocketServer: string
13
16
 
17
+ private events: Record<string, RegisteredEventHandler[]>
18
+
14
19
  constructor({
15
20
  portal,
16
21
  websocketServer = 'connect.portalhq.io',
17
22
  }: PortalConnectOptions) {
23
+ this.connected = false
24
+ this.events = {}
18
25
  this.portal = portal
19
26
  this.websocketServer = websocketServer
20
27
  }
@@ -30,10 +37,113 @@ class PortalConnect {
30
37
  this.socket.close()
31
38
  }
32
39
 
33
- this.socket = new WebSocket(`wss://${this.websocketServer}`)
40
+ const protocol = this.websocketServer.startsWith('localhost') ? 'ws' : 'wss'
41
+ // @ts-ignore
42
+ this.socket = new WebSocket(
43
+ `${protocol}://${this.websocketServer}/`,
44
+ null,
45
+ // @ts-ignore
46
+ {
47
+ headers: {
48
+ Authorization: `Bearer ${this.portal.apiKey}`,
49
+ },
50
+ },
51
+ )
34
52
  this.bindToSocketEvents(this.socket, uri)
35
53
  }
36
54
 
55
+ /**
56
+ * Invokes all registered event handlers with the data provided
57
+ * - If any `once` handlers exist, they are removed after all handlers are invoked
58
+ *
59
+ * @param event The name of the event to be handled
60
+ * @param data The data to be passed to registered event handlers
61
+ * @returns BaseProvider
62
+ */
63
+ public emit(event: string, data: any): PortalConnect {
64
+ // Grab the registered event handlers if any are available
65
+ const handlers = this.events[event] || []
66
+
67
+ // Execute every event handler
68
+ for (const registeredEventHandler of handlers) {
69
+ registeredEventHandler.handler(data)
70
+ }
71
+
72
+ // Remove any registered event handlers with the `once` flag
73
+ this.events[event] = handlers.filter((handler) => !handler.once)
74
+
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Registers an event handler for the provided event
80
+ *
81
+ * @param event The event name to add a handler to
82
+ * @param callback The callback to be invoked when the event is emitted
83
+ * @returns BaseProvider
84
+ */
85
+ public on(event: string, callback: EventHandler): PortalConnect {
86
+ // If no handlers are registered for this event, create an entry for the event
87
+ if (!this.events[event]) {
88
+ this.events[event] = []
89
+ }
90
+
91
+ // Register event handler with the rudimentary event bus
92
+ if (typeof callback !== 'undefined') {
93
+ this.events[event].push({
94
+ handler: callback,
95
+ once: false,
96
+ })
97
+ }
98
+
99
+ return this
100
+ }
101
+
102
+ /**
103
+ * Registers a single-execution event handler for the provided event
104
+ *
105
+ * @param event The event name to add a handler to
106
+ * @param callback The callback to be invoked the next time the event is emitted
107
+ * @returns BaseProvider
108
+ */
109
+ public once(event: string, callback: EventHandler): PortalConnect {
110
+ // If no handlers are registered for this event, create an entry for the event
111
+ if (!this.events[event]) {
112
+ this.events[event] = []
113
+ }
114
+
115
+ // Register event handler with the rudimentary event bus
116
+ if (typeof callback !== 'undefined') {
117
+ this.events[event].push({
118
+ handler: callback,
119
+ once: true,
120
+ })
121
+ }
122
+
123
+ return this
124
+ }
125
+
126
+ public removeEventListener(
127
+ event: string,
128
+ listenerToRemove?: EventHandler,
129
+ ): void {
130
+ if (!this.events[event]) {
131
+ return
132
+ }
133
+
134
+ if (!listenerToRemove) {
135
+ this.events[event] = []
136
+ } else {
137
+ const filterEventHandlers = (
138
+ registeredEventHandler: RegisteredEventHandler,
139
+ ) => {
140
+ return registeredEventHandler.handler !== listenerToRemove
141
+ }
142
+
143
+ this.events[event] = this.events[event].filter(filterEventHandlers)
144
+ }
145
+ }
146
+
37
147
  /**
38
148
  * Adds event bindings to a websocket connection
39
149
  * - on open, a `connect` event is dispatched via the socket to establish a bridge connection
@@ -68,7 +178,7 @@ class PortalConnect {
68
178
  * @param messageEvent
69
179
  * @returns
70
180
  */
71
- socket.onmessage = async (messageEvent: MessageEvent) => {
181
+ socket.onmessage = async (messageEvent: WebSocketMessageEvent) => {
72
182
  const message = JSON.parse(messageEvent.data) as WebsocketMessage
73
183
 
74
184
  switch (message.event) {
@@ -84,6 +194,19 @@ class PortalConnect {
84
194
  )
85
195
  return
86
196
  }
197
+
198
+ this.connected = true
199
+ this.emit('connect', {
200
+ uri,
201
+ })
202
+ break
203
+ case 'disconnect':
204
+ socket.close()
205
+ this.connected = false
206
+ this.emit('disconnect', {
207
+ uri,
208
+ })
209
+
87
210
  break
88
211
  case 'session_request':
89
212
  const { id, params, topic } = message.data as SessionRequest
package/types.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import Portal from '@portal-hq/core'
2
2
 
3
- interface ConnectResult {
3
+ export type EventHandler = (data: any) => void
4
+
5
+ export interface ConnectResult {
4
6
  active: boolean
5
7
  expiry: number
6
8
  peerMetadata: PeerMetadata
@@ -8,40 +10,50 @@ interface ConnectResult {
8
10
  topic: string
9
11
  }
10
12
 
11
- interface PeerMetadata {
13
+ export interface DisconnectResult {
14
+ id: number
15
+ topic: string
16
+ }
17
+
18
+ export interface PeerMetadata {
12
19
  name: string
13
20
  description: string
14
21
  url: string
15
22
  icons: string[]
16
23
  }
17
24
 
18
- interface PortalConnectOptions {
25
+ export interface PortalConnectOptions {
19
26
  portal: Portal
20
27
  websocketServer?: string
21
28
  }
22
29
 
23
- interface ProtocolOptions {
30
+ export interface ProtocolOptions {
24
31
  protocol: string
25
32
  data?: string
26
33
  }
27
34
 
28
- interface ProviderRequestPayload {
35
+ export interface ProviderRequestPayload {
29
36
  chainId: string
30
37
  request: ProviderRequestData
31
38
  }
32
39
 
33
- interface ProviderRequestData {
40
+ export interface ProviderRequestData {
34
41
  method: string
35
42
  params: any
36
43
  }
37
44
 
38
- interface SessionRequest {
45
+ export interface RegisteredEventHandler {
46
+ handler: EventHandler
47
+ once?: boolean
48
+ }
49
+
50
+ export interface SessionRequest {
39
51
  id: string
40
52
  params: ProviderRequestPayload
41
53
  topic: string
42
54
  }
43
55
 
44
- interface WebsocketMessage {
56
+ export interface WebsocketMessage {
45
57
  event: string
46
- data: ConnectResult | SessionRequest
58
+ data: ConnectResult | DisconnectResult | SessionRequest
47
59
  }