@bentonow/bento-node-sdk 1.0.4 → 1.0.5
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 +256 -100
- package/dist/index.js +101 -68
- package/dist/sdk/batch/index.d.ts +1 -1
- package/dist/sdk/broadcasts/index.d.ts +2 -1
- package/dist/sdk/broadcasts/types.d.ts +4 -0
- package/dist/sdk/client/errors.d.ts +3 -0
- package/dist/sdk/client/index.d.ts +23 -3
- package/dist/sdk/interfaces.d.ts +4 -0
- package/dist/sdk/sequences/index.d.ts +2 -2
- package/dist/sdk/workflows/index.d.ts +2 -2
- package/dist/versions/v1/index.d.ts +7 -3
- package/package.json +1 -1
- package/src/sdk/batch/index.ts +10 -5
- package/src/sdk/broadcasts/index.ts +8 -7
- package/src/sdk/broadcasts/types.ts +5 -1
- package/src/sdk/client/errors.ts +7 -0
- package/src/sdk/client/index.ts +122 -49
- package/src/sdk/interfaces.ts +4 -0
- package/src/sdk/sequences/index.ts +4 -4
- package/src/sdk/workflows/index.ts +4 -4
- package/src/versions/v1/index.ts +16 -10
package/dist/index.js
CHANGED
|
@@ -626,7 +626,7 @@ class BentoBatch {
|
|
|
626
626
|
}
|
|
627
627
|
const result = await this._client.post(`${this._url}/subscribers`, {
|
|
628
628
|
subscribers: parameters.subscribers
|
|
629
|
-
});
|
|
629
|
+
}, { timeout: null });
|
|
630
630
|
return result.results;
|
|
631
631
|
}
|
|
632
632
|
async importEvents(parameters) {
|
|
@@ -638,7 +638,7 @@ class BentoBatch {
|
|
|
638
638
|
}
|
|
639
639
|
const result = await this._client.post(`${this._url}/events`, {
|
|
640
640
|
events: parameters.events
|
|
641
|
-
});
|
|
641
|
+
}, { timeout: null });
|
|
642
642
|
return result.results;
|
|
643
643
|
}
|
|
644
644
|
async sendTransactionalEmails(parameters) {
|
|
@@ -679,6 +679,13 @@ class AuthorNotAuthorizedError extends Error {
|
|
|
679
679
|
}
|
|
680
680
|
}
|
|
681
681
|
|
|
682
|
+
class RequestTimeoutError extends Error {
|
|
683
|
+
constructor(message = "Request timed out") {
|
|
684
|
+
super(message);
|
|
685
|
+
this.name = "RequestTimeoutError";
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
682
689
|
// src/sdk/client/index.ts
|
|
683
690
|
function encodeBase64(str) {
|
|
684
691
|
if (typeof btoa === "function") {
|
|
@@ -704,61 +711,83 @@ class BentoClient {
|
|
|
704
711
|
_baseUrl = "https://app.bentonow.com/api/v1";
|
|
705
712
|
_siteUuid = "";
|
|
706
713
|
_logErrors = false;
|
|
714
|
+
_timeout = 30000;
|
|
707
715
|
constructor(options) {
|
|
708
716
|
this._baseUrl = options.clientOptions?.baseUrl || this._baseUrl;
|
|
709
717
|
this._siteUuid = options.siteUuid;
|
|
710
718
|
this._headers = this._extractHeaders(options.authentication, options.siteUuid);
|
|
711
719
|
this._logErrors = options.logErrors || false;
|
|
720
|
+
this._timeout = options.clientOptions?.timeout ?? this._timeout;
|
|
721
|
+
}
|
|
722
|
+
async get(endpoint, payload = {}, requestOptions = {}) {
|
|
723
|
+
const queryParameters = this._getQueryParameters(payload);
|
|
724
|
+
const url = `${this._baseUrl}${endpoint}?${queryParameters}`;
|
|
725
|
+
const timeoutMs = requestOptions.timeout === undefined ? this._timeout : requestOptions.timeout;
|
|
726
|
+
const response = await this._fetchWithTimeout(url, {
|
|
727
|
+
method: "GET",
|
|
728
|
+
headers: this._headers
|
|
729
|
+
}, timeoutMs);
|
|
730
|
+
return this._handleResponse(response);
|
|
731
|
+
}
|
|
732
|
+
async post(endpoint, payload = {}, requestOptions = {}) {
|
|
733
|
+
const body = this._getBody(payload);
|
|
734
|
+
const url = `${this._baseUrl}${endpoint}`;
|
|
735
|
+
const timeoutMs = requestOptions.timeout === undefined ? this._timeout : requestOptions.timeout;
|
|
736
|
+
const response = await this._fetchWithTimeout(url, {
|
|
737
|
+
method: "POST",
|
|
738
|
+
headers: {
|
|
739
|
+
...this._headers,
|
|
740
|
+
"Content-Type": "application/json"
|
|
741
|
+
},
|
|
742
|
+
body
|
|
743
|
+
}, timeoutMs);
|
|
744
|
+
return this._handleResponse(response);
|
|
745
|
+
}
|
|
746
|
+
async patch(endpoint, payload = {}, requestOptions = {}) {
|
|
747
|
+
const body = this._getBody(payload);
|
|
748
|
+
const url = `${this._baseUrl}${endpoint}`;
|
|
749
|
+
const timeoutMs = requestOptions.timeout === undefined ? this._timeout : requestOptions.timeout;
|
|
750
|
+
const response = await this._fetchWithTimeout(url, {
|
|
751
|
+
method: "PATCH",
|
|
752
|
+
headers: {
|
|
753
|
+
...this._headers,
|
|
754
|
+
"Content-Type": "application/json"
|
|
755
|
+
},
|
|
756
|
+
body
|
|
757
|
+
}, timeoutMs);
|
|
758
|
+
return this._handleResponse(response);
|
|
759
|
+
}
|
|
760
|
+
async _fetchWithTimeout(url, options, timeout) {
|
|
761
|
+
if (timeout === null) {
|
|
762
|
+
return import_cross_fetch.default(url, options);
|
|
763
|
+
}
|
|
764
|
+
const controller = new AbortController;
|
|
765
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
766
|
+
try {
|
|
767
|
+
const response = await import_cross_fetch.default(url, {
|
|
768
|
+
...options,
|
|
769
|
+
signal: controller.signal
|
|
770
|
+
});
|
|
771
|
+
return response;
|
|
772
|
+
} catch (error) {
|
|
773
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
774
|
+
throw new RequestTimeoutError(`Request timed out after ${timeout}ms`);
|
|
775
|
+
}
|
|
776
|
+
throw error;
|
|
777
|
+
} finally {
|
|
778
|
+
clearTimeout(timeoutId);
|
|
779
|
+
}
|
|
712
780
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
throw await this._getErrorForResponse(result);
|
|
724
|
-
}).then((data) => resolve(data)).catch((error) => reject(error));
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
post(endpoint, payload = {}) {
|
|
728
|
-
return new Promise((resolve, reject) => {
|
|
729
|
-
const body = this._getBody(payload);
|
|
730
|
-
import_cross_fetch.default(`${this._baseUrl}${endpoint}`, {
|
|
731
|
-
method: "POST",
|
|
732
|
-
headers: {
|
|
733
|
-
...this._headers,
|
|
734
|
-
"Content-Type": "application/json"
|
|
735
|
-
},
|
|
736
|
-
body
|
|
737
|
-
}).then(async (result) => {
|
|
738
|
-
if (this._isSuccessfulStatus(result.status)) {
|
|
739
|
-
return result.json();
|
|
740
|
-
}
|
|
741
|
-
throw await this._getErrorForResponse(result);
|
|
742
|
-
}).then((data) => resolve(data)).catch((error) => reject(error));
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
patch(endpoint, payload = {}) {
|
|
746
|
-
return new Promise((resolve, reject) => {
|
|
747
|
-
const body = this._getBody(payload);
|
|
748
|
-
import_cross_fetch.default(`${this._baseUrl}${endpoint}`, {
|
|
749
|
-
method: "PATCH",
|
|
750
|
-
headers: {
|
|
751
|
-
...this._headers,
|
|
752
|
-
"Content-Type": "application/json"
|
|
753
|
-
},
|
|
754
|
-
body
|
|
755
|
-
}).then(async (result) => {
|
|
756
|
-
if (this._isSuccessfulStatus(result.status)) {
|
|
757
|
-
return result.json();
|
|
758
|
-
}
|
|
759
|
-
throw await this._getErrorForResponse(result);
|
|
760
|
-
}).then((data) => resolve(data)).catch((error) => reject(error));
|
|
761
|
-
});
|
|
781
|
+
async _handleResponse(response) {
|
|
782
|
+
if (this._isSuccessfulStatus(response.status)) {
|
|
783
|
+
try {
|
|
784
|
+
const data = await response.json();
|
|
785
|
+
return data;
|
|
786
|
+
} catch {
|
|
787
|
+
throw new Error(`[${response.status}] - Invalid JSON response from server`);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
throw await this._getErrorForResponse(response);
|
|
762
791
|
}
|
|
763
792
|
_extractHeaders(authentication, siteUuid) {
|
|
764
793
|
const authenticationKey = encodeBase64(`${authentication.publishableKey}:${authentication.secretKey}`);
|
|
@@ -780,7 +809,7 @@ class BentoClient {
|
|
|
780
809
|
};
|
|
781
810
|
const queryParameters = new URLSearchParams;
|
|
782
811
|
for (const [key, value] of Object.entries(body)) {
|
|
783
|
-
queryParameters.append(key, value);
|
|
812
|
+
queryParameters.append(key, String(value));
|
|
784
813
|
}
|
|
785
814
|
return queryParameters.toString();
|
|
786
815
|
}
|
|
@@ -1034,9 +1063,9 @@ class BentoSequences {
|
|
|
1034
1063
|
}
|
|
1035
1064
|
async getSequences() {
|
|
1036
1065
|
const result = await this._client.get(this._url);
|
|
1037
|
-
if (Object.keys(result).length === 0
|
|
1038
|
-
return
|
|
1039
|
-
return result.data;
|
|
1066
|
+
if (!result || Object.keys(result).length === 0)
|
|
1067
|
+
return [];
|
|
1068
|
+
return result.data ?? [];
|
|
1040
1069
|
}
|
|
1041
1070
|
}
|
|
1042
1071
|
// src/sdk/subscribers/index.ts
|
|
@@ -1092,16 +1121,17 @@ class BentoWorkflows {
|
|
|
1092
1121
|
}
|
|
1093
1122
|
async getWorkflows() {
|
|
1094
1123
|
const result = await this._client.get(this._url);
|
|
1095
|
-
if (Object.keys(result).length === 0
|
|
1096
|
-
return
|
|
1097
|
-
return result.data;
|
|
1124
|
+
if (!result || Object.keys(result).length === 0)
|
|
1125
|
+
return [];
|
|
1126
|
+
return result.data ?? [];
|
|
1098
1127
|
}
|
|
1099
1128
|
}
|
|
1100
1129
|
// src/sdk/broadcasts/index.ts
|
|
1101
1130
|
class BentoBroadcasts {
|
|
1102
1131
|
_client;
|
|
1103
|
-
|
|
1104
|
-
|
|
1132
|
+
_fetchUrl = "/fetch/broadcasts";
|
|
1133
|
+
_batchUrl = "/batch/broadcasts";
|
|
1134
|
+
_emailsUrl = "/batch/emails";
|
|
1105
1135
|
constructor(_client) {
|
|
1106
1136
|
this._client = _client;
|
|
1107
1137
|
}
|
|
@@ -1112,11 +1142,11 @@ class BentoBroadcasts {
|
|
|
1112
1142
|
return result.results;
|
|
1113
1143
|
}
|
|
1114
1144
|
async getBroadcasts() {
|
|
1115
|
-
const result = await this._client.get(this.
|
|
1145
|
+
const result = await this._client.get(this._fetchUrl);
|
|
1116
1146
|
return result.data ?? [];
|
|
1117
1147
|
}
|
|
1118
1148
|
async createBroadcast(broadcasts) {
|
|
1119
|
-
const result = await this._client.post(this.
|
|
1149
|
+
const result = await this._client.post(this._batchUrl, {
|
|
1120
1150
|
broadcasts
|
|
1121
1151
|
});
|
|
1122
1152
|
return result.data ?? [];
|
|
@@ -1248,12 +1278,14 @@ class BentoAPIV1 {
|
|
|
1248
1278
|
}
|
|
1249
1279
|
async upsertSubscriber(parameters) {
|
|
1250
1280
|
await this.Batch.importSubscribers({
|
|
1251
|
-
subscribers: [
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1281
|
+
subscribers: [
|
|
1282
|
+
{
|
|
1283
|
+
email: parameters.email,
|
|
1284
|
+
...parameters.fields,
|
|
1285
|
+
...parameters.tags && { tags: parameters.tags },
|
|
1286
|
+
...parameters.remove_tags && { remove_tags: parameters.remove_tags }
|
|
1287
|
+
}
|
|
1288
|
+
]
|
|
1257
1289
|
});
|
|
1258
1290
|
return this.Subscribers.getSubscribers({
|
|
1259
1291
|
email: parameters.email
|
|
@@ -1269,6 +1301,7 @@ class Analytics {
|
|
|
1269
1301
|
}
|
|
1270
1302
|
}
|
|
1271
1303
|
export {
|
|
1304
|
+
RequestTimeoutError,
|
|
1272
1305
|
RateLimitedError,
|
|
1273
1306
|
NotAuthorizedError,
|
|
1274
1307
|
AuthorNotAuthorizedError,
|
|
@@ -44,7 +44,7 @@ export declare class BentoBatch<S, E extends string> {
|
|
|
44
44
|
* Each email must have a `to` address, a `from` address, a `subject`, an `html_body`
|
|
45
45
|
* and `transactional: true`.
|
|
46
46
|
* In addition you can add a `personalizations` object to provide
|
|
47
|
-
* liquid
|
|
47
|
+
* liquid tags that will be injected into the email.
|
|
48
48
|
*
|
|
49
49
|
* Returns the number of events that were imported.
|
|
50
50
|
*
|
|
@@ -2,7 +2,8 @@ import type { BentoClient } from '../client';
|
|
|
2
2
|
import type { Broadcast, CreateBroadcastInput, EmailData } from './types';
|
|
3
3
|
export declare class BentoBroadcasts {
|
|
4
4
|
private readonly _client;
|
|
5
|
-
private readonly
|
|
5
|
+
private readonly _fetchUrl;
|
|
6
|
+
private readonly _batchUrl;
|
|
6
7
|
private readonly _emailsUrl;
|
|
7
8
|
constructor(_client: BentoClient);
|
|
8
9
|
/**
|
|
@@ -18,6 +18,10 @@ export type BroadcastAttributes = {
|
|
|
18
18
|
};
|
|
19
19
|
export type Broadcast = BaseEntity<BroadcastAttributes>;
|
|
20
20
|
export type CreateBroadcastInput = Omit<BroadcastAttributes, 'created_at'>;
|
|
21
|
+
/**
|
|
22
|
+
* Email data for transactional emails.
|
|
23
|
+
* Note: This is the same structure as TransactionalEmail in batch/types.ts
|
|
24
|
+
*/
|
|
21
25
|
export type EmailData = {
|
|
22
26
|
to: string;
|
|
23
27
|
from: string;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { AnalyticsOptions } from '../interfaces';
|
|
2
|
+
interface RequestOptions {
|
|
3
|
+
timeout?: number | null;
|
|
4
|
+
}
|
|
2
5
|
export declare class BentoClient {
|
|
3
6
|
private readonly _headers;
|
|
4
7
|
private readonly _baseUrl;
|
|
5
8
|
private readonly _siteUuid;
|
|
6
9
|
private readonly _logErrors;
|
|
10
|
+
private readonly _timeout;
|
|
7
11
|
constructor(options: AnalyticsOptions);
|
|
8
12
|
/**
|
|
9
13
|
* Wraps a GET request to the Bento API and automatically adds the required
|
|
@@ -13,7 +17,7 @@ export declare class BentoClient {
|
|
|
13
17
|
* @param payload object
|
|
14
18
|
* @returns Promise\<T\>
|
|
15
19
|
* */
|
|
16
|
-
get<T>(endpoint: string, payload?: Record<string, unknown
|
|
20
|
+
get<T>(endpoint: string, payload?: Record<string, unknown>, requestOptions?: RequestOptions): Promise<T>;
|
|
17
21
|
/**
|
|
18
22
|
* Wraps a POST request to the Bento API and automatically adds the required
|
|
19
23
|
* headers.
|
|
@@ -22,7 +26,7 @@ export declare class BentoClient {
|
|
|
22
26
|
* @param payload object
|
|
23
27
|
* @returns Promise\<T\>
|
|
24
28
|
* */
|
|
25
|
-
post<T>(endpoint: string, payload?: Record<string, unknown
|
|
29
|
+
post<T>(endpoint: string, payload?: Record<string, unknown>, requestOptions?: RequestOptions): Promise<T>;
|
|
26
30
|
/**
|
|
27
31
|
* Wraps a PATCH request to the Bento API and automatically adds the required
|
|
28
32
|
* headers.
|
|
@@ -31,7 +35,22 @@ export declare class BentoClient {
|
|
|
31
35
|
* @param payload object
|
|
32
36
|
* @returns Promise\<T\>
|
|
33
37
|
* */
|
|
34
|
-
patch<T>(endpoint: string, payload?: Record<string, unknown
|
|
38
|
+
patch<T>(endpoint: string, payload?: Record<string, unknown>, requestOptions?: RequestOptions): Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Performs a fetch request with a configurable timeout.
|
|
41
|
+
*
|
|
42
|
+
* @param url The URL to fetch
|
|
43
|
+
* @param options Fetch options
|
|
44
|
+
* @returns Promise<Response>
|
|
45
|
+
*/
|
|
46
|
+
private _fetchWithTimeout;
|
|
47
|
+
/**
|
|
48
|
+
* Handles the response from a fetch request, parsing JSON or throwing appropriate errors.
|
|
49
|
+
*
|
|
50
|
+
* @param response The fetch Response object
|
|
51
|
+
* @returns Promise<T> The parsed response data
|
|
52
|
+
*/
|
|
53
|
+
private _handleResponse;
|
|
35
54
|
/**
|
|
36
55
|
* Extracts the `publishableKey` and `secretKey` from the `authentication` options,
|
|
37
56
|
* adds the `Authorization` header, and includes a `User-Agent` header with the site UUID.
|
|
@@ -72,3 +91,4 @@ export declare class BentoClient {
|
|
|
72
91
|
*/
|
|
73
92
|
private _getErrorForResponse;
|
|
74
93
|
}
|
|
94
|
+
export {};
|
package/dist/sdk/interfaces.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class BentoSequences {
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns all of the sequences for the site, including their email templates.
|
|
9
9
|
*
|
|
10
|
-
* @returns Promise\<Sequence[]
|
|
10
|
+
* @returns Promise\<Sequence[]\>
|
|
11
11
|
*/
|
|
12
|
-
getSequences(): Promise<Sequence[]
|
|
12
|
+
getSequences(): Promise<Sequence[]>;
|
|
13
13
|
}
|
|
@@ -7,7 +7,7 @@ export declare class BentoWorkflows {
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns all of the workflows for the site, including their email templates.
|
|
9
9
|
*
|
|
10
|
-
* @returns Promise\<Workflow[]
|
|
10
|
+
* @returns Promise\<Workflow[]\>
|
|
11
11
|
*/
|
|
12
|
-
getWorkflows(): Promise<Workflow[]
|
|
12
|
+
getWorkflows(): Promise<Workflow[]>;
|
|
13
13
|
}
|
|
@@ -3,7 +3,7 @@ import type { AnalyticsOptions } from '../../sdk/interfaces';
|
|
|
3
3
|
import type { AddSubscriberParameters, RemoveSubscriberParameters, TagSubscriberParameters, TrackParameters, TrackPurchaseParameters, UpdateFieldsParameters } from './types';
|
|
4
4
|
import { BentoBroadcasts } from '../../sdk/broadcasts';
|
|
5
5
|
import { BentoStats } from '../../sdk/stats';
|
|
6
|
-
import { Subscriber } from '../../sdk/subscribers/types';
|
|
6
|
+
import type { Subscriber } from '../../sdk/subscribers/types';
|
|
7
7
|
export declare class BentoAPIV1<S = {
|
|
8
8
|
[key: string]: unknown;
|
|
9
9
|
}, E extends string = '$custom'> {
|
|
@@ -141,9 +141,13 @@ export declare class BentoAPIV1<S = {
|
|
|
141
141
|
* Upserts a subscriber in Bento. If the subscriber exists, their data will be updated.
|
|
142
142
|
* If they don't exist, they will be created with the provided data.
|
|
143
143
|
*
|
|
144
|
+
* This method still relies on the batch import queue (which can take 1-5 minutes to
|
|
145
|
+
* finish processing), but it automatically attempts to fetch and return the subscriber
|
|
146
|
+
* record after the import has been queued.
|
|
147
|
+
*
|
|
144
148
|
* @example
|
|
145
149
|
* ```typescript
|
|
146
|
-
* await analytics.V1.upsertSubscriber({
|
|
150
|
+
* const subscriber = await analytics.V1.upsertSubscriber({
|
|
147
151
|
* email: 'user@example.com',
|
|
148
152
|
* fields: {
|
|
149
153
|
* firstName: 'John',
|
|
@@ -155,7 +159,7 @@ export declare class BentoAPIV1<S = {
|
|
|
155
159
|
* ```
|
|
156
160
|
*
|
|
157
161
|
* @param parameters Object containing subscriber data including email, fields, and tags
|
|
158
|
-
* @returns Promise<Subscriber<S
|
|
162
|
+
* @returns Promise<Subscriber<S> | null> The created or updated subscriber
|
|
159
163
|
*/
|
|
160
164
|
upsertSubscriber(parameters: Omit<AddSubscriberParameters<S>, 'date'> & {
|
|
161
165
|
tags?: string;
|
package/package.json
CHANGED
package/src/sdk/batch/index.ts
CHANGED
|
@@ -54,7 +54,8 @@ export class BentoBatch<S, E extends string> {
|
|
|
54
54
|
`${this._url}/subscribers`,
|
|
55
55
|
{
|
|
56
56
|
subscribers: parameters.subscribers,
|
|
57
|
-
}
|
|
57
|
+
},
|
|
58
|
+
{ timeout: null }
|
|
58
59
|
);
|
|
59
60
|
|
|
60
61
|
return result.results;
|
|
@@ -80,9 +81,13 @@ export class BentoBatch<S, E extends string> {
|
|
|
80
81
|
throw new TooManyEventsError(`You must send between 1 and 1,000 events.`);
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
const result = await this._client.post<BatchImportEventsResponse>(
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
const result = await this._client.post<BatchImportEventsResponse>(
|
|
85
|
+
`${this._url}/events`,
|
|
86
|
+
{
|
|
87
|
+
events: parameters.events,
|
|
88
|
+
},
|
|
89
|
+
{ timeout: null }
|
|
90
|
+
);
|
|
86
91
|
|
|
87
92
|
return result.results;
|
|
88
93
|
}
|
|
@@ -94,7 +99,7 @@ export class BentoBatch<S, E extends string> {
|
|
|
94
99
|
* Each email must have a `to` address, a `from` address, a `subject`, an `html_body`
|
|
95
100
|
* and `transactional: true`.
|
|
96
101
|
* In addition you can add a `personalizations` object to provide
|
|
97
|
-
* liquid
|
|
102
|
+
* liquid tags that will be injected into the email.
|
|
98
103
|
*
|
|
99
104
|
* Returns the number of events that were imported.
|
|
100
105
|
*
|
|
@@ -3,8 +3,9 @@ import type { DataResponse } from '../client/types';
|
|
|
3
3
|
import type { Broadcast, CreateBroadcastInput, EmailData } from './types';
|
|
4
4
|
|
|
5
5
|
export class BentoBroadcasts {
|
|
6
|
-
private readonly
|
|
7
|
-
private readonly
|
|
6
|
+
private readonly _fetchUrl = '/fetch/broadcasts';
|
|
7
|
+
private readonly _batchUrl = '/batch/broadcasts';
|
|
8
|
+
private readonly _emailsUrl = '/batch/emails';
|
|
8
9
|
|
|
9
10
|
constructor(private readonly _client: BentoClient) {}
|
|
10
11
|
|
|
@@ -15,7 +16,7 @@ export class BentoBroadcasts {
|
|
|
15
16
|
*/
|
|
16
17
|
public async createEmails(emails: EmailData[]): Promise<number> {
|
|
17
18
|
const result = await this._client.post<{ results: number }>(this._emailsUrl, {
|
|
18
|
-
emails
|
|
19
|
+
emails,
|
|
19
20
|
});
|
|
20
21
|
return result.results;
|
|
21
22
|
}
|
|
@@ -25,7 +26,7 @@ export class BentoBroadcasts {
|
|
|
25
26
|
* @returns Promise<Broadcast[]>
|
|
26
27
|
*/
|
|
27
28
|
public async getBroadcasts(): Promise<Broadcast[]> {
|
|
28
|
-
const result = await this._client.get<DataResponse<Broadcast[]>>(this.
|
|
29
|
+
const result = await this._client.get<DataResponse<Broadcast[]>>(this._fetchUrl);
|
|
29
30
|
return result.data ?? [];
|
|
30
31
|
}
|
|
31
32
|
|
|
@@ -35,9 +36,9 @@ export class BentoBroadcasts {
|
|
|
35
36
|
* @returns Promise<Broadcast[]>
|
|
36
37
|
*/
|
|
37
38
|
public async createBroadcast(broadcasts: CreateBroadcastInput[]): Promise<Broadcast[]> {
|
|
38
|
-
const result = await this._client.post<DataResponse<Broadcast[]>>(this.
|
|
39
|
-
broadcasts
|
|
39
|
+
const result = await this._client.post<DataResponse<Broadcast[]>>(this._batchUrl, {
|
|
40
|
+
broadcasts,
|
|
40
41
|
});
|
|
41
42
|
return result.data ?? [];
|
|
42
43
|
}
|
|
43
|
-
}
|
|
44
|
+
}
|
|
@@ -24,6 +24,10 @@ export type Broadcast = BaseEntity<BroadcastAttributes>;
|
|
|
24
24
|
|
|
25
25
|
export type CreateBroadcastInput = Omit<BroadcastAttributes, 'created_at'>;
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Email data for transactional emails.
|
|
29
|
+
* Note: This is the same structure as TransactionalEmail in batch/types.ts
|
|
30
|
+
*/
|
|
27
31
|
export type EmailData = {
|
|
28
32
|
to: string;
|
|
29
33
|
from: string;
|
|
@@ -31,4 +35,4 @@ export type EmailData = {
|
|
|
31
35
|
html_body: string;
|
|
32
36
|
transactional: boolean;
|
|
33
37
|
personalizations?: Record<string, string | number | boolean>;
|
|
34
|
-
};
|
|
38
|
+
};
|
package/src/sdk/client/errors.ts
CHANGED
|
@@ -18,3 +18,10 @@ export class AuthorNotAuthorizedError extends Error {
|
|
|
18
18
|
this.name = 'AuthorNotAuthorizedError';
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
export class RequestTimeoutError extends Error {
|
|
23
|
+
constructor(message = 'Request timed out') {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = 'RequestTimeoutError';
|
|
26
|
+
}
|
|
27
|
+
}
|