@notificationapi/react 1.2.0 → 1.4.0

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/README.md CHANGED
@@ -6,6 +6,22 @@ The React SDK is mainly used for displaying In-App Notifications, allowing users
6
6
 
7
7
  Please refer to our [documentations](https://docs.notificationapi.com).
8
8
 
9
+ # Debug Mode
10
+
11
+ The SDK includes a comprehensive debug mode to help troubleshoot issues and understand SDK behavior. Enable it by adding the `debug` prop:
12
+
13
+ ```jsx
14
+ <NotificationAPIProvider
15
+ clientId="your-client-id"
16
+ userId="your-user-id"
17
+ debug={true}
18
+ >
19
+ {/* Your app components */}
20
+ </NotificationAPIProvider>
21
+ ```
22
+
23
+ For detailed information about debug mode, see [DEBUG.md](./DEBUG.md).
24
+
9
25
  # Development
10
26
 
11
27
  1. Install dependencies:
@@ -20,6 +36,8 @@ npm install
20
36
  npm run dev
21
37
  ```
22
38
 
39
+ The example application includes a debug mode toggle to demonstrate the feature.
40
+
23
41
  # React + TypeScript + Vite
24
42
 
25
43
  This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
@@ -100,7 +118,7 @@ We welcome contributions! To ensure smooth collaboration, please follow these st
100
118
 
101
119
  5. **Commit and Push**
102
120
 
103
- - Once youve made and tested your changes, commit them with a meaningful message:
121
+ - Once you've made and tested your changes, commit them with a meaningful message:
104
122
 
105
123
  ```bash
106
124
  git add .
@@ -19,6 +19,7 @@ type Props = ({
19
19
  client?: typeof NotificationAPIClientSDK;
20
20
  webPushOptInMessage?: 'AUTOMATIC' | boolean;
21
21
  customServiceWorkerPath?: string;
22
+ debug?: boolean;
22
23
  };
23
24
  export declare const NotificationAPIProvider: React.FunctionComponent<PropsWithChildren<Props>> & {
24
25
  useNotificationAPIContext: typeof useNotificationAPIContext;
@@ -1,25 +1,59 @@
1
- import { jsx as Q } from "react/jsx-runtime";
2
- import { useState as I, useCallback as m, useMemo as X, useRef as U, useEffect as y, useContext as Y } from "react";
3
- import { NotificationAPIContext as H } from "./context.js";
4
- const Z = async (e, c, i, a, f, b, h) => {
5
- const l = ee(a, f, b), g = await fetch(
6
- `https://${c}/${a}/users/${encodeURIComponent(
7
- f
8
- )}/${i}`,
9
- {
10
- method: e,
11
- body: JSON.stringify(h),
12
- headers: {
13
- Authorization: `Basic ${l}`
14
- }
15
- }
16
- );
1
+ import { jsx as oe } from "react/jsx-runtime";
2
+ import { useMemo as z, useState as N, useCallback as A, useRef as F, useEffect as E, useContext as ie } from "react";
3
+ import { NotificationAPIContext as V } from "./context.js";
4
+ import { createDebugLogger as ne, formatApiCall as C } from "../../utils/debug.js";
5
+ const re = async (o, e, u, a, c, h, I, l) => {
6
+ const p = se(a, c, h), b = `https://${e}/${a}/users/${encodeURIComponent(
7
+ c
8
+ )}/${u}`, w = {
9
+ Authorization: `Basic ${p}`
10
+ };
11
+ l && l.log("HTTP Request:", {
12
+ method: o,
13
+ host: e,
14
+ url: b,
15
+ body: I
16
+ });
17
+ const v = Date.now();
17
18
  try {
18
- return await g.json();
19
- } catch {
20
- return;
19
+ const m = await fetch(b, {
20
+ method: o,
21
+ body: JSON.stringify(I),
22
+ headers: w
23
+ });
24
+ l && l.log("HTTP Response:", m);
25
+ try {
26
+ const P = await m.json();
27
+ return l && l.log("Response Data:", P), P;
28
+ } catch (P) {
29
+ l && l.warn("Failed to parse response as JSON:", P);
30
+ return;
31
+ }
32
+ } catch (m) {
33
+ const P = Date.now() - v;
34
+ throw l && l.error("HTTP Request Failed:", {
35
+ error: m,
36
+ url: b,
37
+ headers: w,
38
+ duration: `${P}ms`
39
+ }), m;
40
+ }
41
+ }, se = (o, e, u) => btoa(u ? o + ":" + e + ":" + u : o + ":" + e);
42
+ class B {
43
+ constructor(e = !1) {
44
+ this.debug = e;
21
45
  }
22
- }, ee = (e, c, i) => btoa(i ? e + ":" + c + ":" + i : e + ":" + c), q = {
46
+ log(...e) {
47
+ this.debug && console.log("[NotificationAPI js core SDK Debug]", ...e);
48
+ }
49
+ warn(...e) {
50
+ this.debug && console.warn("[NotificationAPI js core SDK Debug]", ...e);
51
+ }
52
+ error(...e) {
53
+ this.debug && console.error("[NotificationAPI js core SDK Debug]", ...e);
54
+ }
55
+ }
56
+ const J = {
23
57
  host: "api.notificationapi.com",
24
58
  websocketHost: "ws.notificationapi.com",
25
59
  userId: "",
@@ -27,84 +61,114 @@ const Z = async (e, c, i, a, f, b, h) => {
27
61
  hashedUserId: "",
28
62
  getInAppDefaultCount: 100,
29
63
  getInAppDefaultOldest: new Date(
30
- Date.now() - 2592e6
64
+ Date.now() - 30 * 24 * 60 * 60 * 1e3
31
65
  ).toISOString(),
32
66
  onNewInAppNotifications: void 0,
33
- keepWebSocketAliveForSeconds: 86400
67
+ keepWebSocketAliveForSeconds: 24 * 60 * 60,
34
68
  // 24 hours
35
- }, o = {
36
- config: q,
37
- init: function(e) {
38
- return this.config = { ...q, ...e }, {
69
+ debug: !1
70
+ }, s = {
71
+ config: J,
72
+ logger: new B(!1),
73
+ init: function(o) {
74
+ return this.config = { ...J, ...o }, this.logger = new B(this.config.debug), this.logger.log("Initialized with config:", {
75
+ userId: this.config.userId,
76
+ clientId: this.config.clientId,
77
+ host: this.config.host,
78
+ websocketHost: this.config.websocketHost,
79
+ debug: this.config.debug,
80
+ hasHashedUserId: !!this.config.hashedUserId
81
+ }), {
39
82
  ...this
40
83
  };
41
84
  },
42
85
  rest: {
43
- generic: function(e, c, i) {
44
- return Z(
86
+ generic: function(o, e, u) {
87
+ return s.logger.log(
88
+ `API Call: ${o} ${e}`,
89
+ u ? { body: u } : ""
90
+ ), re(
91
+ o,
92
+ s.config.host,
45
93
  e,
46
- o.config.host,
47
- c,
48
- o.config.clientId,
49
- o.config.userId,
50
- o.config.hashedUserId,
51
- i
94
+ s.config.clientId,
95
+ s.config.userId,
96
+ s.config.hashedUserId,
97
+ u,
98
+ s.logger
52
99
  );
53
100
  },
54
101
  // The functions below are nice wrappers over the generic
55
102
  // rest api function above. They must follow REST API naming:
56
103
  // Method + Resource, representing the end-point.
57
- getNotifications: function(e, c) {
58
- return o.rest.generic(
104
+ getNotifications: function(o, e) {
105
+ return s.rest.generic(
59
106
  "GET",
60
- `notifications/INAPP_WEB?count=${c}&before=${e}`
107
+ `notifications/INAPP_WEB?count=${e}&before=${o}`
61
108
  );
62
109
  },
63
- patchNotifications: function(e) {
64
- return o.rest.generic(
110
+ patchNotifications: function(o) {
111
+ return s.rest.generic(
65
112
  "PATCH",
66
113
  "notifications/INAPP_WEB",
67
- e
114
+ o
68
115
  );
69
116
  },
70
117
  getPreferences: function() {
71
- return o.rest.generic("GET", "preferences");
118
+ return s.rest.generic("GET", "preferences");
72
119
  },
73
- postPreferences: function(e) {
74
- return o.rest.generic(
120
+ postPreferences: function(o) {
121
+ return s.rest.generic(
75
122
  "POST",
76
123
  "preferences",
77
- e
124
+ o
78
125
  );
79
126
  },
80
- postUser: function(e) {
81
- return o.rest.generic("POST", "", e);
127
+ postUser: function(o) {
128
+ return s.rest.generic("POST", "", o);
82
129
  },
83
130
  getUserAccountMetadata: function() {
84
- return o.rest.generic("GET", "account_metadata");
131
+ return s.rest.generic("GET", "account_metadata");
85
132
  }
86
133
  },
87
134
  websocket: {
88
135
  object: void 0,
89
136
  connect: function() {
90
- let e = `wss://${o.config.websocketHost}?userId=${encodeURIComponent(o.config.userId)}&envId=${o.config.clientId}`;
91
- return o.config.hashedUserId && (e += `&userIdHash=${encodeURIComponent(o.config.hashedUserId)}`), o.websocket.object = new WebSocket(e), o.websocket.object.onmessage = (c) => {
92
- const i = JSON.parse(c.data);
93
- if (!(!i || !i.route) && i.route === "inapp_web/new_notifications") {
94
- const a = i;
95
- o.config.onNewInAppNotifications && o.config.onNewInAppNotifications(
137
+ let o = `wss://${s.config.websocketHost}?userId=${encodeURIComponent(s.config.userId)}&envId=${s.config.clientId}`;
138
+ return s.config.hashedUserId && (o += `&userIdHash=${encodeURIComponent(s.config.hashedUserId)}`), s.logger.log("WebSocket connecting to:", o), s.websocket.object = new WebSocket(o), s.websocket.object.onopen = () => {
139
+ s.logger.log("WebSocket connection opened");
140
+ }, s.websocket.object.onclose = (e) => {
141
+ s.logger.log("WebSocket connection closed:", {
142
+ code: e.code,
143
+ reason: e.reason,
144
+ wasClean: e.wasClean
145
+ });
146
+ }, s.websocket.object.onerror = (e) => {
147
+ s.logger.error("WebSocket error:", e);
148
+ }, s.websocket.object.onmessage = (e) => {
149
+ s.logger.log(
150
+ "WebSocket message received:",
151
+ e.data
152
+ );
153
+ const u = JSON.parse(e.data);
154
+ if (!(!u || !u.route) && u.route === "inapp_web/new_notifications") {
155
+ const a = u;
156
+ s.logger.log(
157
+ "New notifications received:",
158
+ a.payload.notifications
159
+ ), s.config.onNewInAppNotifications && s.config.onNewInAppNotifications(
96
160
  a.payload.notifications
97
161
  );
98
162
  }
99
- }, o.websocket.object;
163
+ }, s.websocket.object;
100
164
  },
101
- disconnect: function(e) {
102
- var c;
103
- o.websocket.object && ((c = o.websocket.object) == null || c.close(), e && e(o.websocket.object));
165
+ disconnect: function(o) {
166
+ var e;
167
+ s.websocket.object && (s.logger.log("WebSocket disconnecting"), (e = s.websocket.object) == null || e.close(), o && o(s.websocket.object));
104
168
  }
105
169
  },
106
170
  openWebSocket: function() {
107
- return o.websocket.connect(() => {
171
+ return s.websocket.connect(() => {
108
172
  setTimeout(
109
173
  () => {
110
174
  this.websocket.disconnect(() => {
@@ -118,45 +182,83 @@ const Z = async (e, c, i, a, f, b, h) => {
118
182
  // These functions are developer friendly wrappers over the rest APIs
119
183
  // They may or may not do additional tasks.
120
184
  // e.g. identify simply maps to postUsers
121
- getInAppNotifications: async (e) => {
122
- const c = e.maxCountNeeded || o.config.getInAppDefaultCount, i = e.oldestNeeded || o.config.getInAppDefaultOldest;
123
- let a = [], f = e.before, b = !0, h = !0;
124
- for (; h; ) {
125
- const l = (await o.rest.getNotifications(
126
- f,
127
- c
128
- )).notifications.filter(
129
- (g) => !a.find((w) => w.id === g.id)
185
+ getInAppNotifications: async (o) => {
186
+ s.logger.log(
187
+ "getInAppNotifications called with params:",
188
+ o
189
+ );
190
+ const e = o.maxCountNeeded || s.config.getInAppDefaultCount, u = o.oldestNeeded || s.config.getInAppDefaultOldest;
191
+ s.logger.log("Fetching notifications with:", {
192
+ maxCountNeeded: e,
193
+ oldestNeeded: u,
194
+ before: o.before
195
+ });
196
+ let a = [], c = o.before, h = !0, I = !0;
197
+ for (; I; ) {
198
+ const l = (await s.rest.getNotifications(
199
+ c,
200
+ e
201
+ )).notifications, p = l.filter(
202
+ (b) => !a.find((w) => w.id === b.id)
130
203
  );
131
- f = l.reduce(
132
- (g, w) => g < w.date ? g : w.date,
133
- e.before
134
- ), a = [...a, ...l], b = l.length > 0, h = !0, (!b || a.length >= c || f < i) && (h = !1);
204
+ s.logger.log(
205
+ `Received ${l.length} notifications, ${p.length} unique`
206
+ ), c = p.reduce(
207
+ (b, w) => b < w.date ? b : w.date,
208
+ o.before
209
+ ), a = [...a, ...p], h = p.length > 0, I = !0, (!h || a.length >= e || c < u) && (I = !1, s.logger.log("Stopping fetch loop:", {
210
+ hasMore: h,
211
+ totalResults: a.length,
212
+ maxCountNeeded: e,
213
+ oldestReceived: c,
214
+ oldestNeeded: u
215
+ }));
135
216
  }
136
- return {
217
+ return s.logger.log("getInAppNotifications completed:", {
218
+ totalItems: a.length,
219
+ hasMore: h,
220
+ oldestReceived: c
221
+ }), {
137
222
  items: a,
138
- hasMore: b,
139
- oldestReceived: f
223
+ hasMore: h,
224
+ oldestReceived: c
140
225
  };
141
226
  },
142
- updateInAppNotifications: async (e) => {
143
- const c = {
144
- trackingIds: e.ids
227
+ updateInAppNotifications: async (o) => {
228
+ s.logger.log(
229
+ "updateInAppNotifications called with params:",
230
+ o
231
+ );
232
+ const e = {
233
+ trackingIds: o.ids
145
234
  };
146
- return e.archived === !0 ? c.archived = (/* @__PURE__ */ new Date()).toISOString() : e.archived === !1 && (c.archived = null), e.clicked === !0 ? c.clicked = (/* @__PURE__ */ new Date()).toISOString() : e.clicked === !1 && (c.clicked = null), e.opened === !0 ? c.opened = (/* @__PURE__ */ new Date()).toISOString() : e.opened === !1 && (c.opened = null), o.rest.patchNotifications(c);
235
+ return o.archived === !0 ? e.archived = (/* @__PURE__ */ new Date()).toISOString() : o.archived === !1 && (e.archived = null), o.clicked === !0 ? e.clicked = (/* @__PURE__ */ new Date()).toISOString() : o.clicked === !1 && (e.clicked = null), o.opened === !0 ? e.opened = (/* @__PURE__ */ new Date()).toISOString() : o.opened === !1 && (e.opened = null), s.logger.log(
236
+ "Updating notifications with body:",
237
+ e
238
+ ), s.rest.patchNotifications(e);
147
239
  },
148
- getPreferences: async () => o.rest.getPreferences(),
149
- updateDeliveryOption: async (e) => o.rest.postPreferences([e]),
150
- identify: async (e) => {
151
- if (e.id && e.id !== o.config.userId)
240
+ getPreferences: async () => s.rest.getPreferences(),
241
+ updateDeliveryOption: async (o) => s.rest.postPreferences([o]),
242
+ identify: async (o) => {
243
+ if (o.id && o.id !== s.config.userId)
152
244
  throw new Error(
153
245
  "The id in the parameters does not match the initialized userId."
154
246
  );
155
- return o.rest.postUser(e);
247
+ return s.rest.postUser(o);
156
248
  },
157
- getUserAccountMetadata: async () => o.rest.getUserAccountMetadata()
158
- }, F = typeof window < "u", te = (e) => {
159
- const i = {
249
+ getUserAccountMetadata: async () => s.rest.getUserAccountMetadata()
250
+ }, G = typeof window < "u", ae = (o) => {
251
+ const e = z(
252
+ () => ne(o.debug || !1),
253
+ [o.debug]
254
+ );
255
+ e.log("NotificationAPI Provider initializing", {
256
+ clientId: o.clientId,
257
+ userId: "userId" in o ? o.userId : o.user.id,
258
+ debug: o.debug || !1,
259
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
260
+ });
261
+ const a = {
160
262
  ...{
161
263
  apiURL: "api.notificationapi.com",
162
264
  wsURL: "ws.notificationapi.com",
@@ -167,153 +269,315 @@ const Z = async (e, c, i, a, f, b, h) => {
167
269
  webPushOptInMessage: "AUTOMATIC",
168
270
  customServiceWorkerPath: "/notificationapi-service-worker.js"
169
271
  },
170
- ...e,
171
- user: "userId" in e ? { id: e.userId } : e.user
172
- }, [a, f] = I(), [b, h] = I(), [l, g] = I(), [w, S] = I(!1), [k, T] = I((/* @__PURE__ */ new Date()).toISOString()), [A, C] = I(!0), [v, N] = I(i.webPushOptInMessage), [L, J] = I(!1), W = m(() => {
173
- i.playSoundOnNewNotification && new Audio(i.newNotificationSoundPath).play().catch((s) => {
174
- console.log("Failed to play new notification sound:", s);
175
- });
176
- }, [i.newNotificationSoundPath, i.playSoundOnNewNotification]), P = m((t) => {
177
- const s = (/* @__PURE__ */ new Date()).toISOString();
178
- f((n) => (t = Array.isArray(t) ? t : [], t = t.filter((d) => {
179
- const p = d.expDate && new Date(d.expDate).toISOString() > s, D = new Date(d.date).getTime() > new Date(s).getTime() + 1e3;
180
- return !p && !D;
181
- }), n = Array.isArray(n) ? n : [], [
182
- ...t.filter((d) => !n.find((D) => D.id === d.id)),
183
- ...n
184
- ]));
185
- }, []), u = X(() => {
186
- const t = e.client ? e.client : o.init({
187
- clientId: i.clientId,
188
- userId: i.user.id,
189
- hashedUserId: i.hashedUserId,
190
- onNewInAppNotifications: (s) => {
191
- W(), P(s);
192
- },
193
- host: i.apiURL,
194
- websocketHost: i.wsURL
195
- });
196
- return t.identify({
197
- email: i.user.email,
198
- number: i.user.number
199
- }), t;
272
+ ...o,
273
+ user: "userId" in o ? { id: o.userId } : o.user
274
+ };
275
+ e.log("Configuration loaded", a);
276
+ const [c, h] = N(), [I, l] = N(), [p, b] = N(), [w, v] = N(!1), [m, P] = N((/* @__PURE__ */ new Date()).toISOString()), [D, x] = N(!0), [k, y] = N(a.webPushOptInMessage), [M, Q] = N(!1), $ = A(() => {
277
+ a.playSoundOnNewNotification && (e.log("Playing notification sound", {
278
+ soundPath: a.newNotificationSoundPath
279
+ }), new Audio(a.newNotificationSoundPath).play().catch((n) => {
280
+ e.error("Failed to play new notification sound", n), console.log("Failed to play new notification sound:", n);
281
+ }));
200
282
  }, [
201
- i.clientId,
202
- i.user.id,
203
- i.user.email,
204
- i.user.number,
205
- i.hashedUserId,
206
- P,
207
- W,
208
- e.client,
209
- i.apiURL,
210
- i.wsURL
211
- ]), x = m(
212
- async (t, s) => {
213
- const n = await u.rest.getNotifications(t, s);
214
- T(n.oldestReceived), C(n.couldLoadMore), P(n.notifications);
283
+ a.newNotificationSoundPath,
284
+ a.playSoundOnNewNotification,
285
+ e
286
+ ]), O = A(
287
+ (t) => {
288
+ e.group("Adding notifications to state"), e.log("Received notifications", {
289
+ count: (t == null ? void 0 : t.length) || 0,
290
+ notifications: t
291
+ });
292
+ const n = (/* @__PURE__ */ new Date()).toISOString();
293
+ h((i) => {
294
+ const r = (i == null ? void 0 : i.length) || 0;
295
+ e.log("Current notifications count", r), t = Array.isArray(t) ? t : [], t = t.filter((g) => {
296
+ const S = g.expDate && new Date(g.expDate).toISOString() > n, L = new Date(g.date).getTime() > new Date(n).getTime() + 1e3, K = !S && !L;
297
+ return K || e.log("Filtering out notification", {
298
+ id: g.id,
299
+ reason: S ? "expired" : "future",
300
+ expDate: g.expDate,
301
+ date: g.date
302
+ }), K;
303
+ }), i = Array.isArray(i) ? i : [];
304
+ const d = [
305
+ ...t.filter((g) => {
306
+ const S = i.find((L) => L.id === g.id);
307
+ return S && e.log("Filtering out duplicate notification", { id: g.id }), !S;
308
+ }),
309
+ ...i
310
+ ];
311
+ return e.log("State updated", {
312
+ previousCount: r,
313
+ newCount: d.length,
314
+ addedCount: t.length
315
+ }), e.groupEnd(), d;
316
+ });
317
+ },
318
+ [e]
319
+ ), f = z(() => {
320
+ e.group("Initializing NotificationAPI client");
321
+ const t = {
322
+ clientId: a.clientId,
323
+ userId: a.user.id,
324
+ hashedUserId: a.hashedUserId,
325
+ host: a.apiURL,
326
+ websocketHost: a.wsURL,
327
+ debug: a.debug
328
+ };
329
+ e.log("Client configuration", t);
330
+ const n = o.client ? o.client : s.init({
331
+ ...t,
332
+ onNewInAppNotifications: (r) => {
333
+ e.log("Received new in-app notifications via WebSocket", {
334
+ count: (r == null ? void 0 : r.length) || 0,
335
+ notifications: r
336
+ }), $(), O(r);
337
+ }
338
+ }), i = {
339
+ email: a.user.email,
340
+ number: a.user.number
341
+ };
342
+ return e.log("Identifying user", i), n.identify(i), e.groupEnd(), n;
343
+ }, [
344
+ a.clientId,
345
+ a.user.id,
346
+ a.user.email,
347
+ a.user.number,
348
+ a.hashedUserId,
349
+ a.debug,
350
+ O,
351
+ $,
352
+ o.client,
353
+ a.apiURL,
354
+ a.wsURL,
355
+ e
356
+ ]), j = A(
357
+ async (t, n) => {
358
+ var i;
359
+ e.group("Fetching notifications"), e.log(
360
+ "Fetch parameters",
361
+ C("GET", "/notifications", { date: t, count: n })
362
+ );
363
+ try {
364
+ const r = await f.rest.getNotifications(t, n);
365
+ e.log("Fetch successful", {
366
+ notificationsCount: ((i = r.notifications) == null ? void 0 : i.length) || 0,
367
+ oldestReceived: r.oldestReceived,
368
+ couldLoadMore: r.couldLoadMore
369
+ }), P(r.oldestReceived), x(r.couldLoadMore), O(r.notifications), e.groupEnd();
370
+ } catch (r) {
371
+ throw e.error("Failed to fetch notifications", r, { date: t, count: n }), e.groupEnd(), r;
372
+ }
215
373
  },
216
- [P, u.rest]
217
- ), E = U(A), R = U(w), $ = U(k);
218
- y(() => {
219
- E.current = A, R.current = w, $.current = k;
220
- }, [A, w, k]);
221
- const O = m(
374
+ [O, f.rest, e]
375
+ ), U = F(D), W = F(w), q = F(m);
376
+ E(() => {
377
+ U.current = D, W.current = w, q.current = m;
378
+ }, [D, w, m]);
379
+ const T = A(
222
380
  async (t) => {
223
- if (!(!t && (!E.current || R.current))) {
224
- S(!0);
225
- try {
226
- await x(
227
- t ? (/* @__PURE__ */ new Date()).toISOString() : $.current,
228
- t ? i.initialLoadMaxCount : 1e3
229
- );
230
- } finally {
231
- S(!1);
232
- }
381
+ if (e.group(`Loading notifications (${t ? "initial" : "more"})`), e.log("Load conditions", {
382
+ initial: t,
383
+ hasMore: U.current,
384
+ loading: W.current
385
+ }), !t && (!U.current || W.current)) {
386
+ e.log("Skipping load - conditions not met"), e.groupEnd();
387
+ return;
388
+ }
389
+ v(!0), e.log("Loading started");
390
+ try {
391
+ await j(
392
+ t ? (/* @__PURE__ */ new Date()).toISOString() : q.current,
393
+ t ? a.initialLoadMaxCount : 1e3
394
+ ), e.log("Loading completed successfully");
395
+ } catch (n) {
396
+ throw e.error("Loading failed", n), n;
397
+ } finally {
398
+ v(!1), e.groupEnd();
233
399
  }
234
400
  },
235
- [i.initialLoadMaxCount, x]
236
- ), B = async (t) => {
237
- if (!a) return;
238
- const s = (/* @__PURE__ */ new Date()).toISOString(), n = a.filter((r) => t.includes(r.id) && !r.clicked).map((r) => r.id);
239
- u.updateInAppNotifications({ ids: n, clicked: !0 }), f((r) => {
240
- if (!r) return [];
241
- const d = [...r];
242
- return d.filter((p) => n.includes(p.id)).forEach((p) => {
243
- p.clicked = s;
244
- }), d;
245
- });
246
- }, G = async () => {
247
- if (!a) return;
248
- const t = (/* @__PURE__ */ new Date()).toISOString(), s = a.filter((n) => !n.opened || !n.seen).map((n) => n.id);
249
- s.length !== 0 && (u.updateInAppNotifications({
250
- ids: s,
251
- opened: !0
252
- }), f((n) => {
253
- if (!n) return [];
254
- const r = [...n];
255
- return r.filter((d) => s.includes(d.id)).forEach((d) => {
256
- d.opened = t, d.seen = !0;
257
- }), r;
258
- }));
259
- }, K = async (t) => {
260
- if (!a) return;
261
- const s = a.filter((n) => n.archived && (t === "ALL" || t.includes(n.id))).map((n) => n.id);
262
- s.length !== 0 && (u.updateInAppNotifications({
263
- ids: s,
264
- archived: !1
265
- }), f((n) => {
266
- if (!n) return [];
267
- const r = [...n];
268
- return r.filter((d) => s.includes(d.id)).forEach((d) => {
269
- d.archived = void 0;
270
- }), r;
271
- }));
272
- }, V = async (t) => {
273
- if (!a) return;
274
- const s = (/* @__PURE__ */ new Date()).toISOString(), n = a.filter((r) => !r.archived && (t === "ALL" || t.includes(r.id))).map((r) => r.id);
275
- n.length !== 0 && (u.updateInAppNotifications({ ids: n, archived: !0 }), f((r) => {
276
- if (!r) return [];
277
- const d = [...r];
278
- return d.filter((p) => n.includes(p.id)).forEach((p) => {
279
- p.archived = s;
280
- }), d;
281
- }));
282
- }, _ = (t, s, n, r) => j([
401
+ [a.initialLoadMaxCount, j, e]
402
+ ), X = async (t) => {
403
+ if (e.group("Marking notifications as clicked"), e.log("Requested IDs", t), !c) {
404
+ e.warn("No notifications available"), e.groupEnd();
405
+ return;
406
+ }
407
+ const n = (/* @__PURE__ */ new Date()).toISOString(), i = c.filter((r) => t.includes(r.id) && !r.clicked).map((r) => r.id);
408
+ if (e.log("Filtered IDs for update", {
409
+ requestedCount: t.length,
410
+ actualCount: i.length,
411
+ ids: i
412
+ }), i.length === 0) {
413
+ e.log("No notifications to update"), e.groupEnd();
414
+ return;
415
+ }
416
+ try {
417
+ e.log(
418
+ "Updating notifications via API",
419
+ C("PUT", "/notifications/clicked", { ids: i })
420
+ ), f.updateInAppNotifications({ ids: i, clicked: !0 }), h((r) => {
421
+ if (!r) return [];
422
+ const d = [...r];
423
+ return d.filter((g) => i.includes(g.id)).forEach((g) => {
424
+ g.clicked = n;
425
+ }), e.log("Local state updated", { updatedCount: i.length }), d;
426
+ }), e.groupEnd();
427
+ } catch (r) {
428
+ throw e.error("Failed to mark notifications as clicked", r, { ids: i }), e.groupEnd(), r;
429
+ }
430
+ }, Y = async () => {
431
+ if (e.group("Marking notifications as opened"), !c) {
432
+ e.warn("No notifications available"), e.groupEnd();
433
+ return;
434
+ }
435
+ const t = (/* @__PURE__ */ new Date()).toISOString(), n = c.filter((i) => !i.opened || !i.seen).map((i) => i.id);
436
+ if (e.log("Notifications to mark as opened", { count: n.length, ids: n }), n.length === 0) {
437
+ e.log("All notifications already opened"), e.groupEnd();
438
+ return;
439
+ }
440
+ try {
441
+ e.log(
442
+ "Updating notifications via API",
443
+ C("PUT", "/notifications/opened", { ids: n })
444
+ ), f.updateInAppNotifications({
445
+ ids: n,
446
+ opened: !0
447
+ }), h((i) => {
448
+ if (!i) return [];
449
+ const r = [...i];
450
+ return r.filter((d) => n.includes(d.id)).forEach((d) => {
451
+ d.opened = t, d.seen = !0;
452
+ }), e.log("Local state updated", { updatedCount: n.length }), r;
453
+ }), e.groupEnd();
454
+ } catch (i) {
455
+ throw e.error("Failed to mark notifications as opened", i, { ids: n }), e.groupEnd(), i;
456
+ }
457
+ }, Z = async (t) => {
458
+ if (e.group("Marking notifications as unarchived"), e.log("Requested operation", { ids: t }), !c) {
459
+ e.warn("No notifications available"), e.groupEnd();
460
+ return;
461
+ }
462
+ const n = c.filter((i) => i.archived && (t === "ALL" || t.includes(i.id))).map((i) => i.id);
463
+ if (e.log("Filtered notifications for unarchiving", {
464
+ count: n.length,
465
+ ids: n
466
+ }), n.length === 0) {
467
+ e.log("No archived notifications to unarchive"), e.groupEnd();
468
+ return;
469
+ }
470
+ try {
471
+ e.log(
472
+ "Updating notifications via API",
473
+ C("PUT", "/notifications/unarchived", { ids: n })
474
+ ), f.updateInAppNotifications({
475
+ ids: n,
476
+ archived: !1
477
+ }), h((i) => {
478
+ if (!i) return [];
479
+ const r = [...i];
480
+ return r.filter((d) => n.includes(d.id)).forEach((d) => {
481
+ d.archived = void 0;
482
+ }), e.log("Local state updated", { unarchivedCount: n.length }), r;
483
+ }), e.groupEnd();
484
+ } catch (i) {
485
+ throw e.error("Failed to unarchive notifications", i, { ids: n }), e.groupEnd(), i;
486
+ }
487
+ }, _ = async (t) => {
488
+ if (e.group("Marking notifications as archived"), e.log("Requested operation", { ids: t }), !c) {
489
+ e.warn("No notifications available"), e.groupEnd();
490
+ return;
491
+ }
492
+ const n = (/* @__PURE__ */ new Date()).toISOString(), i = c.filter((r) => !r.archived && (t === "ALL" || t.includes(r.id))).map((r) => r.id);
493
+ if (e.log("Filtered notifications for archiving", {
494
+ count: i.length,
495
+ ids: i
496
+ }), i.length === 0) {
497
+ e.log("No unarchived notifications to archive"), e.groupEnd();
498
+ return;
499
+ }
500
+ try {
501
+ e.log(
502
+ "Updating notifications via API",
503
+ C("PUT", "/notifications/archived", { ids: i })
504
+ ), f.updateInAppNotifications({ ids: i, archived: !0 }), h((r) => {
505
+ if (!r) return [];
506
+ const d = [...r];
507
+ return d.filter((g) => i.includes(g.id)).forEach((g) => {
508
+ g.archived = n;
509
+ }), e.log("Local state updated", { archivedCount: i.length }), d;
510
+ }), e.groupEnd();
511
+ } catch (r) {
512
+ throw e.error("Failed to archive notifications", r, { ids: i }), e.groupEnd(), r;
513
+ }
514
+ }, ee = (t, n, i, r) => (e.log("Updating single delivery preference", {
515
+ notificationId: t,
516
+ channel: n,
517
+ delivery: i,
518
+ subNotificationId: r
519
+ }), H([
283
520
  {
284
521
  notificationId: t,
285
- channel: s,
286
- delivery: n,
522
+ channel: n,
523
+ delivery: i,
287
524
  subNotificationId: r
288
525
  }
289
- ]), j = (t) => {
290
- u.rest.postPreferences(t).then(() => {
291
- u.getPreferences().then((s) => {
292
- h(s);
526
+ ])), H = (t) => {
527
+ e.group("Updating delivery preferences"), e.log("Preference updates", { count: t.length, params: t });
528
+ try {
529
+ f.rest.postPreferences(t).then(() => {
530
+ e.log(
531
+ "Preferences updated successfully, fetching latest preferences"
532
+ ), f.getPreferences().then((n) => {
533
+ var i, r, d;
534
+ e.log("Latest preferences fetched", {
535
+ preferencesCount: ((i = n.preferences) == null ? void 0 : i.length) || 0,
536
+ notificationsCount: ((r = n.notifications) == null ? void 0 : r.length) || 0,
537
+ subNotificationsCount: ((d = n.subNotifications) == null ? void 0 : d.length) || 0
538
+ }), l(n), e.groupEnd();
539
+ }).catch((n) => {
540
+ e.error("Failed to fetch updated preferences", n), e.groupEnd();
541
+ });
542
+ }).catch((n) => {
543
+ e.error("Failed to update preferences", n, { params: t }), e.groupEnd();
293
544
  });
294
- });
295
- }, M = m(() => {
296
- "serviceWorker" in navigator && navigator.serviceWorker.register(i.customServiceWorkerPath).then(async (t) => {
297
- N(!1), ne().then(async (s) => {
298
- s === "granted" ? await t.pushManager.subscribe({
545
+ } catch (n) {
546
+ throw e.error("Error in updateDeliveries", n, { params: t }), e.groupEnd(), n;
547
+ }
548
+ }, R = A(() => {
549
+ e.group("Requesting web push permission"), e.log("Service worker support check", {
550
+ supported: "serviceWorker" in navigator,
551
+ customServiceWorkerPath: a.customServiceWorkerPath
552
+ }), "serviceWorker" in navigator ? (e.log("Registering service worker"), navigator.serviceWorker.register(a.customServiceWorkerPath).then(async (t) => {
553
+ e.log("Service worker registered successfully"), y(!1), de().then(async (n) => {
554
+ e.log("Notification permission result", { permission: n }), n === "granted" ? (e.log("Permission granted, subscribing to push manager"), await t.pushManager.subscribe({
299
555
  userVisibleOnly: !0,
300
- applicationServerKey: l == null ? void 0 : l.userAccountMetadata.environmentVapidPublicKey
301
- }).then(async (n) => {
556
+ applicationServerKey: p == null ? void 0 : p.userAccountMetadata.environmentVapidPublicKey
557
+ }).then(async (i) => {
558
+ e.log("Push subscription successful");
302
559
  const r = {
303
560
  webPushTokens: [
304
561
  {
305
562
  sub: {
306
- endpoint: n.toJSON().endpoint,
307
- keys: n.toJSON().keys
563
+ endpoint: i.toJSON().endpoint,
564
+ keys: i.toJSON().keys
308
565
  }
309
566
  }
310
567
  ]
311
568
  };
312
- await u.identify(r), localStorage.setItem("hideWebPushOptInMessage", "true");
313
- }) : s === "denied" && console.log("Permission for notifications was denied");
569
+ e.log("Identifying user with web push tokens"), await f.identify(r), localStorage.setItem("hideWebPushOptInMessage", "true"), e.log("Web push setup completed successfully"), e.groupEnd();
570
+ })) : n === "denied" && (e.warn("Permission for notifications was denied"), console.log("Permission for notifications was denied"), e.groupEnd());
314
571
  });
315
572
  }).catch((t) => {
316
- t.code === 18 ? console.error(
573
+ e.error(
574
+ "Service worker registration or push subscription failed",
575
+ t,
576
+ {
577
+ errorCode: t.code,
578
+ customServiceWorkerPath: a.customServiceWorkerPath
579
+ }
580
+ ), t.code === 18 ? console.error(
317
581
  "NotificationAPI guide: Probably you are not setup the service worker correctly. Please check the documentation at https://docs.notificationapi.com/guides/web-push#step-by-step-implementation Step 3: Service Worker Setup."
318
582
  ) : t.code === 19 ? console.error(
319
583
  "The operation is aborted. This can happen if the user denies the permission request."
@@ -323,62 +587,95 @@ const Z = async (e, c, i, a, f, b, h) => {
323
587
  "The operation is not allowed. This can happen if the user has blocked notifications for the site. Please check your browser site settings Notifications part."
324
588
  ) : t.code === 22 ? console.error(
325
589
  "The operation is not supported. This can occur if the browser does not support the required features."
326
- ) : console.error(t);
327
- });
590
+ ) : console.error(t), e.groupEnd();
591
+ })) : (e.warn("Service worker not supported in this browser"), e.groupEnd());
328
592
  }, [
329
- u,
330
- i.customServiceWorkerPath,
331
- l == null ? void 0 : l.userAccountMetadata.environmentVapidPublicKey
593
+ f,
594
+ a.customServiceWorkerPath,
595
+ p == null ? void 0 : p.userAccountMetadata.environmentVapidPublicKey,
596
+ e
332
597
  ]);
333
- y(() => {
334
- f([]), S(!1), h(void 0), T((/* @__PURE__ */ new Date()).toISOString()), C(!0), O(!0), u.openWebSocket(), u.getPreferences().then((t) => {
335
- h(t);
598
+ E(() => {
599
+ e.group("Provider initialization effect"), e.log("Resetting state and loading initial data"), h([]), v(!1), l(void 0), P((/* @__PURE__ */ new Date()).toISOString()), x(!0), T(!0), e.log("Opening WebSocket connection"), f.openWebSocket(), e.log("Fetching user preferences"), f.getPreferences().then((t) => {
600
+ var n, i, r;
601
+ e.log("Initial preferences loaded", {
602
+ preferencesCount: ((n = t.preferences) == null ? void 0 : n.length) || 0,
603
+ notificationsCount: ((i = t.notifications) == null ? void 0 : i.length) || 0,
604
+ subNotificationsCount: ((r = t.subNotifications) == null ? void 0 : r.length) || 0
605
+ }), l(t), e.groupEnd();
606
+ }).catch((t) => {
607
+ e.error("Failed to fetch initial preferences", t), e.groupEnd();
336
608
  });
337
- }, [u, O, M]), y(() => {
338
- u.getUserAccountMetadata().then((t) => {
339
- g(t), F && "Notification" in window && typeof Notification.requestPermission == "function" ? Notification.permission !== "default" && N(!1) : N(t.userAccountMetadata.hasWebPushEnabled);
609
+ }, [f, T, R, e]), E(() => {
610
+ e.group("Fetching user account metadata"), f.getUserAccountMetadata().then((t) => {
611
+ e.log("User account metadata loaded", {
612
+ hasWebPushEnabled: t.userAccountMetadata.hasWebPushEnabled,
613
+ environmentVapidPublicKey: t.userAccountMetadata.environmentVapidPublicKey ? "present" : "missing"
614
+ }), b(t), G && "Notification" in window && typeof Notification.requestPermission == "function" ? (e.log("Browser notification support detected", {
615
+ permission: Notification.permission
616
+ }), Notification.permission !== "default" && (e.log(
617
+ "Setting webPushOptInMessage to false (permission already set)"
618
+ ), y(!1))) : (e.log(
619
+ "Browser notification not supported, using server setting",
620
+ {
621
+ hasWebPushEnabled: t.userAccountMetadata.hasWebPushEnabled
622
+ }
623
+ ), y(t.userAccountMetadata.hasWebPushEnabled)), e.groupEnd();
624
+ }).catch((t) => {
625
+ e.error("Failed to fetch user account metadata", t), e.groupEnd();
340
626
  });
341
- }, [u]), y(() => {
342
- v === "AUTOMATIC" && N(
343
- localStorage.getItem("hideWebPushOptInMessage") !== "true"
344
- );
345
- }, [v]), y(() => {
346
- L && M();
347
- }, [L, M]);
348
- const z = {
349
- notifications: a,
350
- preferences: b,
351
- userAccountMetaData: l,
352
- webPushOptInMessage: v,
353
- loadNotifications: O,
354
- markAsOpened: G,
355
- markAsArchived: V,
356
- markAsUnarchived: K,
357
- markAsClicked: B,
358
- updateDelivery: _,
359
- updateDeliveries: j,
360
- getClient: () => u,
361
- setWebPushOptInMessage: N,
362
- setWebPushOptIn: J
627
+ }, [f, e]), E(() => {
628
+ if (e.group("Handling webPushOptInMessage state"), e.log("webPushOptInMessage value", k), k === "AUTOMATIC") {
629
+ const t = localStorage.getItem("hideWebPushOptInMessage") === "true";
630
+ e.log("Automatic mode - checking localStorage", {
631
+ hideMessage: t,
632
+ shouldShow: !t
633
+ }), y(!t);
634
+ }
635
+ e.groupEnd();
636
+ }, [k, e]), E(() => {
637
+ e.group("Handling webPushOptIn state"), e.log("webPushOptIn state", M), M && (e.log("User opted in for web push, requesting permission"), R()), e.groupEnd();
638
+ }, [M, R, e]);
639
+ const te = {
640
+ notifications: c,
641
+ preferences: I,
642
+ userAccountMetaData: p,
643
+ webPushOptInMessage: k,
644
+ loadNotifications: T,
645
+ markAsOpened: Y,
646
+ markAsArchived: _,
647
+ markAsUnarchived: Z,
648
+ markAsClicked: X,
649
+ updateDelivery: ee,
650
+ updateDeliveries: H,
651
+ getClient: () => f,
652
+ setWebPushOptInMessage: y,
653
+ setWebPushOptIn: Q
363
654
  };
364
- return /* @__PURE__ */ Q(H.Provider, { value: z, children: e.children });
365
- }, ie = () => {
366
- const e = Y(H);
367
- if (!e)
655
+ return e.log("NotificationAPI Provider rendering", {
656
+ notificationsCount: (c == null ? void 0 : c.length) || 0,
657
+ hasPreferences: !!I,
658
+ hasUserAccountMetaData: !!p,
659
+ webPushOptInMessage: k,
660
+ webPushOptIn: M
661
+ }), /* @__PURE__ */ oe(V.Provider, { value: te, children: o.children });
662
+ }, ce = () => {
663
+ const o = ie(V);
664
+ if (!o)
368
665
  throw new Error("useMyContext must be used within a MyProvider");
369
- return e;
666
+ return o;
370
667
  };
371
- te.useNotificationAPIContext = ie;
372
- const ne = async () => {
373
- if (F && "Notification" in window && typeof Notification.requestPermission == "function")
668
+ ae.useNotificationAPIContext = ce;
669
+ const de = async () => {
670
+ if (G && "Notification" in window && typeof Notification.requestPermission == "function")
374
671
  try {
375
672
  return await Notification.requestPermission();
376
- } catch (e) {
377
- return console.error("Error requesting notification permission:", e), "default";
673
+ } catch (o) {
674
+ return console.error("Error requesting notification permission:", o), "default";
378
675
  }
379
676
  else
380
677
  return console.warn("Web Push Notifications are not supported in this browser."), "default";
381
678
  };
382
679
  export {
383
- te as NotificationAPIProvider
680
+ ae as NotificationAPIProvider
384
681
  };
package/dist/main.d.ts CHANGED
@@ -2,3 +2,4 @@
2
2
  export { NotificationFeed, NotificationPopup, NotificationLauncher, NotificationCounter } from './components/Notifications';
3
3
  export { NotificationPreferencesInline, NotificationPreferencesPopup } from './components/Preferences';
4
4
  export { NotificationAPIProvider } from './components/Provider';
5
+ export { createDebugLogger, type DebugLogger } from './utils/debug';
package/dist/main.js CHANGED
@@ -1,16 +1,18 @@
1
1
  import { NotificationFeed as r } from "./components/Notifications/NotificationFeed.js";
2
- import { NotificationPopup as e } from "./components/Notifications/NotificationPopup.js";
2
+ import { NotificationPopup as i } from "./components/Notifications/NotificationPopup.js";
3
3
  import { NotificationLauncher as n } from "./components/Notifications/NotificationLauncher.js";
4
4
  import { NotificationCounter as c } from "./components/Notifications/NotificationCounter.js";
5
- import { N } from "./assets/NotificationPreferencesPopup.js";
6
- import { NotificationPreferencesInline as x } from "./components/Preferences/NotificationPreferencesInline.js";
5
+ import { N as m } from "./assets/NotificationPreferencesPopup.js";
6
+ import { NotificationPreferencesInline as N } from "./components/Preferences/NotificationPreferencesInline.js";
7
7
  import { NotificationAPIProvider as u } from "./components/Provider/index.js";
8
+ import { createDebugLogger as s } from "./utils/debug.js";
8
9
  export {
9
10
  u as NotificationAPIProvider,
10
11
  c as NotificationCounter,
11
12
  r as NotificationFeed,
12
13
  n as NotificationLauncher,
13
- e as NotificationPopup,
14
- x as NotificationPreferencesInline,
15
- N as NotificationPreferencesPopup
14
+ i as NotificationPopup,
15
+ N as NotificationPreferencesInline,
16
+ m as NotificationPreferencesPopup,
17
+ s as createDebugLogger
16
18
  };
@@ -0,0 +1,26 @@
1
+ export interface DebugLogger {
2
+ log: (message: string, data?: unknown) => void;
3
+ warn: (message: string, data?: unknown) => void;
4
+ error: (message: string, error?: Error | unknown, context?: Record<string, unknown>) => void;
5
+ group: (label: string) => void;
6
+ groupEnd: () => void;
7
+ table: (data: Record<string, unknown> | unknown[]) => void;
8
+ }
9
+ export declare const createDebugLogger: (enabled: boolean) => DebugLogger;
10
+ export declare const formatApiCall: (method: string, endpoint: string, params?: Record<string, unknown>) => {
11
+ method: string;
12
+ endpoint: string;
13
+ params: Record<string, unknown> | undefined;
14
+ timestamp: string;
15
+ };
16
+ export declare const formatWebSocketEvent: (event: string, data?: unknown) => {
17
+ event: string;
18
+ data: unknown;
19
+ timestamp: string;
20
+ };
21
+ export declare const formatStateChange: (stateName: string, oldValue: unknown, newValue: unknown) => {
22
+ stateName: string;
23
+ oldValue: unknown;
24
+ newValue: unknown;
25
+ timestamp: string;
26
+ };
@@ -0,0 +1,61 @@
1
+ var s = Object.defineProperty;
2
+ var a = (t, o, e) => o in t ? s(t, o, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[o] = e;
3
+ var n = (t, o, e) => a(t, typeof o != "symbol" ? o + "" : o, e);
4
+ class c {
5
+ log() {
6
+ }
7
+ warn() {
8
+ }
9
+ error() {
10
+ }
11
+ group() {
12
+ }
13
+ groupEnd() {
14
+ }
15
+ table() {
16
+ }
17
+ }
18
+ class g {
19
+ constructor() {
20
+ n(this, "prefix", "[NotificationAPI Debug]");
21
+ }
22
+ log(o, e) {
23
+ console.log(`${this.prefix} ${o}`, e || "");
24
+ }
25
+ warn(o, e) {
26
+ console.warn(`${this.prefix} ${o}`, e || "");
27
+ }
28
+ error(o, e, r) {
29
+ console.group(`${this.prefix} ERROR: ${o}`), e && console.error("Error:", e), r && console.error("Context:", r), e instanceof Error && e.stack && console.error("Stack trace:", e.stack), console.groupEnd();
30
+ }
31
+ group(o) {
32
+ console.group(`${this.prefix} ${o}`);
33
+ }
34
+ groupEnd() {
35
+ console.groupEnd();
36
+ }
37
+ table(o) {
38
+ console.table(o);
39
+ }
40
+ }
41
+ const l = (t) => t ? new g() : new c(), p = (t, o, e) => ({
42
+ method: t,
43
+ endpoint: o,
44
+ params: e,
45
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
46
+ }), u = (t, o) => ({
47
+ event: t,
48
+ data: o,
49
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
50
+ }), f = (t, o, e) => ({
51
+ stateName: t,
52
+ oldValue: o,
53
+ newValue: e,
54
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
55
+ });
56
+ export {
57
+ l as createDebugLogger,
58
+ p as formatApiCall,
59
+ f as formatStateChange,
60
+ u as formatWebSocketEvent
61
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@notificationapi/react",
3
3
  "private": false,
4
- "version": "1.2.0",
4
+ "version": "1.4.0",
5
5
  "type": "module",
6
6
  "overrides": {
7
7
  "esbuild": "^0.25.0",
@@ -25,7 +25,10 @@
25
25
  "format": "prettier --write \"{src,lib}/**/*.{ts,tsx,js,jsx,json,css,md,html}\"",
26
26
  "prettier-check": "prettier --check \"{src,lib}/**/*.{ts,tsx,js,jsx,json,css,md,html}\"",
27
27
  "preview": "vite preview",
28
- "prepublishOnly": "npm run build"
28
+ "prepublishOnly": "npm run build",
29
+ "test:e2e": "playwright test",
30
+ "test:e2e:ui": "playwright test --ui",
31
+ "test:e2e:headed": "playwright test --headed"
29
32
  },
30
33
  "peerDependencies": {
31
34
  "react": "^17.0.2 || ^18.0.0 || ^19.0.0",
@@ -45,9 +48,10 @@
45
48
  "eslint-plugin-react-refresh": "^0.4.6",
46
49
  "faker-js": "^1.0.0",
47
50
  "glob": "^10.4.1",
51
+ "@playwright/test": "^1.48.0",
48
52
  "prettier": "^3.3.3",
49
53
  "typescript": "^5.2.2",
50
- "vite": "^5.4.18",
54
+ "vite": "^5.4.19",
51
55
  "vite-plugin-dts": "^3.9.1",
52
56
  "vite-plugin-lib-inject-css": "^2.1.1"
53
57
  },
@@ -63,7 +67,7 @@
63
67
  "@fontsource/roboto": "^5.1.1",
64
68
  "@mui/icons-material": "^6.3.1",
65
69
  "@mui/material": "^6.3.1",
66
- "@notificationapi/core": "^0.0.16",
70
+ "@notificationapi/core": "^0.0.17",
67
71
  "javascript-time-ago": "^2.5.10",
68
72
  "liquidjs": "^10.14.0",
69
73
  "rc-virtual-list": "^3.11.5",