@trycourier/courier-react 8.0.14-beta → 8.0.16-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,92 +4,259 @@ import { flushSync } from "react-dom";
4
4
  var __defProp$1 = Object.defineProperty;
5
5
  var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
6
  var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
7
+ const CLOSE_CODE_NORMAL_CLOSURE = 1e3;
8
+ const IPW_VERSION = "v1";
7
9
  const _CourierSocket = class _CourierSocket2 {
8
- constructor(url, options) {
10
+ constructor(options) {
9
11
  __publicField$1(this, "webSocket", null);
10
- __publicField$1(this, "pingInterval", null);
11
- __publicField$1(this, "onOpen");
12
- __publicField$1(this, "onMessageReceived");
13
- __publicField$1(this, "onClose");
14
- __publicField$1(this, "onError");
12
+ __publicField$1(this, "retryAttempt", 0);
13
+ __publicField$1(this, "retryTimeoutId", null);
15
14
  __publicField$1(this, "url");
16
15
  __publicField$1(this, "options");
17
- this.url = url;
16
+ this.url = options.apiUrls.inbox.webSocket;
18
17
  this.options = options;
19
18
  }
20
19
  /**
21
- * Dynamically checks if the WebSocket is connected
20
+ * Connects to the Courier WebSocket server.
21
+ *
22
+ * If the connection is already established, this is a no-op.
23
+ *
24
+ * @returns A promise that resolves when the connection is established or rejects if the connection could not be established.
22
25
  */
23
- get isConnected() {
24
- return this.webSocket !== null;
25
- }
26
26
  async connect() {
27
- this.disconnect();
27
+ var _a;
28
+ this.clearRetryTimeout();
29
+ if (this.isConnecting || this.isOpen) {
30
+ (_a = this.options.logger) == null ? void 0 : _a.info("Attempted to open a WebSocket connection, but one already exists.");
31
+ return Promise.reject(new Error("WebSocket connection already exists"));
32
+ }
28
33
  return new Promise((resolve, reject) => {
29
- try {
30
- this.webSocket = new WebSocket(this.url);
31
- this.webSocket.onopen = () => {
32
- var _a;
33
- (_a = this.onOpen) == null ? void 0 : _a.call(this);
34
- resolve();
35
- };
36
- this.webSocket.onmessage = (event) => {
37
- var _a;
38
- (_a = this.onMessageReceived) == null ? void 0 : _a.call(this, event.data);
39
- };
40
- this.webSocket.onclose = (event) => {
41
- var _a;
42
- this.webSocket = null;
43
- (_a = this.onClose) == null ? void 0 : _a.call(this, event.code, event.reason);
44
- };
45
- this.webSocket.onerror = (event) => {
46
- var _a;
47
- this.webSocket = null;
48
- const error = new Error("Courier Socket connection failed");
49
- error.originalEvent = event;
50
- (_a = this.onError) == null ? void 0 : _a.call(this, error);
51
- reject(error);
52
- };
53
- } catch (error) {
54
- this.webSocket = null;
55
- reject(error);
56
- }
34
+ this.webSocket = new WebSocket(this.getWebSocketUrl());
35
+ this.webSocket.addEventListener("open", (event) => {
36
+ this.retryAttempt = 0;
37
+ this.onOpen(event);
38
+ resolve();
39
+ });
40
+ this.webSocket.addEventListener("message", async (event) => {
41
+ var _a2;
42
+ try {
43
+ const json = JSON.parse(event.data);
44
+ if ("event" in json && json.event === "reconnect") {
45
+ this.close(CLOSE_CODE_NORMAL_CLOSURE);
46
+ await this.retryConnection(json.retryAfter * 1e3);
47
+ return;
48
+ }
49
+ this.onMessageReceived(json);
50
+ } catch (error) {
51
+ (_a2 = this.options.logger) == null ? void 0 : _a2.error("Error parsing socket message", error);
52
+ }
53
+ });
54
+ this.webSocket.addEventListener("close", (event) => {
55
+ if (event.code !== CLOSE_CODE_NORMAL_CLOSURE) {
56
+ const courierCloseEvent = _CourierSocket2.parseCloseEvent(event);
57
+ if (courierCloseEvent.retryAfterSeconds) {
58
+ this.retryConnection(courierCloseEvent.retryAfterSeconds * 1e3);
59
+ } else {
60
+ this.retryConnection();
61
+ }
62
+ }
63
+ this.onClose(event);
64
+ });
65
+ this.webSocket.addEventListener("error", (event) => {
66
+ this.retryConnection();
67
+ this.onError(event);
68
+ reject(event);
69
+ });
57
70
  });
58
71
  }
59
- disconnect() {
60
- this.stopPing();
61
- if (this.webSocket) {
62
- this.webSocket.close(_CourierSocket2.NORMAL_CLOSURE_STATUS);
63
- this.webSocket = null;
72
+ /**
73
+ * Closes the WebSocket connection.
74
+ *
75
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close} for more details.
76
+ *
77
+ * @param code The WebSocket close code. Defaults to {@link CLOSE_CODE_NORMAL_CLOSURE}.
78
+ * @param reason The WebSocket close reason.
79
+ */
80
+ close(code = CLOSE_CODE_NORMAL_CLOSURE, reason) {
81
+ if (this.webSocket === null) {
82
+ return;
64
83
  }
84
+ this.webSocket.close(code, reason);
85
+ this.webSocket = null;
65
86
  }
66
- async send(message) {
67
- if (!this.webSocket) {
68
- return false;
87
+ /**
88
+ * Sends a message to the Courier WebSocket server.
89
+ *
90
+ * @param message The message to send. The message will be serialized to a JSON string.
91
+ */
92
+ send(message) {
93
+ var _a;
94
+ if (this.webSocket === null || this.isConnecting) {
95
+ (_a = this.options.logger) == null ? void 0 : _a.info("Attempted to send a message, but the WebSocket is not yet open.");
96
+ return;
69
97
  }
70
98
  const json = JSON.stringify(message);
71
- return this.webSocket.send(json) !== void 0;
99
+ this.webSocket.send(json);
72
100
  }
73
- keepAlive(props) {
74
- this.stopPing();
75
- this.pingInterval = setInterval(async () => {
76
- var _a;
101
+ get userId() {
102
+ return this.options.userId;
103
+ }
104
+ get logger() {
105
+ return this.options.logger;
106
+ }
107
+ /**
108
+ * Whether the WebSocket connection is currently being established.
109
+ */
110
+ get isConnecting() {
111
+ return this.webSocket !== null && this.webSocket.readyState === WebSocket.CONNECTING;
112
+ }
113
+ /**
114
+ * Whether the WebSocket connection is currently open.
115
+ */
116
+ get isOpen() {
117
+ return this.webSocket !== null && this.webSocket.readyState === WebSocket.OPEN;
118
+ }
119
+ /**
120
+ * Constructs the WebSocket URL for the Courier WebSocket server using context
121
+ * from the {@link CourierClientOptions} passed to the constructor.
122
+ *
123
+ * @returns The WebSocket URL
124
+ */
125
+ getWebSocketUrl() {
126
+ const accessToken = this.options.accessToken;
127
+ const connectionId = this.options.connectionId;
128
+ const userId = this.userId;
129
+ return `${this.url}?auth=${accessToken}&cid=${connectionId}&iwpv=${IPW_VERSION}&userId=${userId}`;
130
+ }
131
+ /**
132
+ * Parses the Retry-After time from the WebSocket close event reason,
133
+ * and returns a new {@link CourierCloseEvent} with the retry after time in seconds
134
+ * if present.
135
+ *
136
+ * The Courier WebSocket server may send the close event reason in the following format:
137
+ *
138
+ * ```json
139
+ * {
140
+ * "Retry-After": "10" // The retry after time in seconds
141
+ * }
142
+ * ```
143
+ *
144
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/reason
145
+ *
146
+ * @param closeEvent The WebSocket close event.
147
+ * @returns The WebSocket close event with the retry after time in seconds.
148
+ */
149
+ static parseCloseEvent(closeEvent) {
150
+ if (closeEvent.reason === null || closeEvent.reason === "") {
151
+ return closeEvent;
152
+ }
153
+ try {
154
+ const jsonReason = JSON.parse(closeEvent.reason);
155
+ if (!jsonReason[_CourierSocket2.RETRY_AFTER_KEY]) {
156
+ return closeEvent;
157
+ }
158
+ const retryAfterSeconds = parseInt(jsonReason[_CourierSocket2.RETRY_AFTER_KEY]);
159
+ if (Number.isNaN(retryAfterSeconds) || retryAfterSeconds < 0) {
160
+ return closeEvent;
161
+ }
162
+ return {
163
+ ...closeEvent,
164
+ retryAfterSeconds
165
+ };
166
+ } catch (error) {
167
+ return closeEvent;
168
+ }
169
+ }
170
+ /**
171
+ * Calculates the retry backoff time in milliseconds based on the current retry attempt.
172
+ */
173
+ getBackoffTimeInMillis() {
174
+ const backoffIntervalInMillis = _CourierSocket2.BACKOFF_INTERVALS_IN_MILLIS[this.retryAttempt];
175
+ const lowerBound = backoffIntervalInMillis - backoffIntervalInMillis * _CourierSocket2.BACKOFF_JITTER_FACTOR;
176
+ const upperBound = backoffIntervalInMillis + backoffIntervalInMillis * _CourierSocket2.BACKOFF_JITTER_FACTOR;
177
+ return Math.floor(Math.random() * (upperBound - lowerBound) + lowerBound);
178
+ }
179
+ /**
180
+ * Retries the connection to the Courier WebSocket server after
181
+ * either {@param suggestedBackoffTimeInMillis} or a random backoff time
182
+ * calculated using {@link getBackoffTimeInMillis}.
183
+ *
184
+ * @param suggestedBackoffTimeInMillis The suggested backoff time in milliseconds.
185
+ * @returns A promise that resolves when the connection is established or rejects if the connection could not be established.
186
+ */
187
+ async retryConnection(suggestedBackoffTimeInMillis) {
188
+ var _a, _b, _c;
189
+ if (this.retryTimeoutId !== null) {
190
+ (_a = this.logger) == null ? void 0 : _a.debug("Skipping retry attempt because a previous retry is already scheduled.");
191
+ return;
192
+ }
193
+ if (this.retryAttempt >= _CourierSocket2.MAX_RETRY_ATTEMPTS) {
194
+ (_b = this.logger) == null ? void 0 : _b.error(`Max retry attempts (${_CourierSocket2.MAX_RETRY_ATTEMPTS}) reached.`);
195
+ return;
196
+ }
197
+ const backoffTimeInMillis = suggestedBackoffTimeInMillis ?? this.getBackoffTimeInMillis();
198
+ this.retryTimeoutId = window.setTimeout(async () => {
77
199
  try {
78
- await this.send({ action: "keepAlive" });
200
+ await this.connect();
79
201
  } catch (error) {
80
- (_a = this.options.logger) == null ? void 0 : _a.error("Error occurred on Keep Alive:", error);
81
202
  }
82
- }, (props == null ? void 0 : props.intervalInMillis) ?? 3e5);
203
+ }, backoffTimeInMillis);
204
+ (_c = this.logger) == null ? void 0 : _c.debug(`Retrying connection in ${Math.floor(backoffTimeInMillis / 1e3)}s. Retry attempt ${this.retryAttempt + 1} of ${_CourierSocket2.MAX_RETRY_ATTEMPTS}.`);
205
+ this.retryAttempt++;
83
206
  }
84
- stopPing() {
85
- if (this.pingInterval) {
86
- clearInterval(this.pingInterval);
87
- this.pingInterval = null;
207
+ /**
208
+ * Clears the retry timeout if it exists.
209
+ */
210
+ clearRetryTimeout() {
211
+ if (this.retryTimeoutId !== null) {
212
+ window.clearTimeout(this.retryTimeoutId);
213
+ this.retryTimeoutId = null;
88
214
  }
89
215
  }
90
216
  };
91
- __publicField$1(_CourierSocket, "NORMAL_CLOSURE_STATUS", 1e3);
217
+ __publicField$1(_CourierSocket, "BACKOFF_JITTER_FACTOR", 0.5);
218
+ __publicField$1(_CourierSocket, "MAX_RETRY_ATTEMPTS", 5);
219
+ __publicField$1(_CourierSocket, "BACKOFF_INTERVALS_IN_MILLIS", [
220
+ 3e4,
221
+ // 30 seconds
222
+ 6e4,
223
+ // 1 minute
224
+ 12e4,
225
+ // 2 minutes
226
+ 24e4,
227
+ // 4 minutes
228
+ 48e4
229
+ // 8 minutes
230
+ ]);
231
+ __publicField$1(_CourierSocket, "RETRY_AFTER_KEY", "Retry-After");
92
232
  let CourierSocket = _CourierSocket;
233
+ var ClientAction = /* @__PURE__ */ ((ClientAction2) => {
234
+ ClientAction2["Subscribe"] = "subscribe";
235
+ ClientAction2["Unsubscribe"] = "unsubscribe";
236
+ ClientAction2["Pong"] = "pong";
237
+ ClientAction2["Ping"] = "ping";
238
+ return ClientAction2;
239
+ })(ClientAction || {});
240
+ var ServerAction = /* @__PURE__ */ ((ServerAction2) => {
241
+ ServerAction2["Ack"] = "ack";
242
+ ServerAction2["Ping"] = "ping";
243
+ ServerAction2["Pong"] = "pong";
244
+ return ServerAction2;
245
+ })(ServerAction || {});
246
+ var MessageEvent = /* @__PURE__ */ ((MessageEvent2) => {
247
+ MessageEvent2["NewMessage"] = "message";
248
+ MessageEvent2["Archive"] = "archive";
249
+ MessageEvent2["ArchiveAll"] = "archive-all";
250
+ MessageEvent2["ArchiveRead"] = "archive-read";
251
+ MessageEvent2["Clicked"] = "clicked";
252
+ MessageEvent2["MarkAllRead"] = "mark-all-read";
253
+ MessageEvent2["Opened"] = "opened";
254
+ MessageEvent2["Read"] = "read";
255
+ MessageEvent2["Unarchive"] = "unarchive";
256
+ MessageEvent2["Unopened"] = "unopened";
257
+ MessageEvent2["Unread"] = "unread";
258
+ return MessageEvent2;
259
+ })(MessageEvent || {});
93
260
  const getCourierApiUrls = (urls) => ({
94
261
  courier: {
95
262
  rest: (urls == null ? void 0 : urls.courier.rest) || "https://api.courier.com",
@@ -131,12 +298,27 @@ class Logger {
131
298
  }
132
299
  }
133
300
  }
134
- class UUID {
135
- static generate(prefix) {
136
- const id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
137
- return prefix ? prefix + id : id;
301
+ const _UUID = class _UUID2 {
302
+ /**
303
+ * nanoid
304
+ * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>
305
+ *
306
+ * https://github.com/ai/nanoid/blob/main/LICENSE
307
+ *
308
+ * @param size - The size of the UUID to generate.
309
+ * @returns A string representing the UUID.
310
+ */
311
+ static nanoid(size = 21) {
312
+ let id = "";
313
+ let bytes = crypto.getRandomValues(new Uint8Array(size |= 0));
314
+ while (size--) {
315
+ id += _UUID2.ALPHABET[bytes[size] & 63];
316
+ }
317
+ return id;
138
318
  }
139
- }
319
+ };
320
+ __publicField$1(_UUID, "ALPHABET", "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict");
321
+ let UUID = _UUID;
140
322
  class CourierRequestError extends Error {
141
323
  constructor(code, message, type) {
142
324
  super(message);
@@ -165,7 +347,7 @@ Response JSON: ${JSON.stringify(data.response, null, 2)}
165
347
  }
166
348
  async function http(props) {
167
349
  const validCodes = props.validCodes ?? [200];
168
- const uid = props.options.showLogs ? UUID.generate() : void 0;
350
+ const uid = props.options.showLogs ? UUID.nanoid() : void 0;
169
351
  const request = new Request(props.url, {
170
352
  method: props.method,
171
353
  headers: {
@@ -215,7 +397,7 @@ async function http(props) {
215
397
  return data;
216
398
  }
217
399
  async function graphql(props) {
218
- const uid = props.options.showLogs ? UUID.generate() : void 0;
400
+ const uid = props.options.showLogs ? UUID.nanoid() : void 0;
219
401
  if (uid) {
220
402
  logRequest(props.options.logger, uid, "GraphQL", {
221
403
  url: props.url,
@@ -304,70 +486,120 @@ class BrandClient extends Client {
304
486
  return json.data.brand;
305
487
  }
306
488
  }
307
- class InboxSocket extends CourierSocket {
489
+ const _CourierInboxSocket = class _CourierInboxSocket2 extends CourierSocket {
308
490
  constructor(options) {
309
- const url = InboxSocket.buildUrl(options);
310
- super(url, options);
311
- __publicField$1(this, "receivedMessage");
312
- __publicField$1(this, "receivedMessageEvent");
313
- this.onMessageReceived = (data) => this.convertToType(data);
491
+ super(options);
492
+ __publicField$1(this, "pingIntervalId", null);
493
+ __publicField$1(this, "messageEventListeners", []);
314
494
  }
315
- convertToType(data) {
316
- var _a, _b, _c, _d;
317
- try {
318
- const payload = JSON.parse(data);
319
- switch (payload.type) {
320
- case "event":
321
- const messageEvent = JSON.parse(data);
322
- (_a = this.receivedMessageEvent) == null ? void 0 : _a.call(this, messageEvent);
323
- break;
324
- case "message":
325
- const message = JSON.parse(data);
326
- (_b = this.receivedMessage) == null ? void 0 : _b.call(this, message);
327
- break;
328
- }
329
- } catch (error) {
330
- (_c = this.options.logger) == null ? void 0 : _c.error("Error parsing socket message", error);
331
- if (error instanceof Error) {
332
- (_d = this.onError) == null ? void 0 : _d.call(this, error);
495
+ onOpen(_) {
496
+ this.restartPingInterval();
497
+ return Promise.resolve();
498
+ }
499
+ onMessageReceived(data) {
500
+ if ("action" in data && data.action === ServerAction.Ping) {
501
+ const envelope = data;
502
+ this.sendPong(envelope);
503
+ }
504
+ if ("event" in data) {
505
+ for (const listener of this.messageEventListeners) {
506
+ listener(data);
333
507
  }
334
508
  }
509
+ this.restartPingInterval();
510
+ return Promise.resolve();
335
511
  }
336
- async sendSubscribe(props) {
337
- var _a;
338
- const subscription = {
339
- action: "subscribe",
512
+ onClose(_) {
513
+ return Promise.resolve();
514
+ }
515
+ onError(_) {
516
+ return Promise.resolve();
517
+ }
518
+ /**
519
+ * Sends a subscribe message to the server.
520
+ *
521
+ * Subscribes to all events for the user.
522
+ */
523
+ sendSubscribe() {
524
+ const envelope = {
525
+ tid: UUID.nanoid(),
526
+ action: ClientAction.Subscribe,
340
527
  data: {
341
- userAgent: "courier-js",
342
- // TODO: Equivalent to Courier.agent.value()
343
- channel: this.options.userId,
344
- event: "*",
345
- version: (props == null ? void 0 : props.version) ?? 5
528
+ channel: this.userId,
529
+ event: "*"
346
530
  }
347
531
  };
348
- if (this.options.connectionId) {
349
- subscription.data.clientSourceId = this.options.connectionId;
350
- }
351
- if (this.options.tenantId) {
352
- subscription.data.accountId = this.options.tenantId;
353
- }
354
- (_a = this.options.logger) == null ? void 0 : _a.debug("Sending subscribe request", subscription);
355
- await this.send(subscription);
532
+ this.send(envelope);
356
533
  }
357
- static buildUrl(options) {
358
- var _a;
359
- let url = ((_a = options.apiUrls) == null ? void 0 : _a.inbox.webSocket) ?? "";
360
- if (options.accessToken) {
361
- url += `/?auth=${options.accessToken}`;
534
+ /**
535
+ * Sends an unsubscribe message to the server.
536
+ *
537
+ * Unsubscribes from all events for the user.
538
+ */
539
+ sendUnsubscribe() {
540
+ const envelope = {
541
+ tid: UUID.nanoid(),
542
+ action: ClientAction.Unsubscribe,
543
+ data: {
544
+ channel: this.userId
545
+ }
546
+ };
547
+ this.send(envelope);
548
+ }
549
+ /**
550
+ * Adds a message event listener, called when a message event is received
551
+ * from the Courier WebSocket server.
552
+ *
553
+ * @param listener The listener function
554
+ */
555
+ addMessageEventListener(listener) {
556
+ this.messageEventListeners.push(listener);
557
+ }
558
+ /**
559
+ * Send a ping message to the server.
560
+ *
561
+ * ping/pong is implemented at the application layer since the browser's
562
+ * WebSocket implementation does not support control-level ping/pong.
563
+ */
564
+ sendPing() {
565
+ const envelope = {
566
+ tid: UUID.nanoid(),
567
+ action: ClientAction.Ping
568
+ };
569
+ this.send(envelope);
570
+ }
571
+ /**
572
+ * Send a pong response to the server.
573
+ *
574
+ * ping/pong is implemented at the application layer since the browser's
575
+ * WebSocket implementation does not support control-level ping/pong.
576
+ */
577
+ sendPong(incomingMessage) {
578
+ const response = {
579
+ tid: incomingMessage.tid,
580
+ action: ClientAction.Pong
581
+ };
582
+ this.send(response);
583
+ }
584
+ /**
585
+ * Restart the ping interval, clearing the previous interval if it exists.
586
+ */
587
+ restartPingInterval() {
588
+ if (this.pingIntervalId) {
589
+ window.clearInterval(this.pingIntervalId);
362
590
  }
363
- return url;
591
+ this.pingIntervalId = window.setInterval(() => {
592
+ this.sendPing();
593
+ }, _CourierInboxSocket2.PING_INTERVAL_MILLIS);
364
594
  }
365
- }
595
+ };
596
+ __publicField$1(_CourierInboxSocket, "PING_INTERVAL_MILLIS", 6e4);
597
+ let CourierInboxSocket = _CourierInboxSocket;
366
598
  class InboxClient extends Client {
367
599
  constructor(options) {
368
600
  super(options);
369
601
  __publicField$1(this, "socket");
370
- this.socket = new InboxSocket(options);
602
+ this.socket = new CourierInboxSocket(options);
371
603
  }
372
604
  /**
373
605
  * Get paginated messages
@@ -977,7 +1209,7 @@ class TrackingClient extends Client {
977
1209
  class CourierClient extends Client {
978
1210
  constructor(props) {
979
1211
  var _a, _b;
980
- const showLogs = props.showLogs !== void 0 ? props.showLogs : process.env.NODE_ENV === "development";
1212
+ const showLogs = props.showLogs !== void 0 ? props.showLogs : false;
981
1213
  const baseOptions = {
982
1214
  ...props,
983
1215
  showLogs,
@@ -1027,7 +1259,7 @@ class AuthenticationListener {
1027
1259
  }
1028
1260
  const _Courier = class _Courier2 {
1029
1261
  constructor() {
1030
- __publicField$1(this, "id", UUID.generate());
1262
+ __publicField$1(this, "id", UUID.nanoid());
1031
1263
  __publicField$1(this, "instanceClient");
1032
1264
  __publicField$1(this, "_paginationLimit", 24);
1033
1265
  __publicField$1(this, "authenticationListeners", []);
@@ -1060,7 +1292,7 @@ const _Courier = class _Courier2 {
1060
1292
  * @param options - The options for the Courier client
1061
1293
  */
1062
1294
  signIn(props) {
1063
- const connectionId = props.connectionId ?? UUID.generate();
1295
+ const connectionId = props.connectionId ?? UUID.nanoid();
1064
1296
  this.instanceClient = new CourierClient({ ...props, connectionId });
1065
1297
  this.notifyAuthenticationListeners({ userId: props.userId });
1066
1298
  }
@@ -2042,73 +2274,70 @@ const _CourierInboxDatastore = class _CourierInboxDatastore2 {
2042
2274
  await Promise.all(dataSetPromises);
2043
2275
  }
2044
2276
  async connectSocket() {
2045
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
2277
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2046
2278
  const socket = (_a = Courier.shared.client) == null ? void 0 : _a.inbox.socket;
2047
2279
  try {
2048
2280
  if (!socket) {
2049
2281
  (_c = (_b = Courier.shared.client) == null ? void 0 : _b.options.logger) == null ? void 0 : _c.info("CourierInbox socket not available");
2050
2282
  return;
2051
2283
  }
2052
- (_f = (_d = Courier.shared.client) == null ? void 0 : _d.options.logger) == null ? void 0 : _f.info("CourierInbox socket connectionId:", (_e = Courier.shared.client) == null ? void 0 : _e.options.connectionId);
2053
- if (socket.isConnected) {
2054
- (_h = (_g = Courier.shared.client) == null ? void 0 : _g.options.logger) == null ? void 0 : _h.info("CourierInbox socket already connected. Socket will not attempt reconnection.");
2284
+ if (socket.isConnecting || socket.isOpen) {
2285
+ (_f = (_d = Courier.shared.client) == null ? void 0 : _d.options.logger) == null ? void 0 : _f.info(`Inbox socket already connecting or open for client ID: [${(_e = Courier.shared.client) == null ? void 0 : _e.options.connectionId}]`);
2055
2286
  return;
2056
2287
  }
2057
- socket.receivedMessage = (message) => {
2058
- this.addMessage(message, 0, "inbox");
2059
- };
2060
- socket.receivedMessageEvent = (event) => {
2061
- let message;
2062
- if (event.messageId) {
2063
- message = this.getMessage({ messageId: event.messageId });
2288
+ socket.addMessageEventListener((event) => {
2289
+ if (event.event === MessageEvent.NewMessage) {
2290
+ const message2 = event.data;
2291
+ this.addMessage(message2, 0, "inbox");
2292
+ return;
2064
2293
  }
2294
+ const message = this.getMessage({ messageId: event.messageId });
2065
2295
  switch (event.event) {
2066
- case "mark-all-read":
2296
+ case MessageEvent.MarkAllRead:
2067
2297
  this.readAllMessages({ canCallApi: false });
2068
2298
  break;
2069
- case "read":
2299
+ case MessageEvent.Read:
2070
2300
  if (message) {
2071
2301
  this.readMessage({ message, canCallApi: false });
2072
2302
  }
2073
2303
  break;
2074
- case "unread":
2304
+ case MessageEvent.Unread:
2075
2305
  if (message) {
2076
2306
  this.unreadMessage({ message, canCallApi: false });
2077
2307
  }
2078
2308
  break;
2079
- case "opened":
2309
+ case MessageEvent.Opened:
2080
2310
  if (message) {
2081
2311
  this.openMessage({ message, canCallApi: false });
2082
2312
  }
2083
2313
  break;
2084
- case "archive":
2314
+ case MessageEvent.Archive:
2085
2315
  if (message) {
2086
2316
  this.archiveMessage({ message, canCallApi: false });
2087
2317
  }
2088
2318
  break;
2089
- case "archive-read":
2319
+ case MessageEvent.ArchiveRead:
2090
2320
  this.archiveReadMessages({ canCallApi: false });
2091
2321
  break;
2092
- case "click":
2322
+ case MessageEvent.Clicked:
2093
2323
  if (message) {
2094
2324
  this.clickMessage({ message, canCallApi: false });
2095
2325
  }
2096
2326
  break;
2097
- case "unarchive":
2327
+ case MessageEvent.Unarchive:
2098
2328
  if (message) {
2099
2329
  this.unarchiveMessage({ message, canCallApi: false });
2100
2330
  }
2101
2331
  break;
2102
- case "unopened":
2332
+ case MessageEvent.Unopened:
2103
2333
  break;
2104
2334
  }
2105
- };
2335
+ });
2106
2336
  await socket.connect();
2107
2337
  await socket.sendSubscribe();
2108
- socket.keepAlive();
2109
- (_j = (_i = Courier.shared.client) == null ? void 0 : _i.options.logger) == null ? void 0 : _j.info("CourierInbox socket connected");
2338
+ (_i = (_g = Courier.shared.client) == null ? void 0 : _g.options.logger) == null ? void 0 : _i.info(`Inbox socket connected for client ID: [${(_h = Courier.shared.client) == null ? void 0 : _h.options.connectionId}]`);
2110
2339
  } catch (error) {
2111
- (_l = (_k = Courier.shared.client) == null ? void 0 : _k.options.logger) == null ? void 0 : _l.error("Failed to connect socket:", error);
2340
+ (_k = (_j = Courier.shared.client) == null ? void 0 : _j.options.logger) == null ? void 0 : _k.error("Failed to connect socket:", error);
2112
2341
  }
2113
2342
  }
2114
2343
  /**
@@ -2118,6 +2347,9 @@ const _CourierInboxDatastore = class _CourierInboxDatastore2 {
2118
2347
  */
2119
2348
  getMessage(props) {
2120
2349
  var _a, _b;
2350
+ if (!props.messageId) {
2351
+ return void 0;
2352
+ }
2121
2353
  return ((_a = this._inboxDataSet) == null ? void 0 : _a.messages.find((m) => m.messageId === props.messageId)) ?? ((_b = this._archiveDataSet) == null ? void 0 : _b.messages.find((m) => m.messageId === props.messageId));
2122
2354
  }
2123
2355
  /**
@@ -5562,284 +5794,12 @@ function requireReactJsxRuntime_production() {
5562
5794
  reactJsxRuntime_production.jsxs = jsxProd;
5563
5795
  return reactJsxRuntime_production;
5564
5796
  }
5565
- var reactJsxRuntime_development = {};
5566
- /**
5567
- * @license React
5568
- * react-jsx-runtime.development.js
5569
- *
5570
- * Copyright (c) Meta Platforms, Inc. and affiliates.
5571
- *
5572
- * This source code is licensed under the MIT license found in the
5573
- * LICENSE file in the root directory of this source tree.
5574
- */
5575
- var hasRequiredReactJsxRuntime_development;
5576
- function requireReactJsxRuntime_development() {
5577
- if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
5578
- hasRequiredReactJsxRuntime_development = 1;
5579
- "production" !== process.env.NODE_ENV && function() {
5580
- function getComponentNameFromType(type) {
5581
- if (null == type) return null;
5582
- if ("function" === typeof type)
5583
- return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null;
5584
- if ("string" === typeof type) return type;
5585
- switch (type) {
5586
- case REACT_FRAGMENT_TYPE:
5587
- return "Fragment";
5588
- case REACT_PROFILER_TYPE:
5589
- return "Profiler";
5590
- case REACT_STRICT_MODE_TYPE:
5591
- return "StrictMode";
5592
- case REACT_SUSPENSE_TYPE:
5593
- return "Suspense";
5594
- case REACT_SUSPENSE_LIST_TYPE:
5595
- return "SuspenseList";
5596
- case REACT_ACTIVITY_TYPE:
5597
- return "Activity";
5598
- }
5599
- if ("object" === typeof type)
5600
- switch ("number" === typeof type.tag && console.error(
5601
- "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
5602
- ), type.$$typeof) {
5603
- case REACT_PORTAL_TYPE:
5604
- return "Portal";
5605
- case REACT_CONTEXT_TYPE:
5606
- return (type.displayName || "Context") + ".Provider";
5607
- case REACT_CONSUMER_TYPE:
5608
- return (type._context.displayName || "Context") + ".Consumer";
5609
- case REACT_FORWARD_REF_TYPE:
5610
- var innerType = type.render;
5611
- type = type.displayName;
5612
- type || (type = innerType.displayName || innerType.name || "", type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef");
5613
- return type;
5614
- case REACT_MEMO_TYPE:
5615
- return innerType = type.displayName || null, null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo";
5616
- case REACT_LAZY_TYPE:
5617
- innerType = type._payload;
5618
- type = type._init;
5619
- try {
5620
- return getComponentNameFromType(type(innerType));
5621
- } catch (x) {
5622
- }
5623
- }
5624
- return null;
5625
- }
5626
- function testStringCoercion(value) {
5627
- return "" + value;
5628
- }
5629
- function checkKeyStringCoercion(value) {
5630
- try {
5631
- testStringCoercion(value);
5632
- var JSCompiler_inline_result = false;
5633
- } catch (e) {
5634
- JSCompiler_inline_result = true;
5635
- }
5636
- if (JSCompiler_inline_result) {
5637
- JSCompiler_inline_result = console;
5638
- var JSCompiler_temp_const = JSCompiler_inline_result.error;
5639
- var JSCompiler_inline_result$jscomp$0 = "function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
5640
- JSCompiler_temp_const.call(
5641
- JSCompiler_inline_result,
5642
- "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
5643
- JSCompiler_inline_result$jscomp$0
5644
- );
5645
- return testStringCoercion(value);
5646
- }
5647
- }
5648
- function getTaskName(type) {
5649
- if (type === REACT_FRAGMENT_TYPE) return "<>";
5650
- if ("object" === typeof type && null !== type && type.$$typeof === REACT_LAZY_TYPE)
5651
- return "<...>";
5652
- try {
5653
- var name = getComponentNameFromType(type);
5654
- return name ? "<" + name + ">" : "<...>";
5655
- } catch (x) {
5656
- return "<...>";
5657
- }
5658
- }
5659
- function getOwner() {
5660
- var dispatcher = ReactSharedInternals.A;
5661
- return null === dispatcher ? null : dispatcher.getOwner();
5662
- }
5663
- function UnknownOwner() {
5664
- return Error("react-stack-top-frame");
5665
- }
5666
- function hasValidKey(config) {
5667
- if (hasOwnProperty.call(config, "key")) {
5668
- var getter = Object.getOwnPropertyDescriptor(config, "key").get;
5669
- if (getter && getter.isReactWarning) return false;
5670
- }
5671
- return void 0 !== config.key;
5672
- }
5673
- function defineKeyPropWarningGetter(props, displayName) {
5674
- function warnAboutAccessingKey() {
5675
- specialPropKeyWarningShown || (specialPropKeyWarningShown = true, console.error(
5676
- "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
5677
- displayName
5678
- ));
5679
- }
5680
- warnAboutAccessingKey.isReactWarning = true;
5681
- Object.defineProperty(props, "key", {
5682
- get: warnAboutAccessingKey,
5683
- configurable: true
5684
- });
5685
- }
5686
- function elementRefGetterWithDeprecationWarning() {
5687
- var componentName = getComponentNameFromType(this.type);
5688
- didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = true, console.error(
5689
- "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
5690
- ));
5691
- componentName = this.props.ref;
5692
- return void 0 !== componentName ? componentName : null;
5693
- }
5694
- function ReactElement(type, key, self, source, owner, props, debugStack, debugTask) {
5695
- self = props.ref;
5696
- type = {
5697
- $$typeof: REACT_ELEMENT_TYPE,
5698
- type,
5699
- key,
5700
- props,
5701
- _owner: owner
5702
- };
5703
- null !== (void 0 !== self ? self : null) ? Object.defineProperty(type, "ref", {
5704
- enumerable: false,
5705
- get: elementRefGetterWithDeprecationWarning
5706
- }) : Object.defineProperty(type, "ref", { enumerable: false, value: null });
5707
- type._store = {};
5708
- Object.defineProperty(type._store, "validated", {
5709
- configurable: false,
5710
- enumerable: false,
5711
- writable: true,
5712
- value: 0
5713
- });
5714
- Object.defineProperty(type, "_debugInfo", {
5715
- configurable: false,
5716
- enumerable: false,
5717
- writable: true,
5718
- value: null
5719
- });
5720
- Object.defineProperty(type, "_debugStack", {
5721
- configurable: false,
5722
- enumerable: false,
5723
- writable: true,
5724
- value: debugStack
5725
- });
5726
- Object.defineProperty(type, "_debugTask", {
5727
- configurable: false,
5728
- enumerable: false,
5729
- writable: true,
5730
- value: debugTask
5731
- });
5732
- Object.freeze && (Object.freeze(type.props), Object.freeze(type));
5733
- return type;
5734
- }
5735
- function jsxDEVImpl(type, config, maybeKey, isStaticChildren, source, self, debugStack, debugTask) {
5736
- var children = config.children;
5737
- if (void 0 !== children)
5738
- if (isStaticChildren)
5739
- if (isArrayImpl(children)) {
5740
- for (isStaticChildren = 0; isStaticChildren < children.length; isStaticChildren++)
5741
- validateChildKeys(children[isStaticChildren]);
5742
- Object.freeze && Object.freeze(children);
5743
- } else
5744
- console.error(
5745
- "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
5746
- );
5747
- else validateChildKeys(children);
5748
- if (hasOwnProperty.call(config, "key")) {
5749
- children = getComponentNameFromType(type);
5750
- var keys = Object.keys(config).filter(function(k) {
5751
- return "key" !== k;
5752
- });
5753
- isStaticChildren = 0 < keys.length ? "{key: someKey, " + keys.join(": ..., ") + ": ...}" : "{key: someKey}";
5754
- didWarnAboutKeySpread[children + isStaticChildren] || (keys = 0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}", console.error(
5755
- 'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',
5756
- isStaticChildren,
5757
- children,
5758
- keys,
5759
- children
5760
- ), didWarnAboutKeySpread[children + isStaticChildren] = true);
5761
- }
5762
- children = null;
5763
- void 0 !== maybeKey && (checkKeyStringCoercion(maybeKey), children = "" + maybeKey);
5764
- hasValidKey(config) && (checkKeyStringCoercion(config.key), children = "" + config.key);
5765
- if ("key" in config) {
5766
- maybeKey = {};
5767
- for (var propName in config)
5768
- "key" !== propName && (maybeKey[propName] = config[propName]);
5769
- } else maybeKey = config;
5770
- children && defineKeyPropWarningGetter(
5771
- maybeKey,
5772
- "function" === typeof type ? type.displayName || type.name || "Unknown" : type
5773
- );
5774
- return ReactElement(
5775
- type,
5776
- children,
5777
- self,
5778
- source,
5779
- getOwner(),
5780
- maybeKey,
5781
- debugStack,
5782
- debugTask
5783
- );
5784
- }
5785
- function validateChildKeys(node) {
5786
- "object" === typeof node && null !== node && node.$$typeof === REACT_ELEMENT_TYPE && node._store && (node._store.validated = 1);
5787
- }
5788
- var React$1 = React, REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler");
5789
- var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = React$1.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
5790
- return null;
5791
- };
5792
- React$1 = {
5793
- "react-stack-bottom-frame": function(callStackForError) {
5794
- return callStackForError();
5795
- }
5796
- };
5797
- var specialPropKeyWarningShown;
5798
- var didWarnAboutElementRef = {};
5799
- var unknownOwnerDebugStack = React$1["react-stack-bottom-frame"].bind(
5800
- React$1,
5801
- UnknownOwner
5802
- )();
5803
- var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
5804
- var didWarnAboutKeySpread = {};
5805
- reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
5806
- reactJsxRuntime_development.jsx = function(type, config, maybeKey, source, self) {
5807
- var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
5808
- return jsxDEVImpl(
5809
- type,
5810
- config,
5811
- maybeKey,
5812
- false,
5813
- source,
5814
- self,
5815
- trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack,
5816
- trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
5817
- );
5818
- };
5819
- reactJsxRuntime_development.jsxs = function(type, config, maybeKey, source, self) {
5820
- var trackActualOwner = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
5821
- return jsxDEVImpl(
5822
- type,
5823
- config,
5824
- maybeKey,
5825
- true,
5826
- source,
5827
- self,
5828
- trackActualOwner ? Error("react-stack-top-frame") : unknownOwnerDebugStack,
5829
- trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask
5830
- );
5831
- };
5832
- }();
5833
- return reactJsxRuntime_development;
5834
- }
5835
5797
  var hasRequiredJsxRuntime;
5836
5798
  function requireJsxRuntime() {
5837
5799
  if (hasRequiredJsxRuntime) return jsxRuntime.exports;
5838
5800
  hasRequiredJsxRuntime = 1;
5839
- if (process.env.NODE_ENV === "production") {
5801
+ {
5840
5802
  jsxRuntime.exports = requireReactJsxRuntime_production();
5841
- } else {
5842
- jsxRuntime.exports = requireReactJsxRuntime_development();
5843
5803
  }
5844
5804
  return jsxRuntime.exports;
5845
5805
  }