@bentonow/bento-node-sdk 0.2.1 → 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/{LICENSE → LICENSE.md} +1 -1
- package/README.md +604 -1031
- package/dist/index.d.ts +9 -9
- package/dist/index.js +1306 -5
- package/dist/sdk/batch/enums.d.ts +8 -8
- package/dist/sdk/batch/errors.d.ts +18 -18
- package/dist/sdk/batch/events.d.ts +71 -71
- package/dist/sdk/batch/index.d.ts +55 -55
- package/dist/sdk/batch/types.d.ts +37 -37
- package/dist/sdk/broadcasts/index.d.ts +26 -0
- package/dist/sdk/broadcasts/types.d.ts +32 -0
- package/dist/sdk/client/errors.d.ts +12 -6
- package/dist/sdk/client/index.d.ts +94 -64
- package/dist/sdk/client/types.d.ts +3 -3
- package/dist/sdk/commands/enums.d.ts +12 -12
- package/dist/sdk/commands/index.d.ts +79 -79
- package/dist/sdk/commands/types.d.ts +32 -32
- package/dist/sdk/email-templates/index.d.ts +21 -0
- package/dist/sdk/email-templates/types.d.ts +23 -0
- package/dist/sdk/enums.d.ts +12 -9
- package/dist/sdk/errors.d.ts +2 -2
- package/dist/sdk/experimental/index.d.ts +75 -57
- package/dist/sdk/experimental/types.d.ts +71 -41
- package/dist/sdk/fields/index.d.ts +29 -29
- package/dist/sdk/fields/types.d.ts +17 -17
- package/dist/sdk/forms/index.d.ts +14 -14
- package/dist/sdk/forms/types.d.ts +28 -28
- package/dist/sdk/index.d.ts +11 -8
- package/dist/sdk/interfaces.d.ts +17 -13
- package/dist/sdk/sequences/index.d.ts +13 -0
- package/dist/sdk/sequences/types.d.ts +18 -0
- package/dist/sdk/stats/index.d.ts +24 -0
- package/dist/sdk/stats/types.d.ts +26 -0
- package/dist/sdk/subscribers/index.d.ts +20 -20
- package/dist/sdk/subscribers/types.d.ts +25 -25
- package/dist/sdk/tags/index.d.ts +20 -20
- package/dist/sdk/tags/types.d.ts +17 -17
- package/dist/sdk/types.d.ts +41 -41
- package/dist/sdk/workflows/index.d.ts +13 -0
- package/dist/sdk/workflows/types.d.ts +18 -0
- package/dist/versions/v1/index.d.ts +168 -132
- package/dist/versions/v1/types.d.ts +31 -31
- package/package.json +31 -44
- package/src/sdk/batch/events.ts +1 -1
- package/src/sdk/batch/index.ts +15 -22
- package/src/sdk/broadcasts/index.ts +44 -0
- package/src/sdk/broadcasts/types.ts +38 -0
- package/src/sdk/client/errors.ts +14 -0
- package/src/sdk/client/index.ts +205 -49
- package/src/sdk/commands/index.ts +54 -89
- package/src/sdk/email-templates/index.ts +39 -0
- package/src/sdk/email-templates/types.ts +27 -0
- package/src/sdk/enums.ts +3 -0
- package/src/sdk/experimental/index.ts +44 -26
- package/src/sdk/experimental/types.ts +35 -0
- package/src/sdk/fields/index.ts +1 -3
- package/src/sdk/forms/index.ts +4 -9
- package/src/sdk/forms/types.ts +1 -7
- package/src/sdk/index.ts +3 -0
- package/src/sdk/interfaces.ts +4 -0
- package/src/sdk/sequences/index.ts +21 -0
- package/src/sdk/sequences/types.ts +21 -0
- package/src/sdk/stats/index.ts +37 -0
- package/src/sdk/stats/types.ts +28 -0
- package/src/sdk/subscribers/index.ts +5 -15
- package/src/sdk/tags/index.ts +1 -3
- package/src/sdk/types.ts +1 -1
- package/src/sdk/workflows/index.ts +21 -0
- package/src/sdk/workflows/types.ts +21 -0
- package/src/versions/v1/index.ts +65 -10
- package/dist/bento-node-sdk.cjs.development.js +0 -2071
- package/dist/bento-node-sdk.cjs.development.js.map +0 -1
- package/dist/bento-node-sdk.cjs.production.min.js +0 -2
- package/dist/bento-node-sdk.cjs.production.min.js.map +0 -1
- package/dist/bento-node-sdk.esm.js +0 -2063
- package/dist/bento-node-sdk.esm.js.map +0 -1
package/src/sdk/client/errors.ts
CHANGED
|
@@ -11,3 +11,17 @@ export class RateLimitedError extends Error {
|
|
|
11
11
|
this.name = 'RateLimitedError';
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
export class AuthorNotAuthorizedError extends Error {
|
|
16
|
+
constructor(message = 'Author not authorized to send on this account') {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'AuthorNotAuthorizedError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class RequestTimeoutError extends Error {
|
|
23
|
+
constructor(message = 'Request timed out') {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = 'RequestTimeoutError';
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/sdk/client/index.ts
CHANGED
|
@@ -1,18 +1,57 @@
|
|
|
1
1
|
import fetch from 'cross-fetch';
|
|
2
2
|
import type { AnalyticsOptions, AuthenticationOptions } from '../interfaces';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
NotAuthorizedError,
|
|
5
|
+
RateLimitedError,
|
|
6
|
+
AuthorNotAuthorizedError,
|
|
7
|
+
RequestTimeoutError,
|
|
8
|
+
} from './errors';
|
|
9
|
+
|
|
10
|
+
interface RequestOptions {
|
|
11
|
+
timeout?: number | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function encodeBase64(str: string): string {
|
|
15
|
+
if (typeof btoa === 'function') {
|
|
16
|
+
return btoa(str);
|
|
17
|
+
} else if (typeof Buffer !== 'undefined') {
|
|
18
|
+
return Buffer.from(str).toString('base64');
|
|
19
|
+
} else {
|
|
20
|
+
// Fallback implementation
|
|
21
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
22
|
+
let output = '';
|
|
23
|
+
for (
|
|
24
|
+
let block = 0, charCode, i = 0, map = chars;
|
|
25
|
+
str.charAt(i | 0) || ((map = '='), i % 1);
|
|
26
|
+
output += map.charAt(63 & (block >> (8 - (i % 1) * 8)))
|
|
27
|
+
) {
|
|
28
|
+
charCode = str.charCodeAt((i += 3 / 4));
|
|
29
|
+
|
|
30
|
+
if (charCode > 0xff) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
block = (block << 8) | charCode;
|
|
37
|
+
}
|
|
38
|
+
return output;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
4
41
|
|
|
5
42
|
export class BentoClient {
|
|
6
43
|
private readonly _headers: HeadersInit = {};
|
|
7
44
|
private readonly _baseUrl: string = 'https://app.bentonow.com/api/v1';
|
|
8
45
|
private readonly _siteUuid: string = '';
|
|
9
46
|
private readonly _logErrors: boolean = false;
|
|
47
|
+
private readonly _timeout: number = 30000; // 30 seconds default
|
|
10
48
|
|
|
11
49
|
constructor(options: AnalyticsOptions) {
|
|
12
50
|
this._baseUrl = options.clientOptions?.baseUrl || this._baseUrl;
|
|
13
51
|
this._siteUuid = options.siteUuid;
|
|
14
|
-
this._headers = this._extractHeaders(options.authentication);
|
|
52
|
+
this._headers = this._extractHeaders(options.authentication, options.siteUuid);
|
|
15
53
|
this._logErrors = options.logErrors || false;
|
|
54
|
+
this._timeout = options.clientOptions?.timeout ?? this._timeout;
|
|
16
55
|
}
|
|
17
56
|
|
|
18
57
|
/**
|
|
@@ -23,27 +62,26 @@ export class BentoClient {
|
|
|
23
62
|
* @param payload object
|
|
24
63
|
* @returns Promise\<T\>
|
|
25
64
|
* */
|
|
26
|
-
public get<T>(
|
|
65
|
+
public async get<T>(
|
|
27
66
|
endpoint: string,
|
|
28
|
-
payload: Record<string, unknown> = {}
|
|
67
|
+
payload: Record<string, unknown> = {},
|
|
68
|
+
requestOptions: RequestOptions = {}
|
|
29
69
|
): Promise<T> {
|
|
30
|
-
|
|
31
|
-
|
|
70
|
+
const queryParameters = this._getQueryParameters(payload);
|
|
71
|
+
const url = `${this._baseUrl}${endpoint}?${queryParameters}`;
|
|
32
72
|
|
|
33
|
-
|
|
73
|
+
const timeoutMs =
|
|
74
|
+
requestOptions.timeout === undefined ? this._timeout : requestOptions.timeout;
|
|
75
|
+
const response = await this._fetchWithTimeout(
|
|
76
|
+
url,
|
|
77
|
+
{
|
|
34
78
|
method: 'GET',
|
|
35
79
|
headers: this._headers,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
throw await this._getErrorForResponse(result);
|
|
43
|
-
})
|
|
44
|
-
.then(data => resolve(data))
|
|
45
|
-
.catch(error => reject(error));
|
|
46
|
-
});
|
|
80
|
+
},
|
|
81
|
+
timeoutMs
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return this._handleResponse<T>(response);
|
|
47
85
|
}
|
|
48
86
|
|
|
49
87
|
/**
|
|
@@ -54,47 +92,137 @@ export class BentoClient {
|
|
|
54
92
|
* @param payload object
|
|
55
93
|
* @returns Promise\<T\>
|
|
56
94
|
* */
|
|
57
|
-
public post<T>(
|
|
95
|
+
public async post<T>(
|
|
58
96
|
endpoint: string,
|
|
59
|
-
payload: Record<string, unknown> = {}
|
|
97
|
+
payload: Record<string, unknown> = {},
|
|
98
|
+
requestOptions: RequestOptions = {}
|
|
60
99
|
): Promise<T> {
|
|
61
|
-
|
|
62
|
-
|
|
100
|
+
const body = this._getBody(payload);
|
|
101
|
+
const url = `${this._baseUrl}${endpoint}`;
|
|
63
102
|
|
|
64
|
-
|
|
103
|
+
const timeoutMs =
|
|
104
|
+
requestOptions.timeout === undefined ? this._timeout : requestOptions.timeout;
|
|
105
|
+
const response = await this._fetchWithTimeout(
|
|
106
|
+
url,
|
|
107
|
+
{
|
|
65
108
|
method: 'POST',
|
|
66
109
|
headers: {
|
|
67
110
|
...this._headers,
|
|
68
111
|
'Content-Type': 'application/json',
|
|
69
112
|
},
|
|
70
113
|
body,
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
114
|
+
},
|
|
115
|
+
timeoutMs
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return this._handleResponse<T>(response);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Wraps a PATCH request to the Bento API and automatically adds the required
|
|
123
|
+
* headers.
|
|
124
|
+
*
|
|
125
|
+
* @param endpoint string
|
|
126
|
+
* @param payload object
|
|
127
|
+
* @returns Promise\<T\>
|
|
128
|
+
* */
|
|
129
|
+
public async patch<T>(
|
|
130
|
+
endpoint: string,
|
|
131
|
+
payload: Record<string, unknown> = {},
|
|
132
|
+
requestOptions: RequestOptions = {}
|
|
133
|
+
): Promise<T> {
|
|
134
|
+
const body = this._getBody(payload);
|
|
135
|
+
const url = `${this._baseUrl}${endpoint}`;
|
|
136
|
+
|
|
137
|
+
const timeoutMs =
|
|
138
|
+
requestOptions.timeout === undefined ? this._timeout : requestOptions.timeout;
|
|
139
|
+
const response = await this._fetchWithTimeout(
|
|
140
|
+
url,
|
|
141
|
+
{
|
|
142
|
+
method: 'PATCH',
|
|
143
|
+
headers: {
|
|
144
|
+
...this._headers,
|
|
145
|
+
'Content-Type': 'application/json',
|
|
146
|
+
},
|
|
147
|
+
body,
|
|
148
|
+
},
|
|
149
|
+
timeoutMs
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return this._handleResponse<T>(response);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Performs a fetch request with a configurable timeout.
|
|
157
|
+
*
|
|
158
|
+
* @param url The URL to fetch
|
|
159
|
+
* @param options Fetch options
|
|
160
|
+
* @returns Promise<Response>
|
|
161
|
+
*/
|
|
162
|
+
private async _fetchWithTimeout(
|
|
163
|
+
url: string,
|
|
164
|
+
options: RequestInit,
|
|
165
|
+
timeout: number | null
|
|
166
|
+
): Promise<Response> {
|
|
167
|
+
if (timeout === null) {
|
|
168
|
+
return fetch(url, options);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const controller = new AbortController();
|
|
172
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const response = await fetch(url, {
|
|
176
|
+
...options,
|
|
177
|
+
signal: controller.signal,
|
|
178
|
+
});
|
|
179
|
+
return response;
|
|
180
|
+
} catch (error: unknown) {
|
|
181
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
182
|
+
throw new RequestTimeoutError(`Request timed out after ${timeout}ms`);
|
|
183
|
+
}
|
|
184
|
+
throw error;
|
|
185
|
+
} finally {
|
|
186
|
+
clearTimeout(timeoutId);
|
|
187
|
+
}
|
|
82
188
|
}
|
|
83
189
|
|
|
84
190
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
191
|
+
* Handles the response from a fetch request, parsing JSON or throwing appropriate errors.
|
|
192
|
+
*
|
|
193
|
+
* @param response The fetch Response object
|
|
194
|
+
* @returns Promise<T> The parsed response data
|
|
195
|
+
*/
|
|
196
|
+
private async _handleResponse<T>(response: Response): Promise<T> {
|
|
197
|
+
if (this._isSuccessfulStatus(response.status)) {
|
|
198
|
+
try {
|
|
199
|
+
const data = await response.json();
|
|
200
|
+
return data as T;
|
|
201
|
+
} catch {
|
|
202
|
+
// If JSON parsing fails on a successful response, throw a descriptive error
|
|
203
|
+
throw new Error(`[${response.status}] - Invalid JSON response from server`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
throw await this._getErrorForResponse(response);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Extracts the `publishableKey` and `secretKey` from the `authentication` options,
|
|
212
|
+
* adds the `Authorization` header, and includes a `User-Agent` header with the site UUID.
|
|
87
213
|
*
|
|
88
214
|
* @param authentication AuthenticationOptions
|
|
215
|
+
* @param siteUuid string The site UUID to be included in the User-Agent header
|
|
89
216
|
* @returns HeadersInit
|
|
90
217
|
*/
|
|
91
|
-
private _extractHeaders(authentication: AuthenticationOptions): HeadersInit {
|
|
92
|
-
const authenticationKey =
|
|
218
|
+
private _extractHeaders(authentication: AuthenticationOptions, siteUuid: string): HeadersInit {
|
|
219
|
+
const authenticationKey = encodeBase64(
|
|
93
220
|
`${authentication.publishableKey}:${authentication.secretKey}`
|
|
94
|
-
)
|
|
221
|
+
);
|
|
95
222
|
|
|
96
223
|
return {
|
|
97
224
|
Authorization: `Basic ${authenticationKey}`,
|
|
225
|
+
'User-Agent': `bento-node-${siteUuid}`,
|
|
98
226
|
};
|
|
99
227
|
}
|
|
100
228
|
|
|
@@ -127,7 +255,7 @@ export class BentoClient {
|
|
|
127
255
|
|
|
128
256
|
const queryParameters = new URLSearchParams();
|
|
129
257
|
for (const [key, value] of Object.entries(body)) {
|
|
130
|
-
queryParameters.append(key, value);
|
|
258
|
+
queryParameters.append(key, String(value));
|
|
131
259
|
}
|
|
132
260
|
|
|
133
261
|
return queryParameters.toString();
|
|
@@ -161,17 +289,45 @@ export class BentoClient {
|
|
|
161
289
|
|
|
162
290
|
const contentType = response.headers.get('Content-Type');
|
|
163
291
|
let responseMessage = '';
|
|
292
|
+
let json: Record<string, unknown> | null = null;
|
|
164
293
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
294
|
+
// Try to parse the response body based on content type
|
|
295
|
+
try {
|
|
296
|
+
if (contentType?.toLowerCase().includes('application/json')) {
|
|
297
|
+
// For JSON content type, try to parse as JSON
|
|
298
|
+
try {
|
|
299
|
+
json = await response.json();
|
|
300
|
+
} catch {
|
|
301
|
+
responseMessage = 'Unable to parse JSON response';
|
|
302
|
+
}
|
|
303
|
+
} else if (contentType?.toLowerCase().includes('text/plain')) {
|
|
304
|
+
// For text/plain content type, read as text
|
|
305
|
+
try {
|
|
306
|
+
responseMessage = await response.text();
|
|
307
|
+
} catch {
|
|
308
|
+
responseMessage = 'Unable to read text response';
|
|
309
|
+
}
|
|
310
|
+
} else {
|
|
311
|
+
// For unknown content types, use default message
|
|
173
312
|
responseMessage = 'Unknown response from the Bento API.';
|
|
174
|
-
|
|
313
|
+
}
|
|
314
|
+
} catch {
|
|
315
|
+
responseMessage = 'Unable to read response body';
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Check for author not authorized error in JSON response
|
|
319
|
+
if (json && json.error === 'Author not authorized to send on this account') {
|
|
320
|
+
return new AuthorNotAuthorizedError(json.error as string);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// If we have JSON but no specific error match, use the JSON string
|
|
324
|
+
if (json) {
|
|
325
|
+
responseMessage = JSON.stringify(json);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// If we still don't have a message, use a default
|
|
329
|
+
if (!responseMessage) {
|
|
330
|
+
responseMessage = 'Unknown response from the Bento API.';
|
|
175
331
|
}
|
|
176
332
|
|
|
177
333
|
return new Error(`[${response.status}] - ${responseMessage}`);
|
|
@@ -30,19 +30,14 @@ export class BentoCommands<S> {
|
|
|
30
30
|
* @param parameters \{ email: string, tagName: string \}
|
|
31
31
|
* @returns Promise\<Subscriber | null\>
|
|
32
32
|
*/
|
|
33
|
-
public async addTag(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
email: parameters.email,
|
|
42
|
-
query: parameters.tagName,
|
|
43
|
-
},
|
|
44
|
-
}
|
|
45
|
-
);
|
|
33
|
+
public async addTag(parameters: AddTagParameters): Promise<Subscriber<S> | null> {
|
|
34
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
35
|
+
command: {
|
|
36
|
+
command: CommandTypes.ADD_TAG,
|
|
37
|
+
email: parameters.email,
|
|
38
|
+
query: parameters.tagName,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
46
41
|
|
|
47
42
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
48
43
|
return result.data;
|
|
@@ -54,19 +49,14 @@ export class BentoCommands<S> {
|
|
|
54
49
|
* @param parameters \{ email: string, tagName: string \}
|
|
55
50
|
* @returns Promise\<Subscriber | null\>
|
|
56
51
|
*/
|
|
57
|
-
public async removeTag(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
email: parameters.email,
|
|
66
|
-
query: parameters.tagName,
|
|
67
|
-
},
|
|
68
|
-
}
|
|
69
|
-
);
|
|
52
|
+
public async removeTag(parameters: RemoveTagParameters): Promise<Subscriber<S> | null> {
|
|
53
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
54
|
+
command: {
|
|
55
|
+
command: CommandTypes.REMOVE_TAG,
|
|
56
|
+
email: parameters.email,
|
|
57
|
+
query: parameters.tagName,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
70
60
|
|
|
71
61
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
72
62
|
return result.data;
|
|
@@ -84,19 +74,14 @@ export class BentoCommands<S> {
|
|
|
84
74
|
* @param parameters \{ email: string, field: \{ key: string; value: string; \} \}
|
|
85
75
|
* @returns Promise\<Subscriber | null\>
|
|
86
76
|
*/
|
|
87
|
-
public async addField(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
email: parameters.email,
|
|
96
|
-
query: parameters.field,
|
|
97
|
-
},
|
|
98
|
-
}
|
|
99
|
-
);
|
|
77
|
+
public async addField(parameters: AddFieldParameters<S>): Promise<Subscriber<S> | null> {
|
|
78
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
79
|
+
command: {
|
|
80
|
+
command: CommandTypes.ADD_FIELD,
|
|
81
|
+
email: parameters.email,
|
|
82
|
+
query: parameters.field,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
100
85
|
|
|
101
86
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
102
87
|
return result.data;
|
|
@@ -108,19 +93,14 @@ export class BentoCommands<S> {
|
|
|
108
93
|
* @param parameters \{ email: string, fieldName: string \}
|
|
109
94
|
* @returns Promise\<Subscriber | null\>
|
|
110
95
|
*/
|
|
111
|
-
public async removeField(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
email: parameters.email,
|
|
120
|
-
query: parameters.fieldName,
|
|
121
|
-
},
|
|
122
|
-
}
|
|
123
|
-
);
|
|
96
|
+
public async removeField(parameters: RemoveFieldParameters<S>): Promise<Subscriber<S> | null> {
|
|
97
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
98
|
+
command: {
|
|
99
|
+
command: CommandTypes.REMOVE_FIELD,
|
|
100
|
+
email: parameters.email,
|
|
101
|
+
query: parameters.fieldName,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
124
104
|
|
|
125
105
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
126
106
|
return result.data;
|
|
@@ -136,18 +116,13 @@ export class BentoCommands<S> {
|
|
|
136
116
|
* @param parameters \{ email: string \}
|
|
137
117
|
* @returns Promise\<Subscriber | null\>
|
|
138
118
|
*/
|
|
139
|
-
public async subscribe(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
command: CommandTypes.SUBSCRIBE,
|
|
147
|
-
email: parameters.email,
|
|
148
|
-
},
|
|
149
|
-
}
|
|
150
|
-
);
|
|
119
|
+
public async subscribe(parameters: SubscribeParameters): Promise<Subscriber<S> | null> {
|
|
120
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
121
|
+
command: {
|
|
122
|
+
command: CommandTypes.SUBSCRIBE,
|
|
123
|
+
email: parameters.email,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
151
126
|
|
|
152
127
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
153
128
|
return result.data;
|
|
@@ -164,18 +139,13 @@ export class BentoCommands<S> {
|
|
|
164
139
|
* @param parameters \{ email: string \}
|
|
165
140
|
* @returns Promise\<Subscriber | null\>
|
|
166
141
|
*/
|
|
167
|
-
public async unsubscribe(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
command: CommandTypes.UNSUBSCRIBE,
|
|
175
|
-
email: parameters.email,
|
|
176
|
-
},
|
|
177
|
-
}
|
|
178
|
-
);
|
|
142
|
+
public async unsubscribe(parameters: UnsubscribeParameters): Promise<Subscriber<S> | null> {
|
|
143
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
144
|
+
command: {
|
|
145
|
+
command: CommandTypes.UNSUBSCRIBE,
|
|
146
|
+
email: parameters.email,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
179
149
|
|
|
180
150
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
181
151
|
return result.data;
|
|
@@ -187,19 +157,14 @@ export class BentoCommands<S> {
|
|
|
187
157
|
* @param parameters \{ oldEmail: string, newEmail: string \}
|
|
188
158
|
* @returns Promise\<Subscriber | null\>
|
|
189
159
|
*/
|
|
190
|
-
public async changeEmail(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
email: parameters.oldEmail,
|
|
199
|
-
query: parameters.newEmail,
|
|
200
|
-
},
|
|
201
|
-
}
|
|
202
|
-
);
|
|
160
|
+
public async changeEmail(parameters: ChangeEmailParameters): Promise<Subscriber<S> | null> {
|
|
161
|
+
const result = await this._client.post<DataResponse<Subscriber<S>>>(this._url, {
|
|
162
|
+
command: {
|
|
163
|
+
command: CommandTypes.CHANGE_EMAIL,
|
|
164
|
+
email: parameters.oldEmail,
|
|
165
|
+
query: parameters.newEmail,
|
|
166
|
+
},
|
|
167
|
+
});
|
|
203
168
|
|
|
204
169
|
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
205
170
|
return result.data;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BentoClient } from '../client';
|
|
2
|
+
import type { DataResponse } from '../client/types';
|
|
3
|
+
import type { EmailTemplate, GetEmailTemplateParameters, UpdateEmailTemplateParameters } from './types';
|
|
4
|
+
|
|
5
|
+
export class BentoEmailTemplates {
|
|
6
|
+
private readonly _url = '/fetch/emails/templates';
|
|
7
|
+
|
|
8
|
+
constructor(private readonly _client: BentoClient) {}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns a single email template by ID.
|
|
12
|
+
*
|
|
13
|
+
* @param parameters GetEmailTemplateParameters
|
|
14
|
+
* @returns Promise\<EmailTemplate | null\>
|
|
15
|
+
*/
|
|
16
|
+
public async getEmailTemplate(parameters: GetEmailTemplateParameters): Promise<EmailTemplate | null> {
|
|
17
|
+
const result = await this._client.get<DataResponse<EmailTemplate>>(`${this._url}/${parameters.id}`);
|
|
18
|
+
|
|
19
|
+
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
20
|
+
return result.data;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Updates an email template's subject and/or HTML content.
|
|
25
|
+
*
|
|
26
|
+
* @param parameters UpdateEmailTemplateParameters
|
|
27
|
+
* @returns Promise\<EmailTemplate | null\>
|
|
28
|
+
*/
|
|
29
|
+
public async updateEmailTemplate(parameters: UpdateEmailTemplateParameters): Promise<EmailTemplate | null> {
|
|
30
|
+
const { id, ...updateFields } = parameters;
|
|
31
|
+
|
|
32
|
+
const result = await this._client.patch<DataResponse<EmailTemplate>>(`${this._url}/${id}`, {
|
|
33
|
+
email_template: updateFields,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (Object.keys(result).length === 0 || !result.data) return null;
|
|
37
|
+
return result.data;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BaseEntity } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Email Template Method Parameter Types
|
|
5
|
+
*/
|
|
6
|
+
export type GetEmailTemplateParameters = {
|
|
7
|
+
id: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type UpdateEmailTemplateParameters = {
|
|
11
|
+
id: number;
|
|
12
|
+
subject?: string;
|
|
13
|
+
html?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Core Email Template Types
|
|
18
|
+
*/
|
|
19
|
+
export type EmailTemplateAttributes = {
|
|
20
|
+
name: string;
|
|
21
|
+
subject: string;
|
|
22
|
+
html: string;
|
|
23
|
+
created_at: string;
|
|
24
|
+
stats: Record<string, unknown> | null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type EmailTemplate = BaseEntity<EmailTemplateAttributes>;
|