@trycourier/courier-js 2.0.0-beta → 2.0.2-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/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # @trycourier/courier-js
2
+
3
+ The base API client and shared instance singleton for Courier's JavaScript Browser SDK.
4
+
5
+ ## Installation
6
+
7
+ ```ts
8
+ npm i @trycourier/courier-js@2.0.1-beta
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ const courierClient = new CourierClient({
15
+ userId: 'mike',
16
+ jwt: 'ey...n0'
17
+ });
18
+
19
+ // Fetch the inbox messages for the user
20
+ const messages = await courierClient.inbox.getMessages();
21
+ console.log(messages);
22
+ ```
@@ -3,6 +3,8 @@ import { Client } from './client';
3
3
  export declare class BrandClient extends Client {
4
4
  /**
5
5
  * Get a brand by ID using GraphQL
6
+ * @param brandId - The ID of the brand to retrieve
7
+ * @returns Promise resolving to the requested brand
6
8
  */
7
9
  getBrand(props: {
8
10
  brandId: string;
@@ -23,10 +23,9 @@ export interface CourierClientOptions {
23
23
  readonly connectionId?: string;
24
24
  readonly tenantId?: string;
25
25
  readonly showLogs?: boolean;
26
- readonly apiUrls?: CourierApiUrls;
27
26
  readonly accessToken?: string;
28
27
  readonly logger: Logger;
29
- readonly urls: CourierApiUrls;
28
+ readonly apiUrls: CourierApiUrls;
30
29
  }
31
30
  export declare class CourierClient extends Client {
32
31
  readonly tokens: TokenClient;
@@ -7,6 +7,9 @@ export declare class InboxClient extends Client {
7
7
  constructor(options: CourierClientOptions);
8
8
  /**
9
9
  * Get paginated messages
10
+ * @param paginationLimit - Number of messages to return per page (default: 24)
11
+ * @param startCursor - Cursor for pagination
12
+ * @returns Promise resolving to paginated messages response
10
13
  */
11
14
  getMessages(props?: {
12
15
  paginationLimit?: number;
@@ -14,6 +17,9 @@ export declare class InboxClient extends Client {
14
17
  }): Promise<CourierGetInboxMessagesResponse>;
15
18
  /**
16
19
  * Get paginated archived messages
20
+ * @param paginationLimit - Number of messages to return per page (default: 24)
21
+ * @param startCursor - Cursor for pagination
22
+ * @returns Promise resolving to paginated archived messages response
17
23
  */
18
24
  getArchivedMessages(props?: {
19
25
  paginationLimit?: number;
@@ -21,10 +27,14 @@ export declare class InboxClient extends Client {
21
27
  }): Promise<CourierGetInboxMessagesResponse>;
22
28
  /**
23
29
  * Get unread message count
30
+ * @returns Promise resolving to number of unread messages
24
31
  */
25
32
  getUnreadMessageCount(): Promise<number>;
26
33
  /**
27
34
  * Track a click event
35
+ * @param messageId - ID of the message
36
+ * @param trackingId - ID for tracking the click
37
+ * @returns Promise resolving when click is tracked
28
38
  */
29
39
  click(props: {
30
40
  messageId: string;
@@ -32,30 +42,43 @@ export declare class InboxClient extends Client {
32
42
  }): Promise<void>;
33
43
  /**
34
44
  * Mark a message as read
45
+ * @param messageId - ID of the message to mark as read
46
+ * @returns Promise resolving when message is marked as read
35
47
  */
36
48
  read(props: {
37
49
  messageId: string;
38
50
  }): Promise<void>;
39
51
  /**
40
52
  * Mark a message as unread
53
+ * @param messageId - ID of the message to mark as unread
54
+ * @returns Promise resolving when message is marked as unread
41
55
  */
42
56
  unread(props: {
43
57
  messageId: string;
44
58
  }): Promise<void>;
45
59
  /**
46
60
  * Mark all messages as read
61
+ * @returns Promise resolving when all messages are marked as read
47
62
  */
48
63
  readAll(): Promise<void>;
49
64
  /**
50
65
  * Mark a message as opened
66
+ * @param messageId - ID of the message to mark as opened
67
+ * @returns Promise resolving when message is marked as opened
51
68
  */
52
69
  open(props: {
53
70
  messageId: string;
54
71
  }): Promise<void>;
55
72
  /**
56
73
  * Archive a message
74
+ * @param messageId - ID of the message to archive
75
+ * @returns Promise resolving when message is archived
57
76
  */
58
77
  archive(props: {
59
78
  messageId: string;
60
79
  }): Promise<void>;
80
+ /**
81
+ * Archive all read messages.
82
+ */
83
+ archiveRead(): Promise<void>;
61
84
  }
@@ -2,6 +2,8 @@ import { Client } from './client';
2
2
  export declare class ListClient extends Client {
3
3
  /**
4
4
  * Subscribe a user to a list
5
+ * @param listId - The ID of the list to subscribe to
6
+ * @returns Promise resolving when subscription is complete
5
7
  * @see https://www.courier.com/docs/reference/lists/recipient-subscribe
6
8
  */
7
9
  putSubscription(props: {
@@ -9,6 +11,8 @@ export declare class ListClient extends Client {
9
11
  }): Promise<void>;
10
12
  /**
11
13
  * Unsubscribe a user from a list
14
+ * @param listId - The ID of the list to unsubscribe from
15
+ * @returns Promise resolving when unsubscription is complete
12
16
  * @see https://www.courier.com/docs/reference/lists/delete-subscription
13
17
  */
14
18
  deleteSubscription(props: {
@@ -4,23 +4,32 @@ export declare class PreferenceClient extends Client {
4
4
  private transformer;
5
5
  /**
6
6
  * Get all preferences for a user
7
+ * @param paginationCursor - Optional cursor for pagination
8
+ * @returns Promise resolving to user preferences
7
9
  * @see https://www.courier.com/docs/reference/user-preferences/list-all-user-preferences
8
10
  */
9
- getUserPreferences(params?: {
11
+ getUserPreferences(props?: {
10
12
  paginationCursor?: string;
11
13
  }): Promise<CourierUserPreferences>;
12
14
  /**
13
15
  * Get preferences for a specific topic
16
+ * @param topicId - The ID of the topic to get preferences for
17
+ * @returns Promise resolving to topic preferences
14
18
  * @see https://www.courier.com/docs/reference/user-preferences/get-subscription-topic-preferences
15
19
  */
16
- getUserPreferenceTopic(params: {
20
+ getUserPreferenceTopic(props: {
17
21
  topicId: string;
18
22
  }): Promise<CourierUserPreferencesTopic>;
19
23
  /**
20
24
  * Update preferences for a specific topic
25
+ * @param topicId - The ID of the topic to update preferences for
26
+ * @param status - The new status for the topic
27
+ * @param hasCustomRouting - Whether the topic has custom routing
28
+ * @param customRouting - The custom routing channels for the topic
29
+ * @returns Promise resolving when update is complete
21
30
  * @see https://www.courier.com/docs/reference/user-preferences/update-subscription-topic-preferences
22
31
  */
23
- putUserPreferenceTopic(params: {
32
+ putUserPreferenceTopic(props: {
24
33
  topicId: string;
25
34
  status: CourierUserPreferencesStatus;
26
35
  hasCustomRouting: boolean;
@@ -28,10 +37,10 @@ export declare class PreferenceClient extends Client {
28
37
  }): Promise<void>;
29
38
  /**
30
39
  * Get the notification center URL
31
- * @param params
32
- * @returns
40
+ * @param clientKey - The client key to use for the URL
41
+ * @returns The notification center URL
33
42
  */
34
- getNotificationCenterUrl(params: {
43
+ getNotificationCenterUrl(props: {
35
44
  clientKey: string;
36
45
  }): string;
37
46
  }
@@ -3,6 +3,9 @@ import { Client } from './client';
3
3
  export declare class TokenClient extends Client {
4
4
  /**
5
5
  * Store a push notification token for a user
6
+ * @param token - The push notification token
7
+ * @param provider - The provider of the token
8
+ * @param device - The device information
6
9
  * @see https://www.courier.com/docs/reference/token-management/put-token
7
10
  */
8
11
  putUserToken(props: {
@@ -12,6 +15,8 @@ export declare class TokenClient extends Client {
12
15
  }): Promise<void>;
13
16
  /**
14
17
  * Delete a push notification token for a user
18
+ * @param token - The push notification token
19
+ * @returns Promise resolving when token is deleted
15
20
  */
16
21
  deleteUserToken(props: {
17
22
  token: string;
@@ -3,6 +3,11 @@ import { Client } from './client';
3
3
  export declare class TrackingClient extends Client {
4
4
  /**
5
5
  * Post an inbound courier event
6
+ * @param event - The event type: Example: "New Order Placed"
7
+ * @param messageId - The message ID
8
+ * @param type - The type of event: Available options: "track"
9
+ * @param properties - The properties of the event
10
+ * @returns Promise resolving to the message ID
6
11
  * @see https://www.courier.com/docs/reference/inbound/courier-track-event
7
12
  */
8
13
  postInboundCourier(props: {
@@ -16,6 +21,9 @@ export declare class TrackingClient extends Client {
16
21
  /**
17
22
  * Post a tracking URL event
18
23
  * These urls are found in messages sent from Courier
24
+ * @param url - The URL to post the event to
25
+ * @param event - The event type: Available options: "click", "open", "unsubscribe"
26
+ * @returns Promise resolving when the event is posted
19
27
  */
20
28
  postTrackingUrl(props: {
21
29
  url: string;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).CourierJS={})}(this,(function(t){"use strict";var e=Object.defineProperty,s=(t,s,n)=>((t,s,n)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[s]=n)(t,"symbol"!=typeof s?s+"":s,n);const n=class t{constructor(t,e){s(this,"webSocket",null),s(this,"pingInterval",null),s(this,"onOpen"),s(this,"onMessageReceived"),s(this,"onClose"),s(this,"onError"),s(this,"url"),s(this,"options"),this.url=t,this.options=e}get isConnected(){return null!==this.webSocket}async connect(){return this.disconnect(),new Promise(((t,e)=>{try{this.webSocket=new WebSocket(this.url),this.webSocket.onopen=()=>{var e;null==(e=this.onOpen)||e.call(this),t()},this.webSocket.onmessage=t=>{var e;null==(e=this.onMessageReceived)||e.call(this,t.data)},this.webSocket.onclose=t=>{var e;this.webSocket=null,null==(e=this.onClose)||e.call(this,t.code,t.reason)},this.webSocket.onerror=t=>{var s;this.webSocket=null;const n=new Error("Courier Socket connection failed");n.originalEvent=t,null==(s=this.onError)||s.call(this,n),e(n)}}catch(s){this.webSocket=null,e(s)}}))}disconnect(){this.stopPing(),this.webSocket&&(this.webSocket.close(t.NORMAL_CLOSURE_STATUS),this.webSocket=null)}async send(t){if(!this.webSocket)return!1;const e=JSON.stringify(t);return void 0!==this.webSocket.send(e)}keepAlive(t){this.stopPing(),this.pingInterval=setInterval((async()=>{var t;try{await this.send({action:"keepAlive"})}catch(e){null==(t=this.options.logger)||t.error("Error occurred on Keep Alive:",e)}}),(null==t?void 0:t.intervalInMillis)??3e5)}stopPing(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}};s(n,"NORMAL_CLOSURE_STATUS",1e3);let o=n;const i=t=>({courier:{rest:(null==t?void 0:t.courier.rest)||"https://api.courier.com",graphql:(null==t?void 0:t.courier.graphql)||"https://api.courier.com/client/q"},inbox:{graphql:(null==t?void 0:t.inbox.graphql)||"https://inbox.courier.com/q",webSocket:(null==t?void 0:t.inbox.webSocket)||"wss://realtime.courier.com"}});class r{constructor(t){s(this,"PREFIX","[COURIER]"),this.showLogs=t}warn(t,...e){this.showLogs&&console.warn(`${this.PREFIX} ${t}`,...e)}log(t,...e){this.showLogs&&console.log(`${this.PREFIX} ${t}`,...e)}error(t,...e){this.showLogs&&console.error(`${this.PREFIX} ${t}`,...e)}debug(t,...e){this.showLogs&&console.debug(`${this.PREFIX} ${t}`,...e)}info(t,...e){this.showLogs&&console.info(`${this.PREFIX} ${t}`,...e)}}class a{static generate(t){const e=Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15);return t?t+e:e}}class c extends Error{constructor(t,e,s){super(e),this.code=t,this.type=s,this.name="CourierRequestError"}}function u(t,e,s,n){t.log(`\n📡 New Courier ${s} Request: ${e}\nURL: ${n.url}\n${n.method?`Method: ${n.method}`:""}\n${n.query?`Query: ${n.query}`:""}\n${n.variables?`Variables: ${JSON.stringify(n.variables,null,2)}`:""}\nHeaders: ${JSON.stringify(n.headers,null,2)}\nBody: ${n.body?JSON.stringify(n.body,null,2):"Empty"}\n `)}function h(t,e,s,n){t.log(`\n📡 New Courier ${s} Response: ${e}\nStatus Code: ${n.status}\nResponse JSON: ${JSON.stringify(n.response,null,2)}\n `)}async function l(t){const e=t.validCodes??[200],s=t.options.showLogs?a.generate():void 0,n=new Request(t.url,{method:t.method,headers:{"Content-Type":"application/json",...t.headers},body:t.body?JSON.stringify(t.body):void 0});s&&u(t.options.logger,s,"HTTP",{url:n.url,method:n.method,headers:Object.fromEntries(n.headers.entries()),body:t.body});const o=await fetch(n);if(204===o.status)return;let i;try{i=await o.json()}catch(r){if(200===o.status)return;throw new c(o.status,"Failed to parse response as JSON","PARSE_ERROR")}if(s&&h(t.options.logger,s,"HTTP",{status:o.status,response:i}),!e.includes(o.status))throw new c(o.status,(null==i?void 0:i.message)||"Unknown Error",null==i?void 0:i.type);return i}async function d(t){const e=t.options.showLogs?a.generate():void 0;e&&u(t.options.logger,e,"GraphQL",{url:t.url,headers:t.headers,query:t.query,variables:t.variables});const s=await fetch(t.url,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify({query:t.query,variables:t.variables})});let n;try{n=await s.json()}catch(o){throw new c(s.status,"Failed to parse response as JSON","PARSE_ERROR")}if(e&&h(t.options.logger,e,"GraphQL",{status:s.status,response:n}),!s.ok)throw new c(s.status,(null==n?void 0:n.message)||"Unknown Error",null==n?void 0:n.type);return n}class p{constructor(t){this.options=t}}class g extends p{async getBrand(t){const e=`\n query GetBrand {\n brand(brandId: "${t.brandId}") {\n settings {\n colors {\n primary\n secondary\n tertiary\n }\n inapp {\n borderRadius\n disableCourierFooter\n }\n }\n }\n }\n `;return(await d({options:this.options,url:this.options.urls.courier.graphql,headers:{"x-courier-user-id":this.options.userId,"x-courier-client-key":"empty",Authorization:`Bearer ${this.options.accessToken}`},query:e,variables:{brandId:t.brandId}})).data.brand}}class m extends o{constructor(t){super(m.buildUrl(t),t),s(this,"receivedMessage"),s(this,"receivedMessageEvent"),this.onMessageReceived=t=>this.convertToType(t)}convertToType(t){var e,s,n,o;try{switch(JSON.parse(t).type){case"event":const n=JSON.parse(t);null==(e=this.receivedMessageEvent)||e.call(this,n);break;case"message":const o=JSON.parse(t);null==(s=this.receivedMessage)||s.call(this,o)}}catch(i){null==(n=this.options.logger)||n.error("Error parsing socket message",i),i instanceof Error&&(null==(o=this.onError)||o.call(this,i))}}async sendSubscribe(t){var e;const s={action:"subscribe",data:{userAgent:"courier-js",channel:this.options.userId,event:"*",version:(null==t?void 0:t.version)??5}};this.options.connectionId&&(s.data.clientSourceId=this.options.connectionId),this.options.tenantId&&(s.data.accountId=this.options.tenantId),null==(e=this.options.logger)||e.debug("Sending subscribe request",s),await this.send(s)}static buildUrl(t){var e;let s=(null==(e=t.apiUrls)?void 0:e.inbox.webSocket)??"";return t.accessToken&&(s+=`/?auth=${t.accessToken}`),s}}class I extends p{constructor(t){super(t),s(this,"socket"),this.socket=new m(t)}async getMessages(t){const e=`\n query GetInboxMessages(\n $params: FilterParamsInput = { ${this.options.tenantId?`accountId: "${this.options.tenantId}"`:""} }\n $limit: Int = ${(null==t?void 0:t.paginationLimit)??24}\n $after: String ${(null==t?void 0:t.startCursor)?`= "${t.startCursor}"`:""}\n ) {\n count(params: $params)\n messages(params: $params, limit: $limit, after: $after) {\n totalCount\n pageInfo {\n startCursor\n hasNextPage\n }\n nodes {\n messageId\n read\n archived\n created\n opened\n title\n preview\n data\n tags\n trackingIds {\n clickTrackingId\n }\n actions {\n content\n data\n href\n }\n }\n }\n }\n `;return await d({options:this.options,query:e,headers:{"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`},url:this.options.urls.inbox.graphql})}async getArchivedMessages(t){const e=`\n query GetInboxMessages(\n $params: FilterParamsInput = { ${this.options.tenantId?`accountId: "${this.options.tenantId}"`:""}, archived: true }\n $limit: Int = ${(null==t?void 0:t.paginationLimit)??24}\n $after: String ${(null==t?void 0:t.startCursor)?`= "${t.startCursor}"`:""}\n ) {\n count(params: $params)\n messages(params: $params, limit: $limit, after: $after) {\n totalCount\n pageInfo {\n startCursor\n hasNextPage\n }\n nodes {\n messageId\n read\n archived\n created\n opened\n title\n preview\n data\n tags\n trackingIds {\n clickTrackingId\n }\n actions {\n content\n data\n href\n }\n }\n }\n }\n `;return d({options:this.options,query:e,headers:{"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`},url:this.options.urls.inbox.graphql})}async getUnreadMessageCount(){var t;const e=`\n query GetMessages {\n count(params: { status: "unread" ${this.options.tenantId?`, accountId: "${this.options.tenantId}"`:""} })\n }\n `;return(null==(t=(await d({options:this.options,query:e,headers:{"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`},url:this.options.urls.inbox.graphql})).data)?void 0:t.count)??0}async click(t){const e=`\n mutation TrackEvent {\n clicked(messageId: "${t.messageId}", trackingId: "${t.trackingId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.urls.inbox.graphql})}async read(t){const e=`\n mutation TrackEvent {\n read(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.urls.inbox.graphql})}async unread(t){const e=`\n mutation TrackEvent {\n unread(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.urls.inbox.graphql})}async readAll(){const t={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(t["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:"\n mutation TrackEvent {\n markAllRead\n }\n ",headers:t,url:this.options.urls.inbox.graphql})}async open(t){const e=`\n mutation TrackEvent {\n opened(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.urls.inbox.graphql})}async archive(t){const e=`\n mutation TrackEvent {\n archive(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.urls.inbox.graphql})}}class b{transformItem(t){return{topicId:t.topic_id,topicName:t.topic_name,sectionId:t.section_id,sectionName:t.section_name,status:t.status,defaultStatus:t.default_status,hasCustomRouting:t.has_custom_routing,customRouting:t.custom_routing||[]}}*transform(t){for(const e of t)yield this.transformItem(e)}}class v extends p{constructor(){super(...arguments),s(this,"transformer",new b)}async getUserPreferences(t){let e=`${this.options.urls.courier.rest}/users/${this.options.userId}/preferences`;(null==t?void 0:t.paginationCursor)&&(e+=`?cursor=${t.paginationCursor}`);const s=await l({options:this.options,url:e,method:"GET",headers:{Authorization:`Bearer ${this.options.accessToken}`}});return{items:[...this.transformer.transform(s.items)],paging:s.paging}}async getUserPreferenceTopic(t){const e=await l({options:this.options,url:`${this.options.urls.courier.rest}/users/${this.options.userId}/preferences/${t.topicId}`,method:"GET",headers:{Authorization:`Bearer ${this.options.accessToken}`}});return this.transformer.transformItem(e.topic)}async putUserPreferenceTopic(t){const e={topic:{status:t.status,has_custom_routing:t.hasCustomRouting,custom_routing:t.customRouting}};await l({options:this.options,url:`${this.options.urls.courier.rest}/users/${this.options.userId}/preferences/${t.topicId}`,method:"PUT",headers:{Authorization:`Bearer ${this.options.accessToken}`},body:e})}getNotificationCenterUrl(t){return`https://view.notificationcenter.app/p/${function(t){const e=new Uint8Array(t.length);for(let s=0;s<t.length;s++)e[s]=t.charCodeAt(s);return btoa(String.fromCharCode(...e))}(`${function(t){const e=atob(t),s=new Uint8Array(e.length);for(let n=0;n<e.length;n++)s[n]=e.charCodeAt(n);return String.fromCharCode(...s)}(t.clientKey)}#${this.options.userId}${this.options.tenantId?`#${this.options.tenantId}`:""}#false`)}`}}class y extends p{async putUserToken(t){const e={provider_key:t.provider,...t.device&&{device:{app_id:t.device.appId,ad_id:t.device.adId,device_id:t.device.deviceId,platform:t.device.platform,manufacturer:t.device.manufacturer,model:t.device.model}}};await l({options:this.options,url:`${this.options.urls.courier.rest}/users/${this.options.userId}/tokens/${t.token}`,method:"PUT",headers:{Authorization:`Bearer ${this.options.accessToken}`},body:e,validCodes:[200,204]})}async deleteUserToken(t){await l({options:this.options,url:`${this.options.urls.courier.rest}/users/${this.options.userId}/tokens/${t.token}`,method:"DELETE",headers:{Authorization:`Bearer ${this.options.accessToken}`},validCodes:[200,204]})}}class w extends p{async putSubscription(t){return await l({url:`${this.options.urls.courier.rest}/lists/${t.listId}/subscriptions/${this.options.userId}`,options:this.options,method:"PUT",headers:{Authorization:`Bearer ${this.options.accessToken}`}})}async deleteSubscription(t){return await l({url:`${this.options.urls.courier.rest}/lists/${t.listId}/subscriptions/${this.options.userId}`,options:this.options,method:"DELETE",headers:{Authorization:`Bearer ${this.options.accessToken}`}})}}class $ extends p{async postInboundCourier(t){return await l({url:`${this.options.urls.courier.rest}/inbound/courier`,options:this.options,method:"POST",headers:{Authorization:`Bearer ${this.options.accessToken}`},body:{...t,userId:this.options.userId},validCodes:[200,202]})}async postTrackingUrl(t){return await l({url:t.url,options:this.options,method:"POST",body:{event:t.event}})}}class f extends p{constructor(t){var e,n;const o=void 0!==t.showLogs?t.showLogs:"development"===process.env.NODE_ENV,a={...t,showLogs:o,apiUrls:t.apiUrls||i(),accessToken:t.jwt??t.publicApiKey};super({...a,logger:new r(a.showLogs),urls:i(a.apiUrls)}),s(this,"tokens"),s(this,"brands"),s(this,"preferences"),s(this,"inbox"),s(this,"lists"),s(this,"tracking"),this.tokens=new y(this.options),this.brands=new g(this.options),this.preferences=new v(this.options),this.inbox=new I(this.options),this.lists=new w(this.options),this.tracking=new $(this.options),this.options.jwt||this.options.publicApiKey||this.options.logger.warn("Courier Client initialized with no authentication method. Please provide a JWT or public API key."),this.options.publicApiKey&&(null==(e=this.options.logger)||e.warn("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.")),this.options.jwt&&this.options.publicApiKey&&(null==(n=this.options.logger)||n.warn("Courier Warning: Both a JWT and a Public API Key were provided. The Public API Key will be ignored."))}}class k{constructor(t){s(this,"callback"),this.callback=t}remove(){S.shared.removeAuthenticationListener(this)}}const T=class t{constructor(){s(this,"id",a.generate()),s(this,"instanceClient"),s(this,"_paginationLimit",24),s(this,"authenticationListeners",[])}get paginationLimit(){return this._paginationLimit}set paginationLimit(t){this._paginationLimit=Math.min(Math.max(t,1),100)}get client(){return this.instanceClient}static get shared(){return t.instance||(t.instance=new t),t.instance}signIn(t){const e=t.connectionId??a.generate();this.instanceClient=new f({...t,connectionId:e}),this.notifyAuthenticationListeners({userId:t.userId})}signOut(){this.instanceClient=void 0,this.notifyAuthenticationListeners({userId:void 0})}addAuthenticationListener(t){var e;null==(e=this.instanceClient)||e.options.logger.info("Adding authentication listener");const s=new k(t);return this.authenticationListeners.push(s),s}removeAuthenticationListener(t){var e;null==(e=this.instanceClient)||e.options.logger.info("Removing authentication listener"),this.authenticationListeners=this.authenticationListeners.filter((e=>e!==t))}notifyAuthenticationListeners(t){this.authenticationListeners.forEach((e=>e.callback(t)))}};s(T,"instance");let S=T;t.BrandClient=g,t.Courier=S,t.CourierClient=f,t.CourierSocket=o,t.InboxClient=I,t.ListClient=w,t.PreferenceClient=v,t.TokenClient=y,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})}));
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).CourierJS={})}(this,(function(t){"use strict";var e=Object.defineProperty,s=(t,s,n)=>((t,s,n)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[s]=n)(t,"symbol"!=typeof s?s+"":s,n);const n=class t{constructor(t,e){s(this,"webSocket",null),s(this,"pingInterval",null),s(this,"onOpen"),s(this,"onMessageReceived"),s(this,"onClose"),s(this,"onError"),s(this,"url"),s(this,"options"),this.url=t,this.options=e}get isConnected(){return null!==this.webSocket}async connect(){return this.disconnect(),new Promise(((t,e)=>{try{this.webSocket=new WebSocket(this.url),this.webSocket.onopen=()=>{var e;null==(e=this.onOpen)||e.call(this),t()},this.webSocket.onmessage=t=>{var e;null==(e=this.onMessageReceived)||e.call(this,t.data)},this.webSocket.onclose=t=>{var e;this.webSocket=null,null==(e=this.onClose)||e.call(this,t.code,t.reason)},this.webSocket.onerror=t=>{var s;this.webSocket=null;const n=new Error("Courier Socket connection failed");n.originalEvent=t,null==(s=this.onError)||s.call(this,n),e(n)}}catch(s){this.webSocket=null,e(s)}}))}disconnect(){this.stopPing(),this.webSocket&&(this.webSocket.close(t.NORMAL_CLOSURE_STATUS),this.webSocket=null)}async send(t){if(!this.webSocket)return!1;const e=JSON.stringify(t);return void 0!==this.webSocket.send(e)}keepAlive(t){this.stopPing(),this.pingInterval=setInterval((async()=>{var t;try{await this.send({action:"keepAlive"})}catch(e){null==(t=this.options.logger)||t.error("Error occurred on Keep Alive:",e)}}),(null==t?void 0:t.intervalInMillis)??3e5)}stopPing(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null)}};s(n,"NORMAL_CLOSURE_STATUS",1e3);let i=n;const o=t=>({courier:{rest:(null==t?void 0:t.courier.rest)||"https://api.courier.com",graphql:(null==t?void 0:t.courier.graphql)||"https://api.courier.com/client/q"},inbox:{graphql:(null==t?void 0:t.inbox.graphql)||"https://inbox.courier.com/q",webSocket:(null==t?void 0:t.inbox.webSocket)||"wss://realtime.courier.com"}});class r{constructor(t){s(this,"PREFIX","[COURIER]"),this.showLogs=t}warn(t,...e){this.showLogs&&console.warn(`${this.PREFIX} ${t}`,...e)}log(t,...e){this.showLogs&&console.log(`${this.PREFIX} ${t}`,...e)}error(t,...e){this.showLogs&&console.error(`${this.PREFIX} ${t}`,...e)}debug(t,...e){this.showLogs&&console.debug(`${this.PREFIX} ${t}`,...e)}info(t,...e){this.showLogs&&console.info(`${this.PREFIX} ${t}`,...e)}}class a{static generate(t){const e=Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15);return t?t+e:e}}class c extends Error{constructor(t,e,s){super(e),this.code=t,this.type=s,this.name="CourierRequestError"}}function u(t,e,s,n){t.log(`\n📡 New Courier ${s} Request: ${e}\nURL: ${n.url}\n${n.method?`Method: ${n.method}`:""}\n${n.query?`Query: ${n.query}`:""}\n${n.variables?`Variables: ${JSON.stringify(n.variables,null,2)}`:""}\nHeaders: ${JSON.stringify(n.headers,null,2)}\nBody: ${n.body?JSON.stringify(n.body,null,2):"Empty"}\n `)}function h(t,e,s,n){t.log(`\n📡 New Courier ${s} Response: ${e}\nStatus Code: ${n.status}\nResponse JSON: ${JSON.stringify(n.response,null,2)}\n `)}async function l(t){const e=t.validCodes??[200],s=t.options.showLogs?a.generate():void 0,n=new Request(t.url,{method:t.method,headers:{"Content-Type":"application/json",...t.headers},body:t.body?JSON.stringify(t.body):void 0});s&&u(t.options.logger,s,"HTTP",{url:n.url,method:n.method,headers:Object.fromEntries(n.headers.entries()),body:t.body});const i=await fetch(n);if(204===i.status)return;let o;try{o=await i.json()}catch(r){if(200===i.status)return;throw new c(i.status,"Failed to parse response as JSON","PARSE_ERROR")}if(s&&h(t.options.logger,s,"HTTP",{status:i.status,response:o}),!e.includes(i.status))throw new c(i.status,(null==o?void 0:o.message)||"Unknown Error",null==o?void 0:o.type);return o}async function d(t){const e=t.options.showLogs?a.generate():void 0;e&&u(t.options.logger,e,"GraphQL",{url:t.url,headers:t.headers,query:t.query,variables:t.variables});const s=await fetch(t.url,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify({query:t.query,variables:t.variables})});let n;try{n=await s.json()}catch(i){throw new c(s.status,"Failed to parse response as JSON","PARSE_ERROR")}if(e&&h(t.options.logger,e,"GraphQL",{status:s.status,response:n}),!s.ok)throw new c(s.status,(null==n?void 0:n.message)||"Unknown Error",null==n?void 0:n.type);return n}class p{constructor(t){this.options=t}}class g extends p{async getBrand(t){const e=`\n query GetBrand {\n brand(brandId: "${t.brandId}") {\n settings {\n colors {\n primary\n secondary\n tertiary\n }\n inapp {\n borderRadius\n disableCourierFooter\n }\n }\n }\n }\n `;return(await d({options:this.options,url:this.options.apiUrls.courier.graphql,headers:{"x-courier-user-id":this.options.userId,"x-courier-client-key":"empty",Authorization:`Bearer ${this.options.accessToken}`},query:e,variables:{brandId:t.brandId}})).data.brand}}class m extends i{constructor(t){super(m.buildUrl(t),t),s(this,"receivedMessage"),s(this,"receivedMessageEvent"),this.onMessageReceived=t=>this.convertToType(t)}convertToType(t){var e,s,n,i;try{switch(JSON.parse(t).type){case"event":const n=JSON.parse(t);null==(e=this.receivedMessageEvent)||e.call(this,n);break;case"message":const i=JSON.parse(t);null==(s=this.receivedMessage)||s.call(this,i)}}catch(o){null==(n=this.options.logger)||n.error("Error parsing socket message",o),o instanceof Error&&(null==(i=this.onError)||i.call(this,o))}}async sendSubscribe(t){var e;const s={action:"subscribe",data:{userAgent:"courier-js",channel:this.options.userId,event:"*",version:(null==t?void 0:t.version)??5}};this.options.connectionId&&(s.data.clientSourceId=this.options.connectionId),this.options.tenantId&&(s.data.accountId=this.options.tenantId),null==(e=this.options.logger)||e.debug("Sending subscribe request",s),await this.send(s)}static buildUrl(t){var e;let s=(null==(e=t.apiUrls)?void 0:e.inbox.webSocket)??"";return t.accessToken&&(s+=`/?auth=${t.accessToken}`),s}}class I extends p{constructor(t){super(t),s(this,"socket"),this.socket=new m(t)}async getMessages(t){const e=`\n query GetInboxMessages(\n $params: FilterParamsInput = { ${this.options.tenantId?`accountId: "${this.options.tenantId}"`:""} }\n $limit: Int = ${(null==t?void 0:t.paginationLimit)??24}\n $after: String ${(null==t?void 0:t.startCursor)?`= "${t.startCursor}"`:""}\n ) {\n count(params: $params)\n messages(params: $params, limit: $limit, after: $after) {\n totalCount\n pageInfo {\n startCursor\n hasNextPage\n }\n nodes {\n messageId\n read\n archived\n created\n opened\n title\n preview\n data\n tags\n trackingIds {\n clickTrackingId\n }\n actions {\n content\n data\n href\n }\n }\n }\n }\n `;return await d({options:this.options,query:e,headers:{"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`},url:this.options.apiUrls.inbox.graphql})}async getArchivedMessages(t){const e=`\n query GetInboxMessages(\n $params: FilterParamsInput = { ${this.options.tenantId?`accountId: "${this.options.tenantId}"`:""}, archived: true }\n $limit: Int = ${(null==t?void 0:t.paginationLimit)??24}\n $after: String ${(null==t?void 0:t.startCursor)?`= "${t.startCursor}"`:""}\n ) {\n count(params: $params)\n messages(params: $params, limit: $limit, after: $after) {\n totalCount\n pageInfo {\n startCursor\n hasNextPage\n }\n nodes {\n messageId\n read\n archived\n created\n opened\n title\n preview\n data\n tags\n trackingIds {\n clickTrackingId\n }\n actions {\n content\n data\n href\n }\n }\n }\n }\n `;return d({options:this.options,query:e,headers:{"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`},url:this.options.apiUrls.inbox.graphql})}async getUnreadMessageCount(){var t;const e=`\n query GetMessages {\n count(params: { status: "unread" ${this.options.tenantId?`, accountId: "${this.options.tenantId}"`:""} })\n }\n `;return(null==(t=(await d({options:this.options,query:e,headers:{"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`},url:this.options.apiUrls.inbox.graphql})).data)?void 0:t.count)??0}async click(t){const e=`\n mutation TrackEvent {\n clicked(messageId: "${t.messageId}", trackingId: "${t.trackingId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.apiUrls.inbox.graphql})}async read(t){const e=`\n mutation TrackEvent {\n read(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.apiUrls.inbox.graphql})}async unread(t){const e=`\n mutation TrackEvent {\n unread(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.apiUrls.inbox.graphql})}async readAll(){const t={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(t["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:"\n mutation TrackEvent {\n markAllRead\n }\n ",headers:t,url:this.options.apiUrls.inbox.graphql})}async open(t){const e=`\n mutation TrackEvent {\n opened(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.apiUrls.inbox.graphql})}async archive(t){const e=`\n mutation TrackEvent {\n archive(messageId: "${t.messageId}")\n }\n `,s={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(s["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:e,headers:s,url:this.options.apiUrls.inbox.graphql})}async archiveRead(){const t={"x-courier-user-id":this.options.userId,Authorization:`Bearer ${this.options.accessToken}`};this.options.connectionId&&(t["x-courier-client-source-id"]=this.options.connectionId),await d({options:this.options,query:"\n mutation TrackEvent {\n archiveRead\n }\n ",headers:t,url:this.options.apiUrls.inbox.graphql})}}class v{transformItem(t){return{topicId:t.topic_id,topicName:t.topic_name,sectionId:t.section_id,sectionName:t.section_name,status:t.status,defaultStatus:t.default_status,hasCustomRouting:t.has_custom_routing,customRouting:t.custom_routing||[]}}*transform(t){for(const e of t)yield this.transformItem(e)}}class b extends p{constructor(){super(...arguments),s(this,"transformer",new v)}async getUserPreferences(t){let e=`${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences`;(null==t?void 0:t.paginationCursor)&&(e+=`?cursor=${t.paginationCursor}`);const s=await l({options:this.options,url:e,method:"GET",headers:{Authorization:`Bearer ${this.options.accessToken}`}});return{items:[...this.transformer.transform(s.items)],paging:s.paging}}async getUserPreferenceTopic(t){const e=await l({options:this.options,url:`${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences/${t.topicId}`,method:"GET",headers:{Authorization:`Bearer ${this.options.accessToken}`}});return this.transformer.transformItem(e.topic)}async putUserPreferenceTopic(t){const e={topic:{status:t.status,has_custom_routing:t.hasCustomRouting,custom_routing:t.customRouting}};await l({options:this.options,url:`${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences/${t.topicId}`,method:"PUT",headers:{Authorization:`Bearer ${this.options.accessToken}`},body:e})}getNotificationCenterUrl(t){return`https://view.notificationcenter.app/p/${function(t){const e=new Uint8Array(t.length);for(let s=0;s<t.length;s++)e[s]=t.charCodeAt(s);return btoa(String.fromCharCode(...e))}(`${function(t){const e=atob(t),s=new Uint8Array(e.length);for(let n=0;n<e.length;n++)s[n]=e.charCodeAt(n);return String.fromCharCode(...s)}(t.clientKey)}#${this.options.userId}${this.options.tenantId?`#${this.options.tenantId}`:""}#false`)}`}}class y extends p{async putUserToken(t){const e={provider_key:t.provider,...t.device&&{device:{app_id:t.device.appId,ad_id:t.device.adId,device_id:t.device.deviceId,platform:t.device.platform,manufacturer:t.device.manufacturer,model:t.device.model}}};await l({options:this.options,url:`${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${t.token}`,method:"PUT",headers:{Authorization:`Bearer ${this.options.accessToken}`},body:e,validCodes:[200,204]})}async deleteUserToken(t){await l({options:this.options,url:`${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${t.token}`,method:"DELETE",headers:{Authorization:`Bearer ${this.options.accessToken}`},validCodes:[200,204]})}}class w extends p{async putSubscription(t){return await l({url:`${this.options.apiUrls.courier.rest}/lists/${t.listId}/subscriptions/${this.options.userId}`,options:this.options,method:"PUT",headers:{Authorization:`Bearer ${this.options.accessToken}`}})}async deleteSubscription(t){return await l({url:`${this.options.apiUrls.courier.rest}/lists/${t.listId}/subscriptions/${this.options.userId}`,options:this.options,method:"DELETE",headers:{Authorization:`Bearer ${this.options.accessToken}`}})}}class $ extends p{async postInboundCourier(t){return await l({url:`${this.options.apiUrls.courier.rest}/inbound/courier`,options:this.options,method:"POST",headers:{Authorization:`Bearer ${this.options.accessToken}`},body:{...t,userId:this.options.userId},validCodes:[200,202]})}async postTrackingUrl(t){return await l({url:t.url,options:this.options,method:"POST",body:{event:t.event}})}}class f extends p{constructor(t){var e,n;const i=void 0!==t.showLogs?t.showLogs:"development"===process.env.NODE_ENV,a={...t,showLogs:i,apiUrls:t.apiUrls||o(),accessToken:t.jwt??t.publicApiKey};super({...a,logger:new r(a.showLogs),apiUrls:o(a.apiUrls)}),s(this,"tokens"),s(this,"brands"),s(this,"preferences"),s(this,"inbox"),s(this,"lists"),s(this,"tracking"),this.tokens=new y(this.options),this.brands=new g(this.options),this.preferences=new b(this.options),this.inbox=new I(this.options),this.lists=new w(this.options),this.tracking=new $(this.options),this.options.jwt||this.options.publicApiKey||this.options.logger.warn("Courier Client initialized with no authentication method. Please provide a JWT or public API key."),this.options.publicApiKey&&(null==(e=this.options.logger)||e.warn("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.")),this.options.jwt&&this.options.publicApiKey&&(null==(n=this.options.logger)||n.warn("Courier Warning: Both a JWT and a Public API Key were provided. The Public API Key will be ignored."))}}class k{constructor(t){s(this,"callback"),this.callback=t}remove(){S.shared.removeAuthenticationListener(this)}}const T=class t{constructor(){s(this,"id",a.generate()),s(this,"instanceClient"),s(this,"_paginationLimit",24),s(this,"authenticationListeners",[])}get paginationLimit(){return this._paginationLimit}set paginationLimit(t){this._paginationLimit=Math.min(Math.max(t,1),100)}get client(){return this.instanceClient}static get shared(){return t.instance||(t.instance=new t),t.instance}signIn(t){const e=t.connectionId??a.generate();this.instanceClient=new f({...t,connectionId:e}),this.notifyAuthenticationListeners({userId:t.userId})}signOut(){this.instanceClient=void 0,this.notifyAuthenticationListeners({userId:void 0})}addAuthenticationListener(t){var e;null==(e=this.instanceClient)||e.options.logger.info("Adding authentication listener");const s=new k(t);return this.authenticationListeners.push(s),s}removeAuthenticationListener(t){var e;null==(e=this.instanceClient)||e.options.logger.info("Removing authentication listener"),this.authenticationListeners=this.authenticationListeners.filter((e=>e!==t))}notifyAuthenticationListeners(t){this.authenticationListeners.forEach((e=>e.callback(t)))}};s(T,"instance");let S=T;t.BrandClient=g,t.Courier=S,t.CourierClient=f,t.CourierSocket=i,t.InboxClient=I,t.ListClient=w,t.PreferenceClient=b,t.TokenClient=y,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})}));
package/dist/index.mjs CHANGED
@@ -269,6 +269,8 @@ class Client {
269
269
  class BrandClient extends Client {
270
270
  /**
271
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
272
274
  */
273
275
  async getBrand(props) {
274
276
  const query = `
@@ -290,7 +292,7 @@ class BrandClient extends Client {
290
292
  `;
291
293
  const json = await graphql({
292
294
  options: this.options,
293
- url: this.options.urls.courier.graphql,
295
+ url: this.options.apiUrls.courier.graphql,
294
296
  headers: {
295
297
  "x-courier-user-id": this.options.userId,
296
298
  "x-courier-client-key": "empty",
@@ -370,6 +372,9 @@ class InboxClient extends Client {
370
372
  }
371
373
  /**
372
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
373
378
  */
374
379
  async getMessages(props) {
375
380
  const query = `
@@ -414,11 +419,14 @@ class InboxClient extends Client {
414
419
  "x-courier-user-id": this.options.userId,
415
420
  "Authorization": `Bearer ${this.options.accessToken}`
416
421
  },
417
- url: this.options.urls.inbox.graphql
422
+ url: this.options.apiUrls.inbox.graphql
418
423
  });
419
424
  }
420
425
  /**
421
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
422
430
  */
423
431
  async getArchivedMessages(props) {
424
432
  const query = `
@@ -463,11 +471,12 @@ class InboxClient extends Client {
463
471
  "x-courier-user-id": this.options.userId,
464
472
  "Authorization": `Bearer ${this.options.accessToken}`
465
473
  },
466
- url: this.options.urls.inbox.graphql
474
+ url: this.options.apiUrls.inbox.graphql
467
475
  });
468
476
  }
469
477
  /**
470
478
  * Get unread message count
479
+ * @returns Promise resolving to number of unread messages
471
480
  */
472
481
  async getUnreadMessageCount() {
473
482
  var _a;
@@ -483,12 +492,15 @@ class InboxClient extends Client {
483
492
  "x-courier-user-id": this.options.userId,
484
493
  "Authorization": `Bearer ${this.options.accessToken}`
485
494
  },
486
- url: this.options.urls.inbox.graphql
495
+ url: this.options.apiUrls.inbox.graphql
487
496
  });
488
497
  return ((_a = response.data) == null ? void 0 : _a.count) ?? 0;
489
498
  }
490
499
  /**
491
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
492
504
  */
493
505
  async click(props) {
494
506
  const query = `
@@ -507,11 +519,13 @@ class InboxClient extends Client {
507
519
  options: this.options,
508
520
  query,
509
521
  headers,
510
- url: this.options.urls.inbox.graphql
522
+ url: this.options.apiUrls.inbox.graphql
511
523
  });
512
524
  }
513
525
  /**
514
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
515
529
  */
516
530
  async read(props) {
517
531
  const query = `
@@ -530,11 +544,13 @@ class InboxClient extends Client {
530
544
  options: this.options,
531
545
  query,
532
546
  headers,
533
- url: this.options.urls.inbox.graphql
547
+ url: this.options.apiUrls.inbox.graphql
534
548
  });
535
549
  }
536
550
  /**
537
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
538
554
  */
539
555
  async unread(props) {
540
556
  const query = `
@@ -553,11 +569,12 @@ class InboxClient extends Client {
553
569
  options: this.options,
554
570
  query,
555
571
  headers,
556
- url: this.options.urls.inbox.graphql
572
+ url: this.options.apiUrls.inbox.graphql
557
573
  });
558
574
  }
559
575
  /**
560
576
  * Mark all messages as read
577
+ * @returns Promise resolving when all messages are marked as read
561
578
  */
562
579
  async readAll() {
563
580
  const query = `
@@ -576,11 +593,13 @@ class InboxClient extends Client {
576
593
  options: this.options,
577
594
  query,
578
595
  headers,
579
- url: this.options.urls.inbox.graphql
596
+ url: this.options.apiUrls.inbox.graphql
580
597
  });
581
598
  }
582
599
  /**
583
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
584
603
  */
585
604
  async open(props) {
586
605
  const query = `
@@ -599,11 +618,13 @@ class InboxClient extends Client {
599
618
  options: this.options,
600
619
  query,
601
620
  headers,
602
- url: this.options.urls.inbox.graphql
621
+ url: this.options.apiUrls.inbox.graphql
603
622
  });
604
623
  }
605
624
  /**
606
625
  * Archive a message
626
+ * @param messageId - ID of the message to archive
627
+ * @returns Promise resolving when message is archived
607
628
  */
608
629
  async archive(props) {
609
630
  const query = `
@@ -622,7 +643,30 @@ class InboxClient extends Client {
622
643
  options: this.options,
623
644
  query,
624
645
  headers,
625
- url: this.options.urls.inbox.graphql
646
+ url: this.options.apiUrls.inbox.graphql
647
+ });
648
+ }
649
+ /**
650
+ * Archive all read messages.
651
+ */
652
+ async archiveRead() {
653
+ const query = `
654
+ mutation TrackEvent {
655
+ archiveRead
656
+ }
657
+ `;
658
+ const headers = {
659
+ "x-courier-user-id": this.options.userId,
660
+ "Authorization": `Bearer ${this.options.accessToken}`
661
+ };
662
+ if (this.options.connectionId) {
663
+ headers["x-courier-client-source-id"] = this.options.connectionId;
664
+ }
665
+ await graphql({
666
+ options: this.options,
667
+ query,
668
+ headers,
669
+ url: this.options.apiUrls.inbox.graphql
626
670
  });
627
671
  }
628
672
  }
@@ -677,12 +721,14 @@ class PreferenceClient extends Client {
677
721
  }
678
722
  /**
679
723
  * Get all preferences for a user
724
+ * @param paginationCursor - Optional cursor for pagination
725
+ * @returns Promise resolving to user preferences
680
726
  * @see https://www.courier.com/docs/reference/user-preferences/list-all-user-preferences
681
727
  */
682
- async getUserPreferences(params) {
683
- let url = `${this.options.urls.courier.rest}/users/${this.options.userId}/preferences`;
684
- if (params == null ? void 0 : params.paginationCursor) {
685
- url += `?cursor=${params.paginationCursor}`;
728
+ async getUserPreferences(props) {
729
+ let url = `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences`;
730
+ if (props == null ? void 0 : props.paginationCursor) {
731
+ url += `?cursor=${props.paginationCursor}`;
686
732
  }
687
733
  const json = await http({
688
734
  options: this.options,
@@ -700,12 +746,14 @@ class PreferenceClient extends Client {
700
746
  }
701
747
  /**
702
748
  * Get preferences for a specific topic
749
+ * @param topicId - The ID of the topic to get preferences for
750
+ * @returns Promise resolving to topic preferences
703
751
  * @see https://www.courier.com/docs/reference/user-preferences/get-subscription-topic-preferences
704
752
  */
705
- async getUserPreferenceTopic(params) {
753
+ async getUserPreferenceTopic(props) {
706
754
  const json = await http({
707
755
  options: this.options,
708
- url: `${this.options.urls.courier.rest}/users/${this.options.userId}/preferences/${params.topicId}`,
756
+ url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences/${props.topicId}`,
709
757
  method: "GET",
710
758
  headers: {
711
759
  "Authorization": `Bearer ${this.options.accessToken}`
@@ -716,19 +764,24 @@ class PreferenceClient extends Client {
716
764
  }
717
765
  /**
718
766
  * Update preferences for a specific topic
767
+ * @param topicId - The ID of the topic to update preferences for
768
+ * @param status - The new status for the topic
769
+ * @param hasCustomRouting - Whether the topic has custom routing
770
+ * @param customRouting - The custom routing channels for the topic
771
+ * @returns Promise resolving when update is complete
719
772
  * @see https://www.courier.com/docs/reference/user-preferences/update-subscription-topic-preferences
720
773
  */
721
- async putUserPreferenceTopic(params) {
774
+ async putUserPreferenceTopic(props) {
722
775
  const payload = {
723
776
  topic: {
724
- status: params.status,
725
- has_custom_routing: params.hasCustomRouting,
726
- custom_routing: params.customRouting
777
+ status: props.status,
778
+ has_custom_routing: props.hasCustomRouting,
779
+ custom_routing: props.customRouting
727
780
  }
728
781
  };
729
782
  await http({
730
783
  options: this.options,
731
- url: `${this.options.urls.courier.rest}/users/${this.options.userId}/preferences/${params.topicId}`,
784
+ url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/preferences/${props.topicId}`,
732
785
  method: "PUT",
733
786
  headers: {
734
787
  "Authorization": `Bearer ${this.options.accessToken}`
@@ -738,11 +791,11 @@ class PreferenceClient extends Client {
738
791
  }
739
792
  /**
740
793
  * Get the notification center URL
741
- * @param params
742
- * @returns
794
+ * @param clientKey - The client key to use for the URL
795
+ * @returns The notification center URL
743
796
  */
744
- getNotificationCenterUrl(params) {
745
- const rootTenantId = decode(params.clientKey);
797
+ getNotificationCenterUrl(props) {
798
+ const rootTenantId = decode(props.clientKey);
746
799
  const url = encode(`${rootTenantId}#${this.options.userId}${this.options.tenantId ? `#${this.options.tenantId}` : ""}#${false}`);
747
800
  return `https://view.notificationcenter.app/p/${url}`;
748
801
  }
@@ -750,6 +803,9 @@ class PreferenceClient extends Client {
750
803
  class TokenClient extends Client {
751
804
  /**
752
805
  * Store a push notification token for a user
806
+ * @param token - The push notification token
807
+ * @param provider - The provider of the token
808
+ * @param device - The device information
753
809
  * @see https://www.courier.com/docs/reference/token-management/put-token
754
810
  */
755
811
  async putUserToken(props) {
@@ -768,7 +824,7 @@ class TokenClient extends Client {
768
824
  };
769
825
  await http({
770
826
  options: this.options,
771
- url: `${this.options.urls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,
827
+ url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,
772
828
  method: "PUT",
773
829
  headers: {
774
830
  "Authorization": `Bearer ${this.options.accessToken}`
@@ -779,11 +835,13 @@ class TokenClient extends Client {
779
835
  }
780
836
  /**
781
837
  * Delete a push notification token for a user
838
+ * @param token - The push notification token
839
+ * @returns Promise resolving when token is deleted
782
840
  */
783
841
  async deleteUserToken(props) {
784
842
  await http({
785
843
  options: this.options,
786
- url: `${this.options.urls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,
844
+ url: `${this.options.apiUrls.courier.rest}/users/${this.options.userId}/tokens/${props.token}`,
787
845
  method: "DELETE",
788
846
  headers: {
789
847
  "Authorization": `Bearer ${this.options.accessToken}`
@@ -795,11 +853,13 @@ class TokenClient extends Client {
795
853
  class ListClient extends Client {
796
854
  /**
797
855
  * Subscribe a user to a list
856
+ * @param listId - The ID of the list to subscribe to
857
+ * @returns Promise resolving when subscription is complete
798
858
  * @see https://www.courier.com/docs/reference/lists/recipient-subscribe
799
859
  */
800
860
  async putSubscription(props) {
801
861
  return await http({
802
- url: `${this.options.urls.courier.rest}/lists/${props.listId}/subscriptions/${this.options.userId}`,
862
+ url: `${this.options.apiUrls.courier.rest}/lists/${props.listId}/subscriptions/${this.options.userId}`,
803
863
  options: this.options,
804
864
  method: "PUT",
805
865
  headers: {
@@ -809,11 +869,13 @@ class ListClient extends Client {
809
869
  }
810
870
  /**
811
871
  * Unsubscribe a user from a list
872
+ * @param listId - The ID of the list to unsubscribe from
873
+ * @returns Promise resolving when unsubscription is complete
812
874
  * @see https://www.courier.com/docs/reference/lists/delete-subscription
813
875
  */
814
876
  async deleteSubscription(props) {
815
877
  return await http({
816
- url: `${this.options.urls.courier.rest}/lists/${props.listId}/subscriptions/${this.options.userId}`,
878
+ url: `${this.options.apiUrls.courier.rest}/lists/${props.listId}/subscriptions/${this.options.userId}`,
817
879
  options: this.options,
818
880
  method: "DELETE",
819
881
  headers: {
@@ -825,11 +887,16 @@ class ListClient extends Client {
825
887
  class TrackingClient extends Client {
826
888
  /**
827
889
  * Post an inbound courier event
890
+ * @param event - The event type: Example: "New Order Placed"
891
+ * @param messageId - The message ID
892
+ * @param type - The type of event: Available options: "track"
893
+ * @param properties - The properties of the event
894
+ * @returns Promise resolving to the message ID
828
895
  * @see https://www.courier.com/docs/reference/inbound/courier-track-event
829
896
  */
830
897
  async postInboundCourier(props) {
831
898
  return await http({
832
- url: `${this.options.urls.courier.rest}/inbound/courier`,
899
+ url: `${this.options.apiUrls.courier.rest}/inbound/courier`,
833
900
  options: this.options,
834
901
  method: "POST",
835
902
  headers: {
@@ -845,6 +912,9 @@ class TrackingClient extends Client {
845
912
  /**
846
913
  * Post a tracking URL event
847
914
  * These urls are found in messages sent from Courier
915
+ * @param url - The URL to post the event to
916
+ * @param event - The event type: Available options: "click", "open", "unsubscribe"
917
+ * @returns Promise resolving when the event is posted
848
918
  */
849
919
  async postTrackingUrl(props) {
850
920
  return await http({
@@ -870,7 +940,7 @@ class CourierClient extends Client {
870
940
  super({
871
941
  ...baseOptions,
872
942
  logger: new Logger(baseOptions.showLogs),
873
- urls: getCourierApiUrls(baseOptions.apiUrls)
943
+ apiUrls: getCourierApiUrls(baseOptions.apiUrls)
874
944
  });
875
945
  __publicField(this, "tokens");
876
946
  __publicField(this, "brands");
@@ -6,7 +6,7 @@ export interface MessageEvent {
6
6
  messageId?: string;
7
7
  type: string;
8
8
  }
9
- export type EventType = 'read' | 'unread' | 'mark-all-read' | 'opened' | 'unopened' | 'archive' | 'unarchive' | 'click';
9
+ export type EventType = 'archive-read' | 'archive' | 'click' | 'mark-all-read' | 'opened' | 'read' | 'unarchive' | 'unopened' | 'unread';
10
10
  export declare class InboxSocket extends CourierSocket {
11
11
  receivedMessage?: (message: InboxMessage) => void;
12
12
  receivedMessageEvent?: (event: MessageEvent) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trycourier/courier-js",
3
- "version": "2.0.0-beta",
3
+ "version": "2.0.2-beta",
4
4
  "description": "A browser-safe API wrapper",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -29,6 +29,8 @@
29
29
  "@types/jest": "29.5.14",
30
30
  "dotenv": "16.4.7",
31
31
  "jest": "29.7.0",
32
+ "jest-environment-jsdom": "29.7.0",
33
+ "jest-fetch-mock": "^3.0.3",
32
34
  "terser": "5.39.0",
33
35
  "ts-jest": "29.1.1",
34
36
  "vite": "6.2.6",