@rivium/push-web 0.1.5 → 0.1.7
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 +69 -0
- package/dist/in-app.d.ts +262 -0
- package/dist/inbox.d.ts +180 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -267,6 +267,75 @@ await riviumPush.unregister();
|
|
|
267
267
|
</html>
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
## Message Inbox
|
|
271
|
+
|
|
272
|
+
Inbox messages are stored server-side and stay available until the user reads,
|
|
273
|
+
archives or deletes them. `riviumPush.inbox` needs a registered device.
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// Live updates (an inbox message never shows a notification)
|
|
277
|
+
riviumPush.inbox.onMessage((message) => console.log(message.content.title));
|
|
278
|
+
riviumPush.inbox.onUnreadCountChange((count) => setBadge(count));
|
|
279
|
+
|
|
280
|
+
// Read
|
|
281
|
+
const { messages, total, unreadCount } = await riviumPush.inbox.getMessages({
|
|
282
|
+
status: 'unread',
|
|
283
|
+
limit: 20,
|
|
284
|
+
});
|
|
285
|
+
const cached = riviumPush.inbox.getCachedMessages(); // instant, no network
|
|
286
|
+
|
|
287
|
+
// Write
|
|
288
|
+
await riviumPush.inbox.markAsRead(messages[0].id);
|
|
289
|
+
await riviumPush.inbox.archiveMessage(messages[0].id);
|
|
290
|
+
await riviumPush.inbox.deleteMessage(messages[0].id);
|
|
291
|
+
await riviumPush.inbox.markMultiple(['id-1', 'id-2'], 'read');
|
|
292
|
+
await riviumPush.inbox.markAllAsRead();
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Messages are cached per device and restored on the next page load. The cache is
|
|
296
|
+
dropped when the user changes (`setUserId` / `clearUserId`).
|
|
297
|
+
|
|
298
|
+
## In-App Messages
|
|
299
|
+
|
|
300
|
+
In-app messages are campaigns shown inside your page — a modal, banner,
|
|
301
|
+
fullscreen takeover or card — when a trigger fires. `riviumPush.inApp` needs a
|
|
302
|
+
registered device.
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
const riviumPush = new RiviumPush({
|
|
306
|
+
apiKey: 'rv_live_your_api_key',
|
|
307
|
+
inApp: {
|
|
308
|
+
display: 'auto', // 'manual' to render your own UI
|
|
309
|
+
autoTrigger: false, // true fires session-start + app-open on page load
|
|
310
|
+
bannerPosition: 'top',
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
riviumPush.inApp.onMessageReady((message) => console.log(message.name));
|
|
315
|
+
riviumPush.inApp.onButtonClicked((message, button) => {
|
|
316
|
+
if (button.action === 'custom') doSomething(button.value);
|
|
317
|
+
});
|
|
318
|
+
riviumPush.inApp.onDismissed((message) => console.log('closed', message.id));
|
|
319
|
+
|
|
320
|
+
await riviumPush.inApp.triggerOnAppOpen();
|
|
321
|
+
await riviumPush.inApp.triggerEvent('purchase_completed', { plan: 'pro' });
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
The built-in UI renders into a **shadow DOM** root, so your page's CSS can never
|
|
325
|
+
break it and the SDK's CSS never leaks into your page. Modals and fullscreen
|
|
326
|
+
messages are dialogs (`role="dialog"`, `aria-modal`, focus trap, focus restored
|
|
327
|
+
on close, dismissible with Escape or a backdrop click); banners and cards are
|
|
328
|
+
polite live regions. Reduced-motion preferences are respected.
|
|
329
|
+
|
|
330
|
+
With `display: 'manual'` nothing is inserted into the page: you get
|
|
331
|
+
`onMessageReady` and render the message yourself, then call
|
|
332
|
+
`riviumPush.inApp.recordImpression(id, 'button_click', buttonId)` and
|
|
333
|
+
`riviumPush.inApp.dismissCurrentMessage()` as the user interacts.
|
|
334
|
+
|
|
335
|
+
Eligible messages are cached per device for 5 minutes, and impression counts,
|
|
336
|
+
schedules and `minSessionCount` are enforced locally as well as on the server.
|
|
337
|
+
The cache is dropped when the user changes (`setUserId` / `clearUserId`).
|
|
338
|
+
|
|
270
339
|
## Delivery Tracking
|
|
271
340
|
|
|
272
341
|
Notifications are confirmed as `delivered` automatically: Web Push arrivals by
|
package/dist/in-app.d.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-App Messages for the RiviumPush Web SDK.
|
|
3
|
+
*
|
|
4
|
+
* An in-app message is a campaign the server keeps for a device and the SDK
|
|
5
|
+
* shows inside the page — a modal, a banner, a fullscreen takeover or a card —
|
|
6
|
+
* when a trigger fires (app open, session start or a custom event).
|
|
7
|
+
*
|
|
8
|
+
* Reachable as `push.inApp` once the SDK is constructed; network calls need
|
|
9
|
+
* a registered device (`register()`).
|
|
10
|
+
*
|
|
11
|
+
* The built-in UI renders into a shadow DOM root, so the host page's CSS can
|
|
12
|
+
* never break it and the SDK's CSS never leaks into the page. Apps that want
|
|
13
|
+
* to render their own UI set `display: 'manual'` and use `onMessageReady`.
|
|
14
|
+
*
|
|
15
|
+
* @packageDocumentation
|
|
16
|
+
*/
|
|
17
|
+
/** How a message is presented. */
|
|
18
|
+
export type InAppMessageType = 'modal' | 'banner' | 'fullscreen' | 'card';
|
|
19
|
+
/** What makes a message eligible to show. */
|
|
20
|
+
export type InAppTriggerType = 'on_app_open' | 'on_event' | 'on_session_start' | 'scheduled' | 'manual';
|
|
21
|
+
/** What a button does when clicked. */
|
|
22
|
+
export type InAppButtonAction = 'dismiss' | 'deep_link' | 'url' | 'custom';
|
|
23
|
+
/** Visual weight of a button. */
|
|
24
|
+
export type InAppButtonStyle = 'primary' | 'secondary' | 'text' | 'destructive';
|
|
25
|
+
/** Interaction reported to the server. */
|
|
26
|
+
export type InAppImpressionAction = 'impression' | 'click' | 'dismiss' | 'button_click';
|
|
27
|
+
/** Where a banner is anchored. */
|
|
28
|
+
export type InAppBannerPosition = 'top' | 'bottom';
|
|
29
|
+
/** An action button on an in-app message. */
|
|
30
|
+
export interface InAppButton {
|
|
31
|
+
/** Button id, reported with the click */
|
|
32
|
+
id: string;
|
|
33
|
+
/** Button label */
|
|
34
|
+
text: string;
|
|
35
|
+
/** What the button does */
|
|
36
|
+
action: InAppButtonAction;
|
|
37
|
+
/** URL or deep link for the `url` / `deep_link` actions */
|
|
38
|
+
value?: string;
|
|
39
|
+
/** Visual style (default: `primary`) */
|
|
40
|
+
style?: InAppButtonStyle;
|
|
41
|
+
}
|
|
42
|
+
/** Content of an in-app message, in one locale. */
|
|
43
|
+
export interface InAppMessageContent {
|
|
44
|
+
/** Message title */
|
|
45
|
+
title: string;
|
|
46
|
+
/** Message body */
|
|
47
|
+
body: string;
|
|
48
|
+
/** Large image URL */
|
|
49
|
+
imageUrl?: string;
|
|
50
|
+
/** Background colour, e.g. "#FFFFFF" */
|
|
51
|
+
backgroundColor?: string;
|
|
52
|
+
/** Text colour, e.g. "#111111" */
|
|
53
|
+
textColor?: string;
|
|
54
|
+
/** Action buttons */
|
|
55
|
+
buttons?: InAppButton[];
|
|
56
|
+
/** Banner anchor; falls back to the `inApp.bannerPosition` config */
|
|
57
|
+
position?: InAppBannerPosition;
|
|
58
|
+
}
|
|
59
|
+
/** Content for one locale. */
|
|
60
|
+
export interface InAppLocalization {
|
|
61
|
+
/** Locale tag, e.g. "fr" or "fr-CA" */
|
|
62
|
+
locale: string;
|
|
63
|
+
/** Content for that locale */
|
|
64
|
+
content: InAppMessageContent;
|
|
65
|
+
}
|
|
66
|
+
/** A single in-app message campaign. */
|
|
67
|
+
export interface InAppMessage {
|
|
68
|
+
/** Server-side message id */
|
|
69
|
+
id: string;
|
|
70
|
+
/** Internal campaign name */
|
|
71
|
+
name: string;
|
|
72
|
+
/** How the message is presented */
|
|
73
|
+
type: InAppMessageType;
|
|
74
|
+
/** Default content */
|
|
75
|
+
content: InAppMessageContent;
|
|
76
|
+
/** Per-locale content, when configured */
|
|
77
|
+
localizations?: InAppLocalization[];
|
|
78
|
+
/** What makes the message eligible */
|
|
79
|
+
triggerType: InAppTriggerType;
|
|
80
|
+
/** Event name for the `on_event` trigger */
|
|
81
|
+
triggerEvent?: string | null;
|
|
82
|
+
/** Extra trigger conditions */
|
|
83
|
+
triggerConditions?: Record<string, any> | null;
|
|
84
|
+
/** ISO date before which the message is not shown */
|
|
85
|
+
startDate?: string | null;
|
|
86
|
+
/** ISO date after which the message is not shown */
|
|
87
|
+
endDate?: string | null;
|
|
88
|
+
/** How many times this device may see the message */
|
|
89
|
+
maxImpressions: number;
|
|
90
|
+
/** Sessions required before the message may show */
|
|
91
|
+
minSessionCount: number;
|
|
92
|
+
/** Delay between the trigger and the display */
|
|
93
|
+
delaySeconds: number;
|
|
94
|
+
/** Higher priority wins when several messages qualify */
|
|
95
|
+
priority: number;
|
|
96
|
+
}
|
|
97
|
+
/** Options for {@link InAppMessages.fetchMessages}. */
|
|
98
|
+
export interface InAppFilter {
|
|
99
|
+
/** Only messages with this trigger */
|
|
100
|
+
trigger?: InAppTriggerType;
|
|
101
|
+
/** Only messages bound to this event name */
|
|
102
|
+
event?: string;
|
|
103
|
+
/** Preferred locale for localized content, e.g. "fr" */
|
|
104
|
+
locale?: string;
|
|
105
|
+
}
|
|
106
|
+
/** Configuration for the in-app module (`RiviumPushConfig.inApp`). */
|
|
107
|
+
export interface InAppConfig {
|
|
108
|
+
/** Turn in-app messages off entirely (default: true) */
|
|
109
|
+
enabled?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* `auto` renders the built-in shadow-DOM UI (default).
|
|
112
|
+
* `manual` renders nothing and only fires `onMessageReady`, so the app can
|
|
113
|
+
* draw its own UI. It still reports the impression.
|
|
114
|
+
*/
|
|
115
|
+
display?: 'auto' | 'manual';
|
|
116
|
+
/**
|
|
117
|
+
* Fire `on_session_start` and `on_app_open` automatically on page load
|
|
118
|
+
* (default: false — call `triggerOnAppOpen()` when your app is ready).
|
|
119
|
+
*/
|
|
120
|
+
autoTrigger?: boolean;
|
|
121
|
+
/** Where banners are anchored when the content does not say (default: top) */
|
|
122
|
+
bannerPosition?: InAppBannerPosition;
|
|
123
|
+
/** Locale used to pick localized content (default: the browser locale) */
|
|
124
|
+
locale?: string;
|
|
125
|
+
}
|
|
126
|
+
/** Called when a message is ready to be displayed. */
|
|
127
|
+
export type OnInAppMessageReadyCallback = (message: InAppMessage) => void;
|
|
128
|
+
/** Called when a button on a message is clicked. */
|
|
129
|
+
export type OnInAppButtonClickedCallback = (message: InAppMessage, button: InAppButton) => void;
|
|
130
|
+
/** Called when a message is dismissed. */
|
|
131
|
+
export type OnInAppDismissedCallback = (message: InAppMessage) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Wiring the SDK passes to the in-app module. Not part of the public API.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
export interface InAppDependencies {
|
|
137
|
+
serverUrl: string;
|
|
138
|
+
getApiKey: () => string;
|
|
139
|
+
getDeviceId: () => string | null;
|
|
140
|
+
getUserId: () => string | null;
|
|
141
|
+
log: (level: number, message: string, ...args: any[]) => void;
|
|
142
|
+
config?: InAppConfig;
|
|
143
|
+
}
|
|
144
|
+
/** Inputs the eligibility rules are evaluated against. */
|
|
145
|
+
export interface InAppEligibilityContext {
|
|
146
|
+
/** Trigger being evaluated */
|
|
147
|
+
trigger: InAppTriggerType;
|
|
148
|
+
/** Event name, for the `on_event` trigger */
|
|
149
|
+
event?: string;
|
|
150
|
+
/** Sessions this device has started */
|
|
151
|
+
sessionCount: number;
|
|
152
|
+
/** Impressions this device already had, per message id */
|
|
153
|
+
impressions: Record<string, number>;
|
|
154
|
+
/** Evaluation time in epoch milliseconds */
|
|
155
|
+
now: number;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Whether a message may be shown for this trigger. Pure, so the frequency and
|
|
159
|
+
* schedule rules can be reasoned about (and tested) on their own.
|
|
160
|
+
*/
|
|
161
|
+
export declare function isInAppMessageEligible(message: InAppMessage, context: InAppEligibilityContext): boolean;
|
|
162
|
+
/** Eligible messages for a trigger, highest priority first. */
|
|
163
|
+
export declare function selectInAppMessages(messages: InAppMessage[], context: InAppEligibilityContext): InAppMessage[];
|
|
164
|
+
/**
|
|
165
|
+
* In-App Messages client.
|
|
166
|
+
*
|
|
167
|
+
* ```typescript
|
|
168
|
+
* push.inApp.onButtonClicked((message, button) => console.log(button.id));
|
|
169
|
+
* await push.inApp.triggerOnAppOpen();
|
|
170
|
+
* await push.inApp.triggerEvent('purchase_completed');
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export declare class InAppMessages {
|
|
174
|
+
private readonly deps;
|
|
175
|
+
private cachedMessages;
|
|
176
|
+
private impressions;
|
|
177
|
+
private sessionCount;
|
|
178
|
+
private lastFetch;
|
|
179
|
+
/** Device the in-memory cache was loaded for, so identity changes reload. */
|
|
180
|
+
private loadedKey;
|
|
181
|
+
private onMessageReadyCallback;
|
|
182
|
+
private onButtonClickedCallback;
|
|
183
|
+
private onDismissedCallback;
|
|
184
|
+
private presentation;
|
|
185
|
+
private showing;
|
|
186
|
+
private pendingTimer;
|
|
187
|
+
/** @internal */
|
|
188
|
+
constructor(deps: InAppDependencies);
|
|
189
|
+
/**
|
|
190
|
+
* Listen for a message becoming ready to display. Fires for the built-in UI
|
|
191
|
+
* too; with `display: 'manual'` it is the only signal you get.
|
|
192
|
+
* Returns a function that removes the listener.
|
|
193
|
+
*/
|
|
194
|
+
onMessageReady(callback: OnInAppMessageReadyCallback): () => void;
|
|
195
|
+
/**
|
|
196
|
+
* Listen for button clicks. `custom` buttons do nothing on their own —
|
|
197
|
+
* handle them here.
|
|
198
|
+
* Returns a function that removes the listener.
|
|
199
|
+
*/
|
|
200
|
+
onButtonClicked(callback: OnInAppButtonClickedCallback): () => void;
|
|
201
|
+
/**
|
|
202
|
+
* Listen for a message being dismissed (close button, backdrop, Escape or
|
|
203
|
+
* a `dismiss` button).
|
|
204
|
+
* Returns a function that removes the listener.
|
|
205
|
+
*/
|
|
206
|
+
onDismissed(callback: OnInAppDismissedCallback): () => void;
|
|
207
|
+
/**
|
|
208
|
+
* Fetch the messages this device is eligible for and cache them. Messages
|
|
209
|
+
* are filtered again locally before anything is shown.
|
|
210
|
+
*/
|
|
211
|
+
fetchMessages(filter?: InAppFilter): Promise<InAppMessage[]>;
|
|
212
|
+
/** Messages cached locally — available immediately, no network call. */
|
|
213
|
+
getCachedMessages(): InAppMessage[];
|
|
214
|
+
/** Sessions this device has started. */
|
|
215
|
+
getSessionCount(): number;
|
|
216
|
+
/** Evaluate `on_app_open` messages and show the best match. */
|
|
217
|
+
triggerOnAppOpen(): Promise<void>;
|
|
218
|
+
/**
|
|
219
|
+
* Evaluate `on_event` messages bound to `name`. `properties` are matched
|
|
220
|
+
* against a message's `triggerConditions` when both are present.
|
|
221
|
+
*/
|
|
222
|
+
triggerEvent(name: string, properties?: Record<string, any>): Promise<void>;
|
|
223
|
+
/** Count a new session and evaluate `on_session_start` messages. */
|
|
224
|
+
triggerSessionStart(): Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Start a session on page load: counts the session and, when
|
|
227
|
+
* `inApp.autoTrigger` is on, fires `on_session_start` then `on_app_open`.
|
|
228
|
+
* @internal
|
|
229
|
+
*/
|
|
230
|
+
startSession(): void;
|
|
231
|
+
/** Show a cached message by id, ignoring its trigger. */
|
|
232
|
+
showMessage(messageId: string): Promise<void>;
|
|
233
|
+
/** Close the message currently on screen, if any. */
|
|
234
|
+
dismissCurrentMessage(): void;
|
|
235
|
+
/**
|
|
236
|
+
* Report an interaction. Called for you by the built-in UI; call it yourself
|
|
237
|
+
* when you render messages with `display: 'manual'`. Never throws.
|
|
238
|
+
*/
|
|
239
|
+
recordImpression(messageId: string, action: InAppImpressionAction, buttonId?: string): Promise<void>;
|
|
240
|
+
/** Drop cached messages, impression counts and the session count. */
|
|
241
|
+
clearCache(): void;
|
|
242
|
+
/**
|
|
243
|
+
* Point the module at a new identity. Campaign eligibility and impression
|
|
244
|
+
* counts belong to the previous user, so they are dropped.
|
|
245
|
+
* @internal
|
|
246
|
+
*/
|
|
247
|
+
onIdentityChanged(): void;
|
|
248
|
+
private trigger;
|
|
249
|
+
/** Shows a message: reports the impression once, then renders or delegates. */
|
|
250
|
+
private present;
|
|
251
|
+
private handleButtonClick;
|
|
252
|
+
/** Tears the UI down once, reports the dismissal once. */
|
|
253
|
+
private finishPresentation;
|
|
254
|
+
private incrementSessionCount;
|
|
255
|
+
private locale;
|
|
256
|
+
private storageKey;
|
|
257
|
+
/** Restores the persisted state the first time it is needed per device. */
|
|
258
|
+
private ensureLoaded;
|
|
259
|
+
private persist;
|
|
260
|
+
}
|
|
261
|
+
/** Exact locale match first, then the language part, then the default content. */
|
|
262
|
+
export declare function localizedContent(message: InAppMessage, locale: string): InAppMessageContent;
|
package/dist/inbox.d.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Inbox for the RiviumPush Web SDK.
|
|
3
|
+
*
|
|
4
|
+
* An inbox message is a message that is stored server-side and stays
|
|
5
|
+
* available to the app until the user reads, archives or deletes it —
|
|
6
|
+
* independent of whether a notification was ever displayed.
|
|
7
|
+
*
|
|
8
|
+
* Reachable as `push.inbox` once the SDK is constructed; network calls need
|
|
9
|
+
* a registered device (`register()`).
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
/** Status of an inbox message. */
|
|
14
|
+
export type InboxMessageStatus = 'unread' | 'read' | 'archived' | 'deleted';
|
|
15
|
+
/** Content of an inbox message. */
|
|
16
|
+
export interface InboxContent {
|
|
17
|
+
/** Message title */
|
|
18
|
+
title: string;
|
|
19
|
+
/** Message body */
|
|
20
|
+
body: string;
|
|
21
|
+
/** Large image URL */
|
|
22
|
+
imageUrl?: string;
|
|
23
|
+
/** Icon/avatar URL */
|
|
24
|
+
iconUrl?: string;
|
|
25
|
+
/** Deep link URL */
|
|
26
|
+
deepLink?: string;
|
|
27
|
+
/** Custom data payload */
|
|
28
|
+
data?: Record<string, any>;
|
|
29
|
+
}
|
|
30
|
+
/** A single inbox message. */
|
|
31
|
+
export interface InboxMessage {
|
|
32
|
+
/** Server-side message id */
|
|
33
|
+
id: string;
|
|
34
|
+
/** User this message belongs to, when addressed by user */
|
|
35
|
+
userId?: string | null;
|
|
36
|
+
/** Device this message belongs to, when addressed by device */
|
|
37
|
+
deviceId?: string | null;
|
|
38
|
+
/** Message content */
|
|
39
|
+
content: InboxContent;
|
|
40
|
+
/** Current status (defaults to `unread`) */
|
|
41
|
+
status: InboxMessageStatus;
|
|
42
|
+
/** Optional category, e.g. "promotions" */
|
|
43
|
+
category?: string | null;
|
|
44
|
+
/** ISO date after which the message is no longer returned */
|
|
45
|
+
expiresAt?: string | null;
|
|
46
|
+
/** ISO date the message was marked read */
|
|
47
|
+
readAt?: string | null;
|
|
48
|
+
/** ISO date the message was created */
|
|
49
|
+
createdAt: string;
|
|
50
|
+
/** ISO date the message was last updated */
|
|
51
|
+
updatedAt?: string | null;
|
|
52
|
+
}
|
|
53
|
+
/** Filter options for {@link RiviumInbox.getMessages}. */
|
|
54
|
+
export interface InboxFilter {
|
|
55
|
+
/** Only messages with this status */
|
|
56
|
+
status?: InboxMessageStatus;
|
|
57
|
+
/** Only messages in this category */
|
|
58
|
+
category?: string;
|
|
59
|
+
/** Page size (default: 50) */
|
|
60
|
+
limit?: number;
|
|
61
|
+
/** Page offset (default: 0) */
|
|
62
|
+
offset?: number;
|
|
63
|
+
/** Preferred locale for localized content, e.g. "fr" */
|
|
64
|
+
locale?: string;
|
|
65
|
+
}
|
|
66
|
+
/** Response of {@link RiviumInbox.getMessages}. */
|
|
67
|
+
export interface InboxMessagesResponse {
|
|
68
|
+
/** The messages for this page */
|
|
69
|
+
messages: InboxMessage[];
|
|
70
|
+
/** Total number of messages matching the filter */
|
|
71
|
+
total: number;
|
|
72
|
+
/** Number of unread messages */
|
|
73
|
+
unreadCount: number;
|
|
74
|
+
}
|
|
75
|
+
/** Called when a new inbox message arrives in real time. */
|
|
76
|
+
export type OnInboxMessageCallback = (message: InboxMessage) => void;
|
|
77
|
+
/** Called when the status of a message changes. */
|
|
78
|
+
export type OnInboxStatusChangeCallback = (messageId: string, status: InboxMessageStatus) => void;
|
|
79
|
+
/** Called whenever the unread count changes. */
|
|
80
|
+
export type OnInboxUnreadCountCallback = (count: number) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Wiring the SDK passes to the inbox. Not part of the public API.
|
|
83
|
+
* @internal
|
|
84
|
+
*/
|
|
85
|
+
export interface InboxDependencies {
|
|
86
|
+
serverUrl: string;
|
|
87
|
+
getApiKey: () => string;
|
|
88
|
+
getDeviceId: () => string | null;
|
|
89
|
+
getUserId: () => string | null;
|
|
90
|
+
log: (level: number, message: string, ...args: any[]) => void;
|
|
91
|
+
createError: (kind: 'network' | 'server' | 'notRegistered', details: string) => Error;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Message Inbox client.
|
|
95
|
+
*
|
|
96
|
+
* ```typescript
|
|
97
|
+
* push.inbox.onMessage((message) => render(message));
|
|
98
|
+
* const { messages, unreadCount } = await push.inbox.getMessages({ status: 'unread' });
|
|
99
|
+
* await push.inbox.markAsRead(messages[0].id);
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare class RiviumInbox {
|
|
103
|
+
private readonly deps;
|
|
104
|
+
private cachedMessages;
|
|
105
|
+
private unreadCount;
|
|
106
|
+
/** Device the in-memory cache was loaded for, so identity changes reload. */
|
|
107
|
+
private loadedKey;
|
|
108
|
+
private onMessageCallback;
|
|
109
|
+
private onStatusChangeCallback;
|
|
110
|
+
private onUnreadCountCallback;
|
|
111
|
+
/** Real-time updates can arrive twice (socket + service worker). */
|
|
112
|
+
private handledIncomingIds;
|
|
113
|
+
/** @internal */
|
|
114
|
+
constructor(deps: InboxDependencies);
|
|
115
|
+
/**
|
|
116
|
+
* Listen for inbox messages arriving in real time.
|
|
117
|
+
* Returns a function that removes the listener.
|
|
118
|
+
*/
|
|
119
|
+
onMessage(callback: OnInboxMessageCallback): () => void;
|
|
120
|
+
/**
|
|
121
|
+
* Listen for status changes (read, archived, deleted).
|
|
122
|
+
* Returns a function that removes the listener.
|
|
123
|
+
*/
|
|
124
|
+
onStatusChange(callback: OnInboxStatusChangeCallback): () => void;
|
|
125
|
+
/**
|
|
126
|
+
* Listen for unread-count changes — useful to drive a badge.
|
|
127
|
+
* Returns a function that removes the listener.
|
|
128
|
+
*/
|
|
129
|
+
onUnreadCountChange(callback: OnInboxUnreadCountCallback): () => void;
|
|
130
|
+
/**
|
|
131
|
+
* Fetch inbox messages from the server. Messages are addressed by userId
|
|
132
|
+
* when one is set, otherwise by deviceId. The result is cached locally.
|
|
133
|
+
*/
|
|
134
|
+
getMessages(filter?: InboxFilter): Promise<InboxMessagesResponse>;
|
|
135
|
+
/** Fetch a single message by id. */
|
|
136
|
+
getMessage(messageId: string): Promise<InboxMessage>;
|
|
137
|
+
/** Messages cached locally — available immediately, no network call. */
|
|
138
|
+
getCachedMessages(): InboxMessage[];
|
|
139
|
+
/** The last known unread count, without a network call. */
|
|
140
|
+
getUnreadCount(): number;
|
|
141
|
+
/** Ask the server for the current unread count. */
|
|
142
|
+
fetchUnreadCount(): Promise<number>;
|
|
143
|
+
/** Mark a message as read. */
|
|
144
|
+
markAsRead(messageId: string): Promise<void>;
|
|
145
|
+
/** Archive a message. */
|
|
146
|
+
archiveMessage(messageId: string): Promise<void>;
|
|
147
|
+
/** Delete a message. */
|
|
148
|
+
deleteMessage(messageId: string): Promise<void>;
|
|
149
|
+
/** Apply a status to several messages at once. */
|
|
150
|
+
markMultiple(messageIds: string[], status: InboxMessageStatus): Promise<void>;
|
|
151
|
+
/** Mark every message in this inbox as read. */
|
|
152
|
+
markAllAsRead(): Promise<void>;
|
|
153
|
+
/** Drop the local cache (in memory and in storage). */
|
|
154
|
+
clearCache(): void;
|
|
155
|
+
/**
|
|
156
|
+
* Add a message that arrived in real time to the cache and notify listeners.
|
|
157
|
+
* Called by the SDK for `inbox_update` payloads; safe to call directly.
|
|
158
|
+
*/
|
|
159
|
+
handleIncomingMessage(message: InboxMessage): void;
|
|
160
|
+
/**
|
|
161
|
+
* Turn a raw `inbox_update` payload into an InboxMessage and handle it.
|
|
162
|
+
* @internal
|
|
163
|
+
*/
|
|
164
|
+
handleIncomingPayload(payload: Record<string, any>): void;
|
|
165
|
+
/**
|
|
166
|
+
* Point the inbox at a new identity. The cache belongs to the previous
|
|
167
|
+
* user, so it is dropped and listeners see an unread count of 0.
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
170
|
+
onIdentityChanged(): void;
|
|
171
|
+
private updateStatus;
|
|
172
|
+
/** Messages are addressed by user when one is known, by device otherwise. */
|
|
173
|
+
private identity;
|
|
174
|
+
private request;
|
|
175
|
+
private setUnreadCount;
|
|
176
|
+
private storageKey;
|
|
177
|
+
/** Restores the persisted cache the first time it is needed per device. */
|
|
178
|
+
private ensureLoaded;
|
|
179
|
+
private persist;
|
|
180
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,13 @@
|
|
|
15
15
|
* @packageDocumentation
|
|
16
16
|
*/
|
|
17
17
|
import { SDK_NAME, SDK_VERSION } from './version';
|
|
18
|
+
import { RiviumInbox } from './inbox';
|
|
19
|
+
import { InAppMessages, type InAppConfig } from './in-app';
|
|
18
20
|
export { SDK_NAME, SDK_VERSION };
|
|
21
|
+
export { RiviumInbox } from './inbox';
|
|
22
|
+
export type { InboxContent, InboxFilter, InboxMessage, InboxMessagesResponse, InboxMessageStatus, OnInboxMessageCallback, OnInboxStatusChangeCallback, OnInboxUnreadCountCallback, } from './inbox';
|
|
23
|
+
export { InAppMessages, isInAppMessageEligible, selectInAppMessages, localizedContent } from './in-app';
|
|
24
|
+
export type { InAppBannerPosition, InAppButton, InAppButtonAction, InAppButtonStyle, InAppConfig, InAppEligibilityContext, InAppFilter, InAppImpressionAction, InAppLocalization, InAppMessage, InAppMessageContent, InAppMessageType, InAppTriggerType, OnInAppButtonClickedCallback, OnInAppDismissedCallback, OnInAppMessageReadyCallback, } from './in-app';
|
|
19
25
|
/**
|
|
20
26
|
* Standardized error codes for RiviumPush SDK.
|
|
21
27
|
* These codes help developers identify and handle specific error scenarios.
|
|
@@ -209,6 +215,12 @@ export interface RiviumPushConfig {
|
|
|
209
215
|
* permission is already granted. Errors are logged, never thrown.
|
|
210
216
|
*/
|
|
211
217
|
autoRefresh?: boolean;
|
|
218
|
+
/**
|
|
219
|
+
* In-App Messages options. Omit it to keep the defaults: the built-in
|
|
220
|
+
* shadow-DOM UI, triggered by your calls to `inApp.triggerOnAppOpen()` /
|
|
221
|
+
* `inApp.triggerEvent()`.
|
|
222
|
+
*/
|
|
223
|
+
inApp?: InAppConfig;
|
|
212
224
|
}
|
|
213
225
|
/**
|
|
214
226
|
* Notification action button
|
|
@@ -382,6 +394,16 @@ declare class RiviumPush {
|
|
|
382
394
|
private registerRequested;
|
|
383
395
|
private ackedMessageIds;
|
|
384
396
|
private receivedMessageIds;
|
|
397
|
+
/**
|
|
398
|
+
* Message Inbox. Listeners can be attached immediately; network calls need
|
|
399
|
+
* a registered device.
|
|
400
|
+
*/
|
|
401
|
+
readonly inbox: RiviumInbox;
|
|
402
|
+
/**
|
|
403
|
+
* In-App Messages. Listeners can be attached immediately; network calls
|
|
404
|
+
* need a registered device.
|
|
405
|
+
*/
|
|
406
|
+
readonly inApp: InAppMessages;
|
|
385
407
|
constructor(config: RiviumPushConfig);
|
|
386
408
|
/**
|
|
387
409
|
* Fetch MQTT and VAPID configuration from server
|
|
@@ -607,6 +629,13 @@ declare class RiviumPush {
|
|
|
607
629
|
* Messages without an id can't be deduped and always pass.
|
|
608
630
|
*/
|
|
609
631
|
private markReceived;
|
|
632
|
+
/**
|
|
633
|
+
* `inbox_update` payloads update the Message Inbox instead of being shown
|
|
634
|
+
* as a notification. Deduped by message id like delivery acks, so a payload
|
|
635
|
+
* arriving over both the real-time channel and the service worker counts
|
|
636
|
+
* once. Returns true when the payload was an inbox update.
|
|
637
|
+
*/
|
|
638
|
+
private routeInboxUpdate;
|
|
610
639
|
private handleServiceWorkerMessage;
|
|
611
640
|
private showRichNotification;
|
|
612
641
|
private updateFaviconBadge;
|