@trycourier/courier-js 1.4.2 → 2.0.1-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/brand-client.test.d.ts +1 -0
- package/dist/__tests__/courier-client.test.d.ts +1 -0
- package/dist/__tests__/inbox-client.test.d.ts +1 -0
- package/dist/__tests__/lists-client.test.d.ts +1 -0
- package/dist/__tests__/preferences-client.test.d.ts +1 -0
- package/dist/__tests__/shared-instance.test.d.ts +1 -0
- package/dist/__tests__/token-client.test.d.ts +1 -0
- package/dist/__tests__/tracking-client.test.d.ts +1 -0
- package/dist/__tests__/utils.d.ts +2 -0
- package/dist/client/brand-client.d.ts +12 -0
- package/dist/client/client.d.ts +5 -0
- package/dist/client/courier-client.d.ts +38 -0
- package/dist/client/inbox-client.d.ts +80 -0
- package/dist/client/list-client.d.ts +21 -0
- package/dist/client/preference-client.d.ts +46 -0
- package/dist/client/token-client.d.ts +24 -0
- package/dist/client/tracking-client.d.ts +32 -0
- package/dist/index.d.ts +19 -40
- package/dist/index.js +1 -189
- package/dist/index.mjs +1028 -133
- package/dist/jest.setup.d.ts +0 -0
- package/dist/shared/authentication-listener.d.ts +9 -0
- package/dist/shared/courier.d.ts +68 -0
- package/dist/socket/courier-socket.d.ts +24 -0
- package/dist/socket/inbox-socket.d.ts +19 -0
- package/dist/types/brands.d.ts +36 -0
- package/dist/types/courier-api-urls.d.ts +11 -0
- package/dist/types/inbox.d.ts +43 -0
- package/dist/types/pagination.d.ts +4 -0
- package/dist/types/preference.d.ts +37 -0
- package/dist/types/token.d.ts +12 -0
- package/dist/types/tracking-event.d.ts +1 -0
- package/dist/utils/coding.d.ts +2 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/request.d.ts +21 -0
- package/dist/utils/uuid.d.ts +3 -0
- package/package.json +32 -21
- package/README.md +0 -123
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,681 @@
|
|
|
1
|
-
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
const _CourierSocket = class _CourierSocket {
|
|
5
|
+
constructor(url, options) {
|
|
6
|
+
// Properties
|
|
7
|
+
__publicField(this, "webSocket", null);
|
|
8
|
+
__publicField(this, "pingInterval", null);
|
|
9
|
+
// Callbacks
|
|
10
|
+
__publicField(this, "onOpen");
|
|
11
|
+
__publicField(this, "onMessageReceived");
|
|
12
|
+
__publicField(this, "onClose");
|
|
13
|
+
__publicField(this, "onError");
|
|
14
|
+
// Properties
|
|
15
|
+
__publicField(this, "url");
|
|
16
|
+
__publicField(this, "options");
|
|
17
|
+
this.url = url;
|
|
18
|
+
this.options = options;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Dynamically checks if the WebSocket is connected
|
|
22
|
+
*/
|
|
23
|
+
get isConnected() {
|
|
24
|
+
return this.webSocket !== null;
|
|
25
|
+
}
|
|
26
|
+
async connect() {
|
|
27
|
+
this.disconnect();
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
try {
|
|
30
|
+
this.webSocket = new WebSocket(this.url);
|
|
31
|
+
this.webSocket.onopen = () => {
|
|
32
|
+
var _a;
|
|
33
|
+
(_a = this.onOpen) == null ? void 0 : _a.call(this);
|
|
34
|
+
resolve();
|
|
35
|
+
};
|
|
36
|
+
this.webSocket.onmessage = (event) => {
|
|
37
|
+
var _a;
|
|
38
|
+
(_a = this.onMessageReceived) == null ? void 0 : _a.call(this, event.data);
|
|
39
|
+
};
|
|
40
|
+
this.webSocket.onclose = (event) => {
|
|
41
|
+
var _a;
|
|
42
|
+
this.webSocket = null;
|
|
43
|
+
(_a = this.onClose) == null ? void 0 : _a.call(this, event.code, event.reason);
|
|
44
|
+
};
|
|
45
|
+
this.webSocket.onerror = (event) => {
|
|
46
|
+
var _a;
|
|
47
|
+
this.webSocket = null;
|
|
48
|
+
const error = new Error("Courier Socket connection failed");
|
|
49
|
+
error.originalEvent = event;
|
|
50
|
+
(_a = this.onError) == null ? void 0 : _a.call(this, error);
|
|
51
|
+
reject(error);
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
this.webSocket = null;
|
|
55
|
+
reject(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
disconnect() {
|
|
60
|
+
this.stopPing();
|
|
61
|
+
if (this.webSocket) {
|
|
62
|
+
this.webSocket.close(_CourierSocket.NORMAL_CLOSURE_STATUS);
|
|
63
|
+
this.webSocket = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async send(message) {
|
|
67
|
+
if (!this.webSocket) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const json = JSON.stringify(message);
|
|
71
|
+
return this.webSocket.send(json) !== void 0;
|
|
72
|
+
}
|
|
73
|
+
keepAlive(props) {
|
|
74
|
+
this.stopPing();
|
|
75
|
+
this.pingInterval = setInterval(async () => {
|
|
76
|
+
var _a;
|
|
77
|
+
try {
|
|
78
|
+
await this.send({ action: "keepAlive" });
|
|
79
|
+
} catch (error) {
|
|
80
|
+
(_a = this.options.logger) == null ? void 0 : _a.error("Error occurred on Keep Alive:", error);
|
|
81
|
+
}
|
|
82
|
+
}, (props == null ? void 0 : props.intervalInMillis) ?? 3e5);
|
|
83
|
+
}
|
|
84
|
+
stopPing() {
|
|
85
|
+
if (this.pingInterval) {
|
|
86
|
+
clearInterval(this.pingInterval);
|
|
87
|
+
this.pingInterval = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// Constants
|
|
92
|
+
__publicField(_CourierSocket, "NORMAL_CLOSURE_STATUS", 1e3);
|
|
93
|
+
let CourierSocket = _CourierSocket;
|
|
94
|
+
const getCourierApiUrls = (urls) => ({
|
|
95
|
+
courier: {
|
|
96
|
+
rest: (urls == null ? void 0 : urls.courier.rest) || "https://api.courier.com",
|
|
97
|
+
graphql: (urls == null ? void 0 : urls.courier.graphql) || "https://api.courier.com/client/q"
|
|
98
|
+
},
|
|
99
|
+
inbox: {
|
|
100
|
+
graphql: (urls == null ? void 0 : urls.inbox.graphql) || "https://inbox.courier.com/q",
|
|
101
|
+
webSocket: (urls == null ? void 0 : urls.inbox.webSocket) || "wss://realtime.courier.com"
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
class Logger {
|
|
105
|
+
constructor(showLogs) {
|
|
106
|
+
__publicField(this, "PREFIX", "[COURIER]");
|
|
107
|
+
this.showLogs = showLogs;
|
|
108
|
+
}
|
|
109
|
+
warn(message, ...args) {
|
|
110
|
+
if (this.showLogs) {
|
|
111
|
+
console.warn(`${this.PREFIX} ${message}`, ...args);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
log(message, ...args) {
|
|
115
|
+
if (this.showLogs) {
|
|
116
|
+
console.log(`${this.PREFIX} ${message}`, ...args);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
error(message, ...args) {
|
|
120
|
+
if (this.showLogs) {
|
|
121
|
+
console.error(`${this.PREFIX} ${message}`, ...args);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
debug(message, ...args) {
|
|
125
|
+
if (this.showLogs) {
|
|
126
|
+
console.debug(`${this.PREFIX} ${message}`, ...args);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
info(message, ...args) {
|
|
130
|
+
if (this.showLogs) {
|
|
131
|
+
console.info(`${this.PREFIX} ${message}`, ...args);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
class UUID {
|
|
136
|
+
static generate(prefix) {
|
|
137
|
+
const id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
138
|
+
return prefix ? prefix + id : id;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
class CourierRequestError extends Error {
|
|
142
|
+
constructor(code, message, type) {
|
|
143
|
+
super(message);
|
|
144
|
+
this.code = code;
|
|
145
|
+
this.type = type;
|
|
146
|
+
this.name = "CourierRequestError";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function logRequest(logger, uid, type, data) {
|
|
150
|
+
logger.log(`
|
|
151
|
+
📡 New Courier ${type} Request: ${uid}
|
|
152
|
+
URL: ${data.url}
|
|
153
|
+
${data.method ? `Method: ${data.method}` : ""}
|
|
154
|
+
${data.query ? `Query: ${data.query}` : ""}
|
|
155
|
+
${data.variables ? `Variables: ${JSON.stringify(data.variables, null, 2)}` : ""}
|
|
156
|
+
Headers: ${JSON.stringify(data.headers, null, 2)}
|
|
157
|
+
Body: ${data.body ? JSON.stringify(data.body, null, 2) : "Empty"}
|
|
158
|
+
`);
|
|
159
|
+
}
|
|
160
|
+
function logResponse(logger, uid, type, data) {
|
|
161
|
+
logger.log(`
|
|
162
|
+
📡 New Courier ${type} Response: ${uid}
|
|
163
|
+
Status Code: ${data.status}
|
|
164
|
+
Response JSON: ${JSON.stringify(data.response, null, 2)}
|
|
165
|
+
`);
|
|
166
|
+
}
|
|
167
|
+
async function http(props) {
|
|
168
|
+
const validCodes = props.validCodes ?? [200];
|
|
169
|
+
const uid = props.options.showLogs ? UUID.generate() : void 0;
|
|
170
|
+
const request = new Request(props.url, {
|
|
171
|
+
method: props.method,
|
|
172
|
+
headers: {
|
|
173
|
+
"Content-Type": "application/json",
|
|
174
|
+
...props.headers
|
|
175
|
+
},
|
|
176
|
+
body: props.body ? JSON.stringify(props.body) : void 0
|
|
177
|
+
});
|
|
178
|
+
if (uid) {
|
|
179
|
+
logRequest(props.options.logger, uid, "HTTP", {
|
|
180
|
+
url: request.url,
|
|
181
|
+
method: request.method,
|
|
182
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
183
|
+
body: props.body
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const response = await fetch(request);
|
|
187
|
+
if (response.status === 204) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
let data;
|
|
191
|
+
try {
|
|
192
|
+
data = await response.json();
|
|
193
|
+
} catch (error) {
|
|
194
|
+
if (response.status === 200) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
throw new CourierRequestError(
|
|
198
|
+
response.status,
|
|
199
|
+
"Failed to parse response as JSON",
|
|
200
|
+
"PARSE_ERROR"
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (uid) {
|
|
204
|
+
logResponse(props.options.logger, uid, "HTTP", {
|
|
205
|
+
status: response.status,
|
|
206
|
+
response: data
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (!validCodes.includes(response.status)) {
|
|
210
|
+
throw new CourierRequestError(
|
|
211
|
+
response.status,
|
|
212
|
+
(data == null ? void 0 : data.message) || "Unknown Error",
|
|
213
|
+
data == null ? void 0 : data.type
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return data;
|
|
217
|
+
}
|
|
218
|
+
async function graphql(props) {
|
|
219
|
+
const uid = props.options.showLogs ? UUID.generate() : void 0;
|
|
220
|
+
if (uid) {
|
|
221
|
+
logRequest(props.options.logger, uid, "GraphQL", {
|
|
222
|
+
url: props.url,
|
|
223
|
+
headers: props.headers,
|
|
224
|
+
query: props.query,
|
|
225
|
+
variables: props.variables
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const response = await fetch(props.url, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: {
|
|
231
|
+
"Content-Type": "application/json",
|
|
232
|
+
...props.headers
|
|
233
|
+
},
|
|
234
|
+
body: JSON.stringify({
|
|
235
|
+
query: props.query,
|
|
236
|
+
variables: props.variables
|
|
237
|
+
})
|
|
238
|
+
});
|
|
239
|
+
let data;
|
|
240
|
+
try {
|
|
241
|
+
data = await response.json();
|
|
242
|
+
} catch (error) {
|
|
243
|
+
throw new CourierRequestError(
|
|
244
|
+
response.status,
|
|
245
|
+
"Failed to parse response as JSON",
|
|
246
|
+
"PARSE_ERROR"
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (uid) {
|
|
250
|
+
logResponse(props.options.logger, uid, "GraphQL", {
|
|
251
|
+
status: response.status,
|
|
252
|
+
response: data
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (!response.ok) {
|
|
256
|
+
throw new CourierRequestError(
|
|
257
|
+
response.status,
|
|
258
|
+
(data == null ? void 0 : data.message) || "Unknown Error",
|
|
259
|
+
data == null ? void 0 : data.type
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return data;
|
|
263
|
+
}
|
|
264
|
+
class Client {
|
|
265
|
+
constructor(options) {
|
|
266
|
+
this.options = options;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
class BrandClient extends Client {
|
|
270
|
+
/**
|
|
271
|
+
* Get a brand by ID using GraphQL
|
|
272
|
+
* @param brandId - The ID of the brand to retrieve
|
|
273
|
+
* @returns Promise resolving to the requested brand
|
|
274
|
+
*/
|
|
275
|
+
async getBrand(props) {
|
|
276
|
+
const query = `
|
|
277
|
+
query GetBrand {
|
|
278
|
+
brand(brandId: "${props.brandId}") {
|
|
279
|
+
settings {
|
|
280
|
+
colors {
|
|
281
|
+
primary
|
|
282
|
+
secondary
|
|
283
|
+
tertiary
|
|
284
|
+
}
|
|
285
|
+
inapp {
|
|
286
|
+
borderRadius
|
|
287
|
+
disableCourierFooter
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
`;
|
|
293
|
+
const json = await graphql({
|
|
294
|
+
options: this.options,
|
|
295
|
+
url: this.options.apiUrls.courier.graphql,
|
|
296
|
+
headers: {
|
|
297
|
+
"x-courier-user-id": this.options.userId,
|
|
298
|
+
"x-courier-client-key": "empty",
|
|
299
|
+
// Empty for now. Will be removed in future.
|
|
300
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
301
|
+
},
|
|
302
|
+
query,
|
|
303
|
+
variables: { brandId: props.brandId }
|
|
304
|
+
});
|
|
305
|
+
return json.data.brand;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
class InboxSocket extends CourierSocket {
|
|
309
|
+
constructor(options) {
|
|
310
|
+
const url = InboxSocket.buildUrl(options);
|
|
311
|
+
super(url, options);
|
|
312
|
+
__publicField(this, "receivedMessage");
|
|
313
|
+
__publicField(this, "receivedMessageEvent");
|
|
314
|
+
this.onMessageReceived = (data) => this.convertToType(data);
|
|
315
|
+
}
|
|
316
|
+
convertToType(data) {
|
|
317
|
+
var _a, _b, _c, _d;
|
|
318
|
+
try {
|
|
319
|
+
const payload = JSON.parse(data);
|
|
320
|
+
switch (payload.type) {
|
|
321
|
+
case "event":
|
|
322
|
+
const messageEvent = JSON.parse(data);
|
|
323
|
+
(_a = this.receivedMessageEvent) == null ? void 0 : _a.call(this, messageEvent);
|
|
324
|
+
break;
|
|
325
|
+
case "message":
|
|
326
|
+
const message = JSON.parse(data);
|
|
327
|
+
(_b = this.receivedMessage) == null ? void 0 : _b.call(this, message);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
} catch (error) {
|
|
331
|
+
(_c = this.options.logger) == null ? void 0 : _c.error("Error parsing socket message", error);
|
|
332
|
+
if (error instanceof Error) {
|
|
333
|
+
(_d = this.onError) == null ? void 0 : _d.call(this, error);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async sendSubscribe(props) {
|
|
338
|
+
var _a;
|
|
339
|
+
const subscription = {
|
|
340
|
+
action: "subscribe",
|
|
341
|
+
data: {
|
|
342
|
+
userAgent: "courier-js",
|
|
343
|
+
// TODO: Equivalent to Courier.agent.value()
|
|
344
|
+
channel: this.options.userId,
|
|
345
|
+
event: "*",
|
|
346
|
+
version: (props == null ? void 0 : props.version) ?? 5
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
if (this.options.connectionId) {
|
|
350
|
+
subscription.data.clientSourceId = this.options.connectionId;
|
|
351
|
+
}
|
|
352
|
+
if (this.options.tenantId) {
|
|
353
|
+
subscription.data.accountId = this.options.tenantId;
|
|
354
|
+
}
|
|
355
|
+
(_a = this.options.logger) == null ? void 0 : _a.debug("Sending subscribe request", subscription);
|
|
356
|
+
await this.send(subscription);
|
|
357
|
+
}
|
|
358
|
+
static buildUrl(options) {
|
|
359
|
+
var _a;
|
|
360
|
+
let url = ((_a = options.apiUrls) == null ? void 0 : _a.inbox.webSocket) ?? "";
|
|
361
|
+
if (options.accessToken) {
|
|
362
|
+
url += `/?auth=${options.accessToken}`;
|
|
363
|
+
}
|
|
364
|
+
return url;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
class InboxClient extends Client {
|
|
368
|
+
constructor(options) {
|
|
369
|
+
super(options);
|
|
370
|
+
__publicField(this, "socket");
|
|
371
|
+
this.socket = new InboxSocket(options);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Get paginated messages
|
|
375
|
+
* @param paginationLimit - Number of messages to return per page (default: 24)
|
|
376
|
+
* @param startCursor - Cursor for pagination
|
|
377
|
+
* @returns Promise resolving to paginated messages response
|
|
378
|
+
*/
|
|
379
|
+
async getMessages(props) {
|
|
380
|
+
const query = `
|
|
381
|
+
query GetInboxMessages(
|
|
382
|
+
$params: FilterParamsInput = { ${this.options.tenantId ? `accountId: "${this.options.tenantId}"` : ""} }
|
|
383
|
+
$limit: Int = ${(props == null ? void 0 : props.paginationLimit) ?? 24}
|
|
384
|
+
$after: String ${(props == null ? void 0 : props.startCursor) ? `= "${props.startCursor}"` : ""}
|
|
385
|
+
) {
|
|
386
|
+
count(params: $params)
|
|
387
|
+
messages(params: $params, limit: $limit, after: $after) {
|
|
388
|
+
totalCount
|
|
389
|
+
pageInfo {
|
|
390
|
+
startCursor
|
|
391
|
+
hasNextPage
|
|
392
|
+
}
|
|
393
|
+
nodes {
|
|
394
|
+
messageId
|
|
395
|
+
read
|
|
396
|
+
archived
|
|
397
|
+
created
|
|
398
|
+
opened
|
|
399
|
+
title
|
|
400
|
+
preview
|
|
401
|
+
data
|
|
402
|
+
tags
|
|
403
|
+
trackingIds {
|
|
404
|
+
clickTrackingId
|
|
405
|
+
}
|
|
406
|
+
actions {
|
|
407
|
+
content
|
|
408
|
+
data
|
|
409
|
+
href
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
`;
|
|
415
|
+
return await graphql({
|
|
416
|
+
options: this.options,
|
|
417
|
+
query,
|
|
418
|
+
headers: {
|
|
419
|
+
"x-courier-user-id": this.options.userId,
|
|
420
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
421
|
+
},
|
|
422
|
+
url: this.options.apiUrls.inbox.graphql
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get paginated archived messages
|
|
427
|
+
* @param paginationLimit - Number of messages to return per page (default: 24)
|
|
428
|
+
* @param startCursor - Cursor for pagination
|
|
429
|
+
* @returns Promise resolving to paginated archived messages response
|
|
430
|
+
*/
|
|
431
|
+
async getArchivedMessages(props) {
|
|
432
|
+
const query = `
|
|
433
|
+
query GetInboxMessages(
|
|
434
|
+
$params: FilterParamsInput = { ${this.options.tenantId ? `accountId: "${this.options.tenantId}"` : ""}, archived: true }
|
|
435
|
+
$limit: Int = ${(props == null ? void 0 : props.paginationLimit) ?? 24}
|
|
436
|
+
$after: String ${(props == null ? void 0 : props.startCursor) ? `= "${props.startCursor}"` : ""}
|
|
437
|
+
) {
|
|
438
|
+
count(params: $params)
|
|
439
|
+
messages(params: $params, limit: $limit, after: $after) {
|
|
440
|
+
totalCount
|
|
441
|
+
pageInfo {
|
|
442
|
+
startCursor
|
|
443
|
+
hasNextPage
|
|
444
|
+
}
|
|
445
|
+
nodes {
|
|
446
|
+
messageId
|
|
447
|
+
read
|
|
448
|
+
archived
|
|
449
|
+
created
|
|
450
|
+
opened
|
|
451
|
+
title
|
|
452
|
+
preview
|
|
453
|
+
data
|
|
454
|
+
tags
|
|
455
|
+
trackingIds {
|
|
456
|
+
clickTrackingId
|
|
457
|
+
}
|
|
458
|
+
actions {
|
|
459
|
+
content
|
|
460
|
+
data
|
|
461
|
+
href
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
`;
|
|
467
|
+
return graphql({
|
|
468
|
+
options: this.options,
|
|
469
|
+
query,
|
|
470
|
+
headers: {
|
|
471
|
+
"x-courier-user-id": this.options.userId,
|
|
472
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
473
|
+
},
|
|
474
|
+
url: this.options.apiUrls.inbox.graphql
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get unread message count
|
|
479
|
+
* @returns Promise resolving to number of unread messages
|
|
480
|
+
*/
|
|
481
|
+
async getUnreadMessageCount() {
|
|
482
|
+
var _a;
|
|
483
|
+
const query = `
|
|
484
|
+
query GetMessages {
|
|
485
|
+
count(params: { status: "unread" ${this.options.tenantId ? `, accountId: "${this.options.tenantId}"` : ""} })
|
|
486
|
+
}
|
|
487
|
+
`;
|
|
488
|
+
const response = await graphql({
|
|
489
|
+
options: this.options,
|
|
490
|
+
query,
|
|
491
|
+
headers: {
|
|
492
|
+
"x-courier-user-id": this.options.userId,
|
|
493
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
494
|
+
},
|
|
495
|
+
url: this.options.apiUrls.inbox.graphql
|
|
496
|
+
});
|
|
497
|
+
return ((_a = response.data) == null ? void 0 : _a.count) ?? 0;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Track a click event
|
|
501
|
+
* @param messageId - ID of the message
|
|
502
|
+
* @param trackingId - ID for tracking the click
|
|
503
|
+
* @returns Promise resolving when click is tracked
|
|
504
|
+
*/
|
|
505
|
+
async click(props) {
|
|
506
|
+
const query = `
|
|
507
|
+
mutation TrackEvent {
|
|
508
|
+
clicked(messageId: "${props.messageId}", trackingId: "${props.trackingId}")
|
|
509
|
+
}
|
|
510
|
+
`;
|
|
511
|
+
const headers = {
|
|
512
|
+
"x-courier-user-id": this.options.userId,
|
|
513
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
514
|
+
};
|
|
515
|
+
if (this.options.connectionId) {
|
|
516
|
+
headers["x-courier-client-source-id"] = this.options.connectionId;
|
|
517
|
+
}
|
|
518
|
+
await graphql({
|
|
519
|
+
options: this.options,
|
|
520
|
+
query,
|
|
521
|
+
headers,
|
|
522
|
+
url: this.options.apiUrls.inbox.graphql
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Mark a message as read
|
|
527
|
+
* @param messageId - ID of the message to mark as read
|
|
528
|
+
* @returns Promise resolving when message is marked as read
|
|
529
|
+
*/
|
|
530
|
+
async read(props) {
|
|
531
|
+
const query = `
|
|
532
|
+
mutation TrackEvent {
|
|
533
|
+
read(messageId: "${props.messageId}")
|
|
534
|
+
}
|
|
535
|
+
`;
|
|
536
|
+
const headers = {
|
|
537
|
+
"x-courier-user-id": this.options.userId,
|
|
538
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
539
|
+
};
|
|
540
|
+
if (this.options.connectionId) {
|
|
541
|
+
headers["x-courier-client-source-id"] = this.options.connectionId;
|
|
542
|
+
}
|
|
543
|
+
await graphql({
|
|
544
|
+
options: this.options,
|
|
545
|
+
query,
|
|
546
|
+
headers,
|
|
547
|
+
url: this.options.apiUrls.inbox.graphql
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Mark a message as unread
|
|
552
|
+
* @param messageId - ID of the message to mark as unread
|
|
553
|
+
* @returns Promise resolving when message is marked as unread
|
|
554
|
+
*/
|
|
555
|
+
async unread(props) {
|
|
556
|
+
const query = `
|
|
557
|
+
mutation TrackEvent {
|
|
558
|
+
unread(messageId: "${props.messageId}")
|
|
559
|
+
}
|
|
560
|
+
`;
|
|
561
|
+
const headers = {
|
|
562
|
+
"x-courier-user-id": this.options.userId,
|
|
563
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
564
|
+
};
|
|
565
|
+
if (this.options.connectionId) {
|
|
566
|
+
headers["x-courier-client-source-id"] = this.options.connectionId;
|
|
567
|
+
}
|
|
568
|
+
await graphql({
|
|
569
|
+
options: this.options,
|
|
570
|
+
query,
|
|
571
|
+
headers,
|
|
572
|
+
url: this.options.apiUrls.inbox.graphql
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Mark all messages as read
|
|
577
|
+
* @returns Promise resolving when all messages are marked as read
|
|
578
|
+
*/
|
|
579
|
+
async readAll() {
|
|
580
|
+
const query = `
|
|
581
|
+
mutation TrackEvent {
|
|
582
|
+
markAllRead
|
|
583
|
+
}
|
|
584
|
+
`;
|
|
585
|
+
const headers = {
|
|
586
|
+
"x-courier-user-id": this.options.userId,
|
|
587
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
588
|
+
};
|
|
589
|
+
if (this.options.connectionId) {
|
|
590
|
+
headers["x-courier-client-source-id"] = this.options.connectionId;
|
|
591
|
+
}
|
|
592
|
+
await graphql({
|
|
593
|
+
options: this.options,
|
|
594
|
+
query,
|
|
595
|
+
headers,
|
|
596
|
+
url: this.options.apiUrls.inbox.graphql
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Mark a message as opened
|
|
601
|
+
* @param messageId - ID of the message to mark as opened
|
|
602
|
+
* @returns Promise resolving when message is marked as opened
|
|
603
|
+
*/
|
|
604
|
+
async open(props) {
|
|
605
|
+
const query = `
|
|
606
|
+
mutation TrackEvent {
|
|
607
|
+
opened(messageId: "${props.messageId}")
|
|
608
|
+
}
|
|
609
|
+
`;
|
|
610
|
+
const headers = {
|
|
611
|
+
"x-courier-user-id": this.options.userId,
|
|
612
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
613
|
+
};
|
|
614
|
+
if (this.options.connectionId) {
|
|
615
|
+
headers["x-courier-client-source-id"] = this.options.connectionId;
|
|
616
|
+
}
|
|
617
|
+
await graphql({
|
|
618
|
+
options: this.options,
|
|
619
|
+
query,
|
|
620
|
+
headers,
|
|
621
|
+
url: this.options.apiUrls.inbox.graphql
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Archive a message
|
|
626
|
+
* @param messageId - ID of the message to archive
|
|
627
|
+
* @returns Promise resolving when message is archived
|
|
628
|
+
*/
|
|
629
|
+
async archive(props) {
|
|
630
|
+
const query = `
|
|
631
|
+
mutation TrackEvent {
|
|
632
|
+
archive(messageId: "${props.messageId}")
|
|
633
|
+
}
|
|
634
|
+
`;
|
|
635
|
+
const headers = {
|
|
636
|
+
"x-courier-user-id": this.options.userId,
|
|
637
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
638
|
+
};
|
|
639
|
+
if (this.options.connectionId) {
|
|
640
|
+
headers["x-courier-client-source-id"] = this.options.connectionId;
|
|
641
|
+
}
|
|
642
|
+
await graphql({
|
|
643
|
+
options: this.options,
|
|
644
|
+
query,
|
|
645
|
+
headers,
|
|
646
|
+
url: this.options.apiUrls.inbox.graphql
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
class PreferenceTransformer {
|
|
651
|
+
/**
|
|
652
|
+
* Transforms a single API response item to the CourierUserPreferencesTopic type
|
|
653
|
+
* @param item - The API response item
|
|
654
|
+
* @returns A CourierUserPreferencesTopic object
|
|
655
|
+
*/
|
|
656
|
+
transformItem(item) {
|
|
657
|
+
return {
|
|
658
|
+
topicId: item.topic_id,
|
|
659
|
+
topicName: item.topic_name,
|
|
660
|
+
sectionId: item.section_id,
|
|
661
|
+
sectionName: item.section_name,
|
|
662
|
+
status: item.status,
|
|
663
|
+
defaultStatus: item.default_status,
|
|
664
|
+
hasCustomRouting: item.has_custom_routing,
|
|
665
|
+
customRouting: item.custom_routing || []
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Transforms an array of API response items to CourierUserPreferencesTopic objects
|
|
670
|
+
* @param items - The API response items
|
|
671
|
+
* @returns A generator of CourierUserPreferencesTopic objects
|
|
672
|
+
*/
|
|
673
|
+
*transform(items) {
|
|
674
|
+
for (const item of items) {
|
|
675
|
+
yield this.transformItem(item);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
5
679
|
function decode(clientKey) {
|
|
6
680
|
const binaryString = atob(clientKey);
|
|
7
681
|
const bytes = new Uint8Array(binaryString.length);
|
|
@@ -17,148 +691,369 @@ function encode(key) {
|
|
|
17
691
|
}
|
|
18
692
|
return btoa(String.fromCharCode(...bytes));
|
|
19
693
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const response = await fn();
|
|
25
|
-
if (!response.ok && debug) {
|
|
26
|
-
console.error(
|
|
27
|
-
`Error invoking ${response.url}: ${(_a = response.status) != null ? _a : 404} because ${JSON.stringify((_b = await response.json()) == null ? void 0 : _b.message)}`
|
|
28
|
-
);
|
|
694
|
+
class PreferenceClient extends Client {
|
|
695
|
+
constructor() {
|
|
696
|
+
super(...arguments);
|
|
697
|
+
__publicField(this, "transformer", new PreferenceTransformer());
|
|
29
698
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
userId
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.userSignature = userSignature;
|
|
49
|
-
}
|
|
50
|
-
getHeaders() {
|
|
51
|
-
return new Headers({
|
|
52
|
-
"Content-Type": "application/json",
|
|
53
|
-
"x-courier-client-version": `courier-js@${version}`,
|
|
54
|
-
"Access-Control-Allow-Origin": "*",
|
|
55
|
-
...this.authorization && { Authorization: this.authorization },
|
|
56
|
-
...this.userId && { "x-courier-user-id": this.userId },
|
|
57
|
-
...this.userSignature && {
|
|
58
|
-
"x-courier-user-signature": this.userSignature
|
|
59
|
-
},
|
|
60
|
-
...this.clientKey && { "x-courier-client-key": this.clientKey }
|
|
699
|
+
/**
|
|
700
|
+
* Get all preferences for a user
|
|
701
|
+
* @param paginationCursor - Optional cursor for pagination
|
|
702
|
+
* @returns Promise resolving to user preferences
|
|
703
|
+
* @see https://www.courier.com/docs/reference/user-preferences/list-all-user-preferences
|
|
704
|
+
*/
|
|
705
|
+
async getUserPreferences(props) {
|
|
706
|
+
let url = `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences`;
|
|
707
|
+
if (props == null ? void 0 : props.paginationCursor) {
|
|
708
|
+
url += `?cursor=${props.paginationCursor}`;
|
|
709
|
+
}
|
|
710
|
+
const json = await http({
|
|
711
|
+
options: this.options,
|
|
712
|
+
url,
|
|
713
|
+
method: "GET",
|
|
714
|
+
headers: {
|
|
715
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
716
|
+
}
|
|
61
717
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
body: JSON.stringify(body),
|
|
67
|
-
headers: this.getHeaders(),
|
|
68
|
-
method: "POST"
|
|
69
|
-
});
|
|
718
|
+
const data = json;
|
|
719
|
+
return {
|
|
720
|
+
items: [...this.transformer.transform(data.items)],
|
|
721
|
+
paging: data.paging
|
|
70
722
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Get preferences for a specific topic
|
|
726
|
+
* @param topicId - The ID of the topic to get preferences for
|
|
727
|
+
* @returns Promise resolving to topic preferences
|
|
728
|
+
* @see https://www.courier.com/docs/reference/user-preferences/get-subscription-topic-preferences
|
|
729
|
+
*/
|
|
730
|
+
async getUserPreferenceTopic(props) {
|
|
731
|
+
const json = await http({
|
|
732
|
+
options: this.options,
|
|
733
|
+
url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences/${props.topicId}`,
|
|
734
|
+
method: "GET",
|
|
735
|
+
headers: {
|
|
736
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
const res = json;
|
|
740
|
+
return this.transformer.transformItem(res.topic);
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Update preferences for a specific topic
|
|
744
|
+
* @param topicId - The ID of the topic to update preferences for
|
|
745
|
+
* @param status - The new status for the topic
|
|
746
|
+
* @param hasCustomRouting - Whether the topic has custom routing
|
|
747
|
+
* @param customRouting - The custom routing channels for the topic
|
|
748
|
+
* @returns Promise resolving when update is complete
|
|
749
|
+
* @see https://www.courier.com/docs/reference/user-preferences/update-subscription-topic-preferences
|
|
750
|
+
*/
|
|
751
|
+
async putUserPreferenceTopic(props) {
|
|
752
|
+
const payload = {
|
|
753
|
+
topic: {
|
|
754
|
+
status: props.status,
|
|
755
|
+
has_custom_routing: props.hasCustomRouting,
|
|
756
|
+
custom_routing: props.customRouting
|
|
757
|
+
}
|
|
80
758
|
};
|
|
81
|
-
await
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
759
|
+
await http({
|
|
760
|
+
options: this.options,
|
|
761
|
+
url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences/${props.topicId}`,
|
|
762
|
+
method: "PUT",
|
|
763
|
+
headers: {
|
|
764
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
765
|
+
},
|
|
766
|
+
body: payload
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Get the notification center URL
|
|
771
|
+
* @param clientKey - The client key to use for the URL
|
|
772
|
+
* @returns The notification center URL
|
|
773
|
+
*/
|
|
774
|
+
getNotificationCenterUrl(props) {
|
|
775
|
+
const rootTenantId = decode(props.clientKey);
|
|
776
|
+
const url = encode(`${rootTenantId}#${this.options.userId}${this.options.tenantId ? `#${this.options.tenantId}` : ""}#${false}`);
|
|
777
|
+
return `https://view.notificationcenter.app/p/${url}`;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
class TokenClient extends Client {
|
|
781
|
+
/**
|
|
782
|
+
* Store a push notification token for a user
|
|
783
|
+
* @param token - The push notification token
|
|
784
|
+
* @param provider - The provider of the token
|
|
785
|
+
* @param device - The device information
|
|
786
|
+
* @see https://www.courier.com/docs/reference/token-management/put-token
|
|
787
|
+
*/
|
|
788
|
+
async putUserToken(props) {
|
|
789
|
+
const payload = {
|
|
790
|
+
provider_key: props.provider,
|
|
791
|
+
...props.device && {
|
|
792
|
+
device: {
|
|
793
|
+
app_id: props.device.appId,
|
|
794
|
+
ad_id: props.device.adId,
|
|
795
|
+
device_id: props.device.deviceId,
|
|
796
|
+
platform: props.device.platform,
|
|
797
|
+
manufacturer: props.device.manufacturer,
|
|
798
|
+
model: props.device.model
|
|
799
|
+
}
|
|
800
|
+
}
|
|
89
801
|
};
|
|
90
|
-
await
|
|
802
|
+
await http({
|
|
803
|
+
options: this.options,
|
|
804
|
+
url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,
|
|
805
|
+
method: "PUT",
|
|
806
|
+
headers: {
|
|
807
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
808
|
+
},
|
|
809
|
+
body: payload,
|
|
810
|
+
validCodes: [200, 204]
|
|
811
|
+
});
|
|
91
812
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
813
|
+
/**
|
|
814
|
+
* Delete a push notification token for a user
|
|
815
|
+
* @param token - The push notification token
|
|
816
|
+
* @returns Promise resolving when token is deleted
|
|
817
|
+
*/
|
|
818
|
+
async deleteUserToken(props) {
|
|
819
|
+
await http({
|
|
820
|
+
options: this.options,
|
|
821
|
+
url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,
|
|
822
|
+
method: "DELETE",
|
|
823
|
+
headers: {
|
|
824
|
+
"Authorization": `Bearer ${this.options.accessToken}`
|
|
825
|
+
},
|
|
826
|
+
validCodes: [200, 204]
|
|
827
|
+
});
|
|
101
828
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
829
|
+
}
|
|
830
|
+
class ListClient extends Client {
|
|
831
|
+
/**
|
|
832
|
+
* Subscribe a user to a list
|
|
833
|
+
* @param listId - The ID of the list to subscribe to
|
|
834
|
+
* @returns Promise resolving when subscription is complete
|
|
835
|
+
* @see https://www.courier.com/docs/reference/lists/recipient-subscribe
|
|
836
|
+
*/
|
|
837
|
+
async putSubscription(props) {
|
|
838
|
+
return await http({
|
|
839
|
+
url: `${this.options.apiUrls.courier.rest}/lists/${props.listId}/subscriptions/${this.options.userId}`,
|
|
840
|
+
options: this.options,
|
|
841
|
+
method: "PUT",
|
|
842
|
+
headers: {
|
|
843
|
+
Authorization: `Bearer ${this.options.accessToken}`
|
|
844
|
+
}
|
|
845
|
+
});
|
|
108
846
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
async identify(userId, payload) {
|
|
124
|
-
if (!userId) {
|
|
125
|
-
throw new Error("userId is required");
|
|
126
|
-
}
|
|
127
|
-
await this.instance.post(`/identify/${userId}`, {
|
|
128
|
-
profile: {
|
|
129
|
-
...payload
|
|
847
|
+
/**
|
|
848
|
+
* Unsubscribe a user from a list
|
|
849
|
+
* @param listId - The ID of the list to unsubscribe from
|
|
850
|
+
* @returns Promise resolving when unsubscription is complete
|
|
851
|
+
* @see https://www.courier.com/docs/reference/lists/delete-subscription
|
|
852
|
+
*/
|
|
853
|
+
async deleteSubscription(props) {
|
|
854
|
+
return await http({
|
|
855
|
+
url: `${this.options.apiUrls.courier.rest}/lists/${props.listId}/subscriptions/${this.options.userId}`,
|
|
856
|
+
options: this.options,
|
|
857
|
+
method: "DELETE",
|
|
858
|
+
headers: {
|
|
859
|
+
Authorization: `Bearer ${this.options.accessToken}`
|
|
130
860
|
}
|
|
131
861
|
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
class TrackingClient extends Client {
|
|
865
|
+
/**
|
|
866
|
+
* Post an inbound courier event
|
|
867
|
+
* @param event - The event type: Example: "New Order Placed"
|
|
868
|
+
* @param messageId - The message ID
|
|
869
|
+
* @param type - The type of event: Available options: "track"
|
|
870
|
+
* @param properties - The properties of the event
|
|
871
|
+
* @returns Promise resolving to the message ID
|
|
872
|
+
* @see https://www.courier.com/docs/reference/inbound/courier-track-event
|
|
873
|
+
*/
|
|
874
|
+
async postInboundCourier(props) {
|
|
875
|
+
return await http({
|
|
876
|
+
url: `${this.options.apiUrls.courier.rest}/inbound/courier`,
|
|
877
|
+
options: this.options,
|
|
878
|
+
method: "POST",
|
|
879
|
+
headers: {
|
|
880
|
+
Authorization: `Bearer ${this.options.accessToken}`
|
|
881
|
+
},
|
|
882
|
+
body: {
|
|
883
|
+
...props,
|
|
884
|
+
userId: this.options.userId
|
|
885
|
+
},
|
|
886
|
+
validCodes: [200, 202]
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Post a tracking URL event
|
|
891
|
+
* These urls are found in messages sent from Courier
|
|
892
|
+
* @param url - The URL to post the event to
|
|
893
|
+
* @param event - The event type: Available options: "click", "open", "unsubscribe"
|
|
894
|
+
* @returns Promise resolving when the event is posted
|
|
895
|
+
*/
|
|
896
|
+
async postTrackingUrl(props) {
|
|
897
|
+
return await http({
|
|
898
|
+
url: props.url,
|
|
899
|
+
options: this.options,
|
|
900
|
+
method: "POST",
|
|
901
|
+
body: {
|
|
902
|
+
event: props.event
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
class CourierClient extends Client {
|
|
908
|
+
constructor(props) {
|
|
909
|
+
var _a, _b;
|
|
910
|
+
const showLogs = props.showLogs !== void 0 ? props.showLogs : process.env.NODE_ENV === "development";
|
|
911
|
+
const baseOptions = {
|
|
912
|
+
...props,
|
|
913
|
+
showLogs,
|
|
914
|
+
apiUrls: props.apiUrls || getCourierApiUrls(),
|
|
915
|
+
accessToken: props.jwt ?? props.publicApiKey
|
|
916
|
+
};
|
|
917
|
+
super({
|
|
918
|
+
...baseOptions,
|
|
919
|
+
logger: new Logger(baseOptions.showLogs),
|
|
920
|
+
apiUrls: getCourierApiUrls(baseOptions.apiUrls)
|
|
921
|
+
});
|
|
922
|
+
__publicField(this, "tokens");
|
|
923
|
+
__publicField(this, "brands");
|
|
924
|
+
__publicField(this, "preferences");
|
|
925
|
+
__publicField(this, "inbox");
|
|
926
|
+
__publicField(this, "lists");
|
|
927
|
+
__publicField(this, "tracking");
|
|
928
|
+
this.tokens = new TokenClient(this.options);
|
|
929
|
+
this.brands = new BrandClient(this.options);
|
|
930
|
+
this.preferences = new PreferenceClient(this.options);
|
|
931
|
+
this.inbox = new InboxClient(this.options);
|
|
932
|
+
this.lists = new ListClient(this.options);
|
|
933
|
+
this.tracking = new TrackingClient(this.options);
|
|
934
|
+
if (!this.options.jwt && !this.options.publicApiKey) {
|
|
935
|
+
this.options.logger.warn("Courier Client initialized with no authentication method. Please provide a JWT or public API key.");
|
|
136
936
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
throw new Error("event is required");
|
|
142
|
-
}
|
|
143
|
-
let indempotentKey = self.crypto.randomUUID ? self.crypto.randomUUID() : Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
144
|
-
await this.instance.post(`/inbound/courier`, {
|
|
145
|
-
messageId: indempotentKey,
|
|
146
|
-
type: "track",
|
|
147
|
-
event,
|
|
148
|
-
properties: { ...properties }
|
|
149
|
-
}, false);
|
|
150
|
-
},
|
|
151
|
-
async unsubscribe(userId, listId) {
|
|
152
|
-
if (!userId || !listId) {
|
|
153
|
-
throw new Error("userId is required");
|
|
937
|
+
if (this.options.publicApiKey) {
|
|
938
|
+
(_a = this.options.logger) == null ? void 0 : _a.warn(
|
|
939
|
+
"Courier Warning: Public API Keys are for testing only. Please use JWTs for production.\nYou can generate a JWT with this endpoint: https://www.courier.com/docs/reference/auth/issue-token\nThis endpoint should be called from your backend server, not the SDK."
|
|
940
|
+
);
|
|
154
941
|
}
|
|
155
|
-
this.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
942
|
+
if (this.options.jwt && this.options.publicApiKey) {
|
|
943
|
+
(_b = this.options.logger) == null ? void 0 : _b.warn(
|
|
944
|
+
"Courier Warning: Both a JWT and a Public API Key were provided. The Public API Key will be ignored."
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
class AuthenticationListener {
|
|
950
|
+
constructor(callback) {
|
|
951
|
+
__publicField(this, "callback");
|
|
952
|
+
this.callback = callback;
|
|
953
|
+
}
|
|
954
|
+
remove() {
|
|
955
|
+
Courier.shared.removeAuthenticationListener(this);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
const _Courier = class _Courier {
|
|
959
|
+
constructor() {
|
|
960
|
+
/**
|
|
961
|
+
* The unique identifier for the Courier instance
|
|
962
|
+
*/
|
|
963
|
+
__publicField(this, "id", UUID.generate());
|
|
964
|
+
/**
|
|
965
|
+
* The Courier client instance
|
|
966
|
+
*/
|
|
967
|
+
__publicField(this, "instanceClient");
|
|
968
|
+
/**
|
|
969
|
+
* The pagination limit (min: 1, max: 100)
|
|
970
|
+
*/
|
|
971
|
+
__publicField(this, "_paginationLimit", 24);
|
|
972
|
+
/**
|
|
973
|
+
* The authentication listeners
|
|
974
|
+
*/
|
|
975
|
+
__publicField(this, "authenticationListeners", []);
|
|
976
|
+
}
|
|
977
|
+
get paginationLimit() {
|
|
978
|
+
return this._paginationLimit;
|
|
979
|
+
}
|
|
980
|
+
set paginationLimit(value) {
|
|
981
|
+
this._paginationLimit = Math.min(Math.max(value, 1), 100);
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Get the Courier client instance
|
|
985
|
+
* @returns The Courier client instance or undefined if not signed in
|
|
986
|
+
*/
|
|
987
|
+
get client() {
|
|
988
|
+
return this.instanceClient;
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Get the shared Courier instance
|
|
992
|
+
* @returns The shared Courier instance
|
|
993
|
+
*/
|
|
994
|
+
static get shared() {
|
|
995
|
+
if (!_Courier.instance) {
|
|
996
|
+
_Courier.instance = new _Courier();
|
|
997
|
+
}
|
|
998
|
+
return _Courier.instance;
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Sign in to Courier
|
|
1002
|
+
* @param options - The options for the Courier client
|
|
1003
|
+
*/
|
|
1004
|
+
signIn(props) {
|
|
1005
|
+
const connectionId = props.connectionId ?? UUID.generate();
|
|
1006
|
+
this.instanceClient = new CourierClient({ ...props, connectionId });
|
|
1007
|
+
this.notifyAuthenticationListeners({ userId: props.userId });
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Sign out of Courier
|
|
1011
|
+
*/
|
|
1012
|
+
signOut() {
|
|
1013
|
+
this.instanceClient = void 0;
|
|
1014
|
+
this.notifyAuthenticationListeners({ userId: void 0 });
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Register a callback to be notified of authentication state changes
|
|
1018
|
+
* @param callback - Function to be called when authentication state changes
|
|
1019
|
+
* @returns AuthenticationListener instance that can be used to remove the listener
|
|
1020
|
+
*/
|
|
1021
|
+
addAuthenticationListener(callback) {
|
|
1022
|
+
var _a;
|
|
1023
|
+
(_a = this.instanceClient) == null ? void 0 : _a.options.logger.info("Adding authentication listener");
|
|
1024
|
+
const listener = new AuthenticationListener(callback);
|
|
1025
|
+
this.authenticationListeners.push(listener);
|
|
1026
|
+
return listener;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Unregister an authentication state change listener
|
|
1030
|
+
* @param listener - The AuthenticationListener instance to remove
|
|
1031
|
+
*/
|
|
1032
|
+
removeAuthenticationListener(listener) {
|
|
1033
|
+
var _a;
|
|
1034
|
+
(_a = this.instanceClient) == null ? void 0 : _a.options.logger.info("Removing authentication listener");
|
|
1035
|
+
this.authenticationListeners = this.authenticationListeners.filter((l) => l !== listener);
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Notify all authentication listeners
|
|
1039
|
+
* @param props - The props to notify the listeners with
|
|
1040
|
+
*/
|
|
1041
|
+
notifyAuthenticationListeners(props) {
|
|
1042
|
+
this.authenticationListeners.forEach((listener) => listener.callback(props));
|
|
159
1043
|
}
|
|
160
1044
|
};
|
|
161
|
-
|
|
1045
|
+
/**
|
|
1046
|
+
* The shared Courier instance
|
|
1047
|
+
*/
|
|
1048
|
+
__publicField(_Courier, "instance");
|
|
1049
|
+
let Courier = _Courier;
|
|
162
1050
|
export {
|
|
163
|
-
|
|
1051
|
+
BrandClient,
|
|
1052
|
+
Courier,
|
|
1053
|
+
CourierClient,
|
|
1054
|
+
CourierSocket,
|
|
1055
|
+
InboxClient,
|
|
1056
|
+
ListClient,
|
|
1057
|
+
PreferenceClient,
|
|
1058
|
+
TokenClient
|
|
164
1059
|
};
|