@novu/js 3.17.0 → 3.18.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.
Files changed (31) hide show
  1. package/dist/cjs/{chunk-7B52C2XE.js → chunk-A6CBLMST.js} +9 -0
  2. package/dist/cjs/{chunk-SP44ETLM.js → chunk-NR4RSYUE.js} +772 -694
  3. package/dist/cjs/{chunk-WDGG3OER.js → chunk-TLQQB5Y7.js} +217 -199
  4. package/dist/{esm/inbox-service-CGCuuYnv.d.mts → cjs/inbox-service-DSSwFYNG.d.ts} +18 -2
  5. package/dist/cjs/index.d.ts +93 -4
  6. package/dist/cjs/index.js +246 -20
  7. package/dist/cjs/internal/index.d.ts +1 -1
  8. package/dist/cjs/internal/index.js +7 -7
  9. package/dist/cjs/{novu-CmNBco-0.d.ts → novu-BQCC3vQS.d.ts} +3 -2
  10. package/dist/cjs/themes/index.d.ts +3 -3
  11. package/dist/cjs/themes/index.js +1 -1
  12. package/dist/cjs/{types-BF6zvyj6.d.ts → types-Djf8MaW9.d.ts} +2 -2
  13. package/dist/cjs/ui/index.d.ts +18 -6
  14. package/dist/cjs/ui/index.js +609 -243
  15. package/dist/esm/{chunk-BKA3HRZM.mjs → chunk-33B2GJE2.mjs} +140 -64
  16. package/dist/esm/{chunk-STZMOEWR.mjs → chunk-3LR3AF54.mjs} +9 -1
  17. package/dist/esm/{chunk-4S22IB5W.mjs → chunk-T3NTOGY3.mjs} +193 -176
  18. package/dist/{cjs/inbox-service-CGCuuYnv.d.ts → esm/inbox-service-DSSwFYNG.d.mts} +18 -2
  19. package/dist/esm/index.d.mts +93 -4
  20. package/dist/esm/index.mjs +228 -3
  21. package/dist/esm/internal/index.d.mts +1 -1
  22. package/dist/esm/internal/index.mjs +2 -2
  23. package/dist/esm/{novu-CFYEiYN8.d.mts → novu-Z0z0-IxO.d.mts} +3 -2
  24. package/dist/esm/themes/index.d.mts +3 -3
  25. package/dist/esm/themes/index.mjs +1 -1
  26. package/dist/esm/{types-CJKmgwu6.d.mts → types-BJ345m1Q.d.mts} +2 -2
  27. package/dist/esm/ui/index.d.mts +18 -6
  28. package/dist/esm/ui/index.mjs +424 -58
  29. package/dist/novu.min.js +15 -15
  30. package/dist/novu.min.js.gz +0 -0
  31. package/package.json +7 -2
@@ -1,5 +1,5 @@
1
- import { NovuError, buildSubscriber, buildContextKey, Notification, read, unread, seen, archive, unarchive, deleteNotification, snooze, unsnooze, completeAction, revertAction, readAll, seenAll, archiveAll, archiveAllRead, deleteAll, buildSubscriptionIdentifier, createNotification } from './chunk-4S22IB5W.mjs';
2
- import { __privateAdd, __privateSet, __spreadValues, __privateGet, __async, __spreadProps, __objRest, __privateMethod } from './chunk-STZMOEWR.mjs';
1
+ import { NovuError, buildSubscriber, buildContextKey, Notification, read, unread, seen, archive, unarchive, deleteNotification, snooze, unsnooze, completeAction, revertAction, readAll, seenAll, archiveAll, archiveAllRead, deleteAll, buildSubscriptionIdentifier, ensureNotificationInstance } from './chunk-T3NTOGY3.mjs';
2
+ import { __privateAdd, __privateSet, __spreadValues, __privateGet, __async, __spreadProps, __objRest, __privateMethod } from './chunk-3LR3AF54.mjs';
3
3
  import mitt from 'mitt';
4
4
  import 'event-target-polyfill';
5
5
  import { WebSocket } from 'partysocket';
@@ -1110,7 +1110,7 @@ _contextKey = new WeakMap();
1110
1110
 
1111
1111
  // src/api/http-client.ts
1112
1112
  var DEFAULT_API_VERSION = "v1";
1113
- var DEFAULT_CLIENT_VERSION = `${"@novu/js"}@${"3.17.0"}`;
1113
+ var DEFAULT_CLIENT_VERSION = `${"@novu/js"}@${"3.18.0"}`;
1114
1114
  var HttpClient = class {
1115
1115
  constructor(options = {}) {
1116
1116
  // Environment variable for local development that overrides the default API endpoint without affecting the Inbox DX
@@ -1683,6 +1683,11 @@ var InboxService = class {
1683
1683
  deleteChannelEndpoint(identifier) {
1684
1684
  return __privateGet(this, _httpClient).delete(`${CHANNEL_ENDPOINTS_ROUTE}/${identifier}`);
1685
1685
  }
1686
+ linkChannelEndpoint({ integrationIdentifier }) {
1687
+ return __privateGet(this, _httpClient).post(`${CHANNEL_ENDPOINTS_ROUTE}/link`, {
1688
+ integrationIdentifier
1689
+ });
1690
+ }
1686
1691
  };
1687
1692
  _httpClient = new WeakMap();
1688
1693
 
@@ -1909,6 +1914,21 @@ var deleteChannelEndpoint = (_0) => __async(null, [_0], function* ({
1909
1914
  return { error: new NovuError("Failed to delete channel endpoint", error) };
1910
1915
  }
1911
1916
  });
1917
+ var linkChannelEndpoint = (_0) => __async(null, [_0], function* ({
1918
+ emitter,
1919
+ apiService,
1920
+ args
1921
+ }) {
1922
+ try {
1923
+ emitter.emit("channel-endpoint.link.pending", { args });
1924
+ const data = yield apiService.linkChannelEndpoint(args);
1925
+ emitter.emit("channel-endpoint.link.resolved", { args, data });
1926
+ return { data };
1927
+ } catch (error) {
1928
+ emitter.emit("channel-endpoint.link.resolved", { args, error });
1929
+ return { error: new NovuError("Failed to link channel endpoint", error) };
1930
+ }
1931
+ });
1912
1932
 
1913
1933
  // src/channel-endpoints/channel-endpoints.ts
1914
1934
  var ChannelEndpoints = class extends BaseModule {
@@ -1973,6 +1993,17 @@ var ChannelEndpoints = class extends BaseModule {
1973
1993
  );
1974
1994
  });
1975
1995
  }
1996
+ link(args) {
1997
+ return __async(this, null, function* () {
1998
+ return this.callWithSession(
1999
+ () => linkChannelEndpoint({
2000
+ emitter: this._emitter,
2001
+ apiService: this._inboxService,
2002
+ args
2003
+ })
2004
+ );
2005
+ });
2006
+ }
1976
2007
  };
1977
2008
  var _mittEmitter;
1978
2009
  var NovuEventEmitter = class {
@@ -2052,12 +2083,16 @@ var updateEvents = [
2052
2083
  "notification.read.resolved",
2053
2084
  "notification.unread.pending",
2054
2085
  "notification.unread.resolved",
2086
+ "notification.seen.pending",
2087
+ "notification.seen.resolved",
2055
2088
  "notification.complete_action.pending",
2056
2089
  "notification.complete_action.resolved",
2057
2090
  "notification.revert_action.pending",
2058
2091
  "notification.revert_action.resolved",
2059
2092
  "notifications.read_all.pending",
2060
- "notifications.read_all.resolved"
2093
+ "notifications.read_all.resolved",
2094
+ "notifications.seen_all.pending",
2095
+ "notifications.seen_all.resolved"
2061
2096
  ];
2062
2097
  var removeEvents = [
2063
2098
  "notification.archive.pending",
@@ -2069,7 +2104,7 @@ var removeEvents = [
2069
2104
  "notifications.archive_all_read.pending",
2070
2105
  "notifications.delete_all.pending"
2071
2106
  ];
2072
- var _emitter4, _inboxService4, _cache5;
2107
+ var _emitter4, _inboxService4, _cache5, _toNotificationInstance, _normalizeNotifications;
2073
2108
  var NotificationsCache = class {
2074
2109
  constructor({ emitter, inboxService }) {
2075
2110
  __privateAdd(this, _emitter4);
@@ -2078,19 +2113,36 @@ var NotificationsCache = class {
2078
2113
  * The key is the stringified notifications filter, the values are the paginated notifications.
2079
2114
  */
2080
2115
  __privateAdd(this, _cache5);
2081
- this.updateNotification = (key, data) => {
2116
+ __privateAdd(this, _toNotificationInstance, (notification) => {
2117
+ return ensureNotificationInstance({
2118
+ notification,
2119
+ emitter: __privateGet(this, _emitter4),
2120
+ inboxService: __privateGet(this, _inboxService4)
2121
+ });
2122
+ });
2123
+ __privateAdd(this, _normalizeNotifications, (notifications) => {
2124
+ return notifications.map((notification) => __privateGet(this, _toNotificationInstance).call(this, notification));
2125
+ });
2126
+ this.syncNotificationInBucket = (key, data) => {
2127
+ const notification = __privateGet(this, _toNotificationInstance).call(this, data);
2082
2128
  const notificationsResponse = __privateGet(this, _cache5).get(key);
2083
2129
  if (!notificationsResponse) {
2084
2130
  return false;
2085
2131
  }
2086
- const index = notificationsResponse.notifications.findIndex((el) => el.id === data.id);
2087
- if (index === -1) {
2088
- return false;
2132
+ const bucketFilter = getFilter(key);
2133
+ const matchesFilter = checkBasicFilters(notification, bucketFilter) && checkNotificationTagFilter(notification.tags, bucketFilter.tags);
2134
+ const index = notificationsResponse.notifications.findIndex((el) => el.id === notification.id);
2135
+ const existsInBucket = index !== -1;
2136
+ if (matchesFilter && existsInBucket) {
2137
+ const updatedNotifications = [...notificationsResponse.notifications];
2138
+ updatedNotifications[index] = notification;
2139
+ __privateGet(this, _cache5).set(key, __spreadProps(__spreadValues({}, notificationsResponse), { notifications: updatedNotifications }));
2140
+ return true;
2089
2141
  }
2090
- const updatedNotifications = [...notificationsResponse.notifications];
2091
- updatedNotifications[index] = data;
2092
- __privateGet(this, _cache5).set(key, __spreadProps(__spreadValues({}, notificationsResponse), { notifications: updatedNotifications }));
2093
- return true;
2142
+ if (!matchesFilter && existsInBucket) {
2143
+ return this.removeNotification(key, notification);
2144
+ }
2145
+ return false;
2094
2146
  };
2095
2147
  this.removeNotification = (key, data) => {
2096
2148
  const notificationsResponse = __privateGet(this, _cache5).get(key);
@@ -2113,13 +2165,13 @@ var NotificationsCache = class {
2113
2165
  let notifications = [];
2114
2166
  if (data !== void 0 && data !== null) {
2115
2167
  if (Array.isArray(data) && data.every((item) => typeof item === "object" && "id" in item)) {
2116
- notifications = data;
2168
+ notifications = __privateGet(this, _normalizeNotifications).call(this, data);
2117
2169
  } else if (typeof data === "object" && "id" in data) {
2118
- notifications = [data];
2170
+ notifications = [__privateGet(this, _toNotificationInstance).call(this, data)];
2119
2171
  }
2120
2172
  } else if (remove && args) {
2121
2173
  if ("notification" in args && args.notification) {
2122
- notifications = [args.notification];
2174
+ notifications = [__privateGet(this, _toNotificationInstance).call(this, args.notification)];
2123
2175
  } else if ("notificationId" in args && args.notificationId) {
2124
2176
  const foundNotifications = [];
2125
2177
  __privateGet(this, _cache5).keys().forEach((key) => {
@@ -2144,7 +2196,7 @@ var NotificationsCache = class {
2144
2196
  if (remove) {
2145
2197
  isNotificationFound = this.removeNotification(key, notification);
2146
2198
  } else {
2147
- isNotificationFound = this.updateNotification(key, notification);
2199
+ isNotificationFound = this.syncNotificationInBucket(key, notification);
2148
2200
  }
2149
2201
  if (isNotificationFound) {
2150
2202
  uniqueFilterKeys.add(getFilterKey(getFilter(key)));
@@ -2173,19 +2225,23 @@ var NotificationsCache = class {
2173
2225
  const parsedFilter = getFilter(key);
2174
2226
  return isSameFilter(parsedFilter, filter);
2175
2227
  });
2176
- return cacheKeys.map((key) => __privateGet(this, _cache5).get(key)).reduce(
2177
- (acc, el) => {
2178
- if (!el) {
2179
- return acc;
2180
- }
2181
- return {
2182
- hasMore: el.hasMore,
2183
- filter: el.filter,
2184
- notifications: [...acc.notifications, ...el.notifications]
2185
- };
2186
- },
2187
- { hasMore: false, filter: {}, notifications: [] }
2188
- );
2228
+ const uniqueNotifications = /* @__PURE__ */ new Map();
2229
+ let hasMore = false;
2230
+ for (const key of cacheKeys) {
2231
+ const cachedResponse = __privateGet(this, _cache5).get(key);
2232
+ if (!cachedResponse) {
2233
+ continue;
2234
+ }
2235
+ hasMore = cachedResponse.hasMore;
2236
+ for (const notification of cachedResponse.notifications) {
2237
+ uniqueNotifications.set(notification.id, notification);
2238
+ }
2239
+ }
2240
+ return {
2241
+ hasMore,
2242
+ filter,
2243
+ notifications: Array.from(uniqueNotifications.values())
2244
+ };
2189
2245
  }
2190
2246
  get(args) {
2191
2247
  return __privateGet(this, _cache5).get(getCacheKey(args));
@@ -2194,7 +2250,9 @@ var NotificationsCache = class {
2194
2250
  return __privateGet(this, _cache5).get(getCacheKey(args)) !== void 0;
2195
2251
  }
2196
2252
  set(args, data) {
2197
- __privateGet(this, _cache5).set(getCacheKey(args), data);
2253
+ __privateGet(this, _cache5).set(getCacheKey(args), __spreadProps(__spreadValues({}, data), {
2254
+ notifications: __privateGet(this, _normalizeNotifications).call(this, data.notifications)
2255
+ }));
2198
2256
  }
2199
2257
  unshift(args, notification) {
2200
2258
  const cacheKey = getCacheKey(args);
@@ -2203,13 +2261,10 @@ var NotificationsCache = class {
2203
2261
  filter: getFilter(cacheKey),
2204
2262
  notifications: []
2205
2263
  };
2206
- const notificationInstance = createNotification({
2207
- notification: __spreadValues({}, notification),
2208
- emitter: __privateGet(this, _emitter4),
2209
- inboxService: __privateGet(this, _inboxService4)
2210
- });
2264
+ const notificationInstance = __privateGet(this, _toNotificationInstance).call(this, __spreadValues({}, notification));
2265
+ const dedupedNotifications = cachedData.notifications.filter((n) => n.id !== notification.id);
2211
2266
  this.update(args, __spreadProps(__spreadValues({}, cachedData), {
2212
- notifications: [notificationInstance, ...cachedData.notifications]
2267
+ notifications: [notificationInstance, ...dedupedNotifications]
2213
2268
  }));
2214
2269
  }
2215
2270
  update(args, data) {
@@ -2274,6 +2329,8 @@ var NotificationsCache = class {
2274
2329
  _emitter4 = new WeakMap();
2275
2330
  _inboxService4 = new WeakMap();
2276
2331
  _cache5 = new WeakMap();
2332
+ _toNotificationInstance = new WeakMap();
2333
+ _normalizeNotifications = new WeakMap();
2277
2334
 
2278
2335
  // src/notifications/notifications.ts
2279
2336
  var _useCache5;
@@ -3380,6 +3437,26 @@ var Session = class {
3380
3437
  _emitter9 = new WeakMap();
3381
3438
  _inboxService5 = new WeakMap();
3382
3439
  _options = new WeakMap();
3440
+
3441
+ // src/utils/in-app-redirect-url.ts
3442
+ var IN_APP_REDIRECT_URL_REGEX = /^(?:\{\{[^}]*\}\}.*|(?!mailto:)(?:https?:\/\/[^\s/$.?#][^\s{}]*(?:\{\{[^}]*\}\}[^\s{}]*)*)|\/(?!\/)[^\s{}]*(?:\{\{[^}]*\}\}[^\s{}]*)*)$/;
3443
+ var IN_APP_REDIRECT_TARGETS = ["_self", "_blank", "_parent", "_top", "_unfencedTop"];
3444
+ function isValidInAppRedirectUrl(url) {
3445
+ return IN_APP_REDIRECT_URL_REGEX.test(url);
3446
+ }
3447
+ function isValidInAppRedirectTarget(target) {
3448
+ return typeof target === "string" && IN_APP_REDIRECT_TARGETS.includes(target);
3449
+ }
3450
+ function sanitizeInAppRedirect(url, target) {
3451
+ if (!url || !isValidInAppRedirectUrl(url)) {
3452
+ return void 0;
3453
+ }
3454
+ return __spreadValues({
3455
+ url
3456
+ }, isValidInAppRedirectTarget(target) ? { target } : {});
3457
+ }
3458
+
3459
+ // src/ws/party-socket.ts
3383
3460
  var PRODUCTION_SOCKET_URL = "wss://socket.novu.co";
3384
3461
  var HIBERNATION_HEARTBEAT_MS = 25e3;
3385
3462
  var HIBERNATION_PING_PAYLOAD = "ping";
@@ -3409,7 +3486,7 @@ var mapToNotification = ({
3409
3486
  workflow,
3410
3487
  severity
3411
3488
  }) => {
3412
- var _a, _b, _c, _d, _e, _f, _g, _h;
3489
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3413
3490
  const to = {
3414
3491
  id: subscriber == null ? void 0 : subscriber._id,
3415
3492
  subscriberId: subscriber == null ? void 0 : subscriber.subscriberId,
@@ -3449,25 +3526,16 @@ var mapToNotification = ({
3449
3526
  primaryAction: primaryCta && {
3450
3527
  label: primaryCta.content,
3451
3528
  isCompleted: actionType === "primary" /* PRIMARY */ && actionStatus === "done" /* DONE */,
3452
- redirect: primaryCta.url ? {
3453
- target: primaryCta.target,
3454
- url: primaryCta.url
3455
- } : void 0
3529
+ redirect: sanitizeInAppRedirect(primaryCta.url, primaryCta.target)
3456
3530
  },
3457
3531
  secondaryAction: secondaryCta && {
3458
3532
  label: secondaryCta.content,
3459
3533
  isCompleted: actionType === "secondary" /* SECONDARY */ && actionStatus === "done" /* DONE */,
3460
- redirect: secondaryCta.url ? {
3461
- target: secondaryCta.target,
3462
- url: secondaryCta.url
3463
- } : void 0
3534
+ redirect: sanitizeInAppRedirect(secondaryCta.url, secondaryCta.target)
3464
3535
  },
3465
3536
  channelType: channel,
3466
3537
  tags,
3467
- redirect: ((_h = cta.data) == null ? void 0 : _h.url) ? {
3468
- url: cta.data.url,
3469
- target: cta.data.target
3470
- } : void 0,
3538
+ redirect: sanitizeInAppRedirect((_h = cta.data) == null ? void 0 : _h.url, (_i = cta.data) == null ? void 0 : _i.target),
3471
3539
  data,
3472
3540
  workflow,
3473
3541
  severity
@@ -3682,7 +3750,7 @@ var mapToNotification2 = ({
3682
3750
  workflow,
3683
3751
  severity
3684
3752
  }) => {
3685
- var _a, _b, _c, _d, _e, _f, _g, _h;
3753
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3686
3754
  const to = {
3687
3755
  id: subscriber == null ? void 0 : subscriber._id,
3688
3756
  subscriberId: subscriber == null ? void 0 : subscriber.subscriberId,
@@ -3722,25 +3790,16 @@ var mapToNotification2 = ({
3722
3790
  primaryAction: primaryCta && {
3723
3791
  label: primaryCta.content,
3724
3792
  isCompleted: actionType === "primary" /* PRIMARY */ && actionStatus === "done" /* DONE */,
3725
- redirect: primaryCta.url ? {
3726
- target: primaryCta.target,
3727
- url: primaryCta.url
3728
- } : void 0
3793
+ redirect: sanitizeInAppRedirect(primaryCta.url, primaryCta.target)
3729
3794
  },
3730
3795
  secondaryAction: secondaryCta && {
3731
3796
  label: secondaryCta.content,
3732
3797
  isCompleted: actionType === "secondary" /* SECONDARY */ && actionStatus === "done" /* DONE */,
3733
- redirect: secondaryCta.url ? {
3734
- target: secondaryCta.target,
3735
- url: secondaryCta.url
3736
- } : void 0
3798
+ redirect: sanitizeInAppRedirect(secondaryCta.url, secondaryCta.target)
3737
3799
  },
3738
3800
  channelType: channel,
3739
3801
  tags,
3740
- redirect: ((_h = cta.data) == null ? void 0 : _h.url) ? {
3741
- url: cta.data.url,
3742
- target: cta.data.target
3743
- } : void 0,
3802
+ redirect: sanitizeInAppRedirect((_h = cta.data) == null ? void 0 : _h.url, (_i = cta.data) == null ? void 0 : _i.target),
3744
3803
  data,
3745
3804
  workflow,
3746
3805
  severity
@@ -4065,4 +4124,21 @@ _session = new WeakMap();
4065
4124
  _inboxService6 = new WeakMap();
4066
4125
  _options2 = new WeakMap();
4067
4126
 
4068
- export { DEFAULT_API_VERSION, Novu, SubscriptionPreference, TopicSubscription, areSeveritiesEqual, areTagsEqual, checkNotificationDataFilter, checkNotificationMatchesFilter, checkNotificationTagFilter, isBrowser, isSameFilter, normalizeTagGroups };
4127
+ // src/notifications/count-sync-events.ts
4128
+ var NOTIFICATION_COUNT_SYNC_EVENTS = [
4129
+ "notification.read.resolved",
4130
+ "notification.unread.resolved",
4131
+ "notification.seen.resolved",
4132
+ "notification.archive.resolved",
4133
+ "notification.unarchive.resolved",
4134
+ "notification.snooze.resolved",
4135
+ "notification.unsnooze.resolved",
4136
+ "notification.delete.resolved",
4137
+ "notifications.read_all.resolved",
4138
+ "notifications.seen_all.resolved",
4139
+ "notifications.archive_all.resolved",
4140
+ "notifications.archive_all_read.resolved",
4141
+ "notifications.delete_all.resolved"
4142
+ ];
4143
+
4144
+ export { DEFAULT_API_VERSION, NOTIFICATION_COUNT_SYNC_EVENTS, Novu, SubscriptionPreference, TopicSubscription, areSeveritiesEqual, areTagsEqual, checkNotificationDataFilter, checkNotificationMatchesFilter, isBrowser, isSameFilter, isValidInAppRedirectTarget, isValidInAppRedirectUrl, normalizeTagGroups };
@@ -37,6 +37,14 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
37
37
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
38
38
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
39
39
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
40
+ var __privateWrapper = (obj, member, setter, getter) => ({
41
+ set _(value) {
42
+ __privateSet(obj, member, value, setter);
43
+ },
44
+ get _() {
45
+ return __privateGet(obj, member, getter);
46
+ }
47
+ });
40
48
  var __async = (__this, __arguments, generator) => {
41
49
  return new Promise((resolve, reject) => {
42
50
  var fulfilled = (value) => {
@@ -58,4 +66,4 @@ var __async = (__this, __arguments, generator) => {
58
66
  });
59
67
  };
60
68
 
61
- export { __async, __objRest, __privateAdd, __privateGet, __privateMethod, __privateSet, __spreadProps, __spreadValues };
69
+ export { __async, __objRest, __privateAdd, __privateGet, __privateMethod, __privateSet, __privateWrapper, __spreadProps, __spreadValues };