perspectapi-ts-sdk 1.1.1 → 1.3.0
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 +127 -0
- package/dist/index.d.mts +285 -10
- package/dist/index.d.ts +285 -10
- package/dist/index.js +226 -18
- package/dist/index.mjs +225 -18
- package/package.json +1 -1
- package/src/client/base-client.ts +11 -8
- package/src/client/contact-client.ts +14 -2
- package/src/client/newsletter-client.ts +381 -0
- package/src/index.ts +9 -0
- package/src/perspect-api-client.ts +3 -0
- package/src/types/index.ts +78 -0
- package/src/utils/http-client.ts +13 -8
package/dist/index.mjs
CHANGED
|
@@ -79,26 +79,26 @@ var HttpClient = class {
|
|
|
79
79
|
/**
|
|
80
80
|
* POST request
|
|
81
81
|
*/
|
|
82
|
-
async post(endpoint, body) {
|
|
83
|
-
return this.request(endpoint, { method: "POST", body });
|
|
82
|
+
async post(endpoint, body, options) {
|
|
83
|
+
return this.request(endpoint, { method: "POST", body, ...options });
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* PUT request
|
|
87
87
|
*/
|
|
88
|
-
async put(endpoint, body) {
|
|
89
|
-
return this.request(endpoint, { method: "PUT", body });
|
|
88
|
+
async put(endpoint, body, options) {
|
|
89
|
+
return this.request(endpoint, { method: "PUT", body, ...options });
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* DELETE request
|
|
93
93
|
*/
|
|
94
|
-
async delete(endpoint) {
|
|
95
|
-
return this.request(endpoint, { method: "DELETE" });
|
|
94
|
+
async delete(endpoint, options) {
|
|
95
|
+
return this.request(endpoint, { method: "DELETE", ...options });
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* PATCH request
|
|
99
99
|
*/
|
|
100
|
-
async patch(endpoint, body) {
|
|
101
|
-
return this.request(endpoint, { method: "PATCH", body });
|
|
100
|
+
async patch(endpoint, body, options) {
|
|
101
|
+
return this.request(endpoint, { method: "PATCH", body, ...options });
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
104
|
* Build full URL with query parameters
|
|
@@ -124,6 +124,9 @@ var HttpClient = class {
|
|
|
124
124
|
...this.defaultHeaders,
|
|
125
125
|
...options.headers
|
|
126
126
|
};
|
|
127
|
+
if (options.csrfToken) {
|
|
128
|
+
headers["X-CSRF-Token"] = options.csrfToken;
|
|
129
|
+
}
|
|
127
130
|
const requestOptions = {
|
|
128
131
|
method: options.method || "GET",
|
|
129
132
|
headers
|
|
@@ -247,26 +250,26 @@ var BaseClient = class {
|
|
|
247
250
|
/**
|
|
248
251
|
* Handle create operations
|
|
249
252
|
*/
|
|
250
|
-
async create(endpoint, data) {
|
|
251
|
-
return this.http.post(this.buildPath(endpoint), data);
|
|
253
|
+
async create(endpoint, data, csrfToken) {
|
|
254
|
+
return this.http.post(this.buildPath(endpoint), data, { csrfToken });
|
|
252
255
|
}
|
|
253
256
|
/**
|
|
254
257
|
* Handle update operations
|
|
255
258
|
*/
|
|
256
|
-
async update(endpoint, data) {
|
|
257
|
-
return this.http.put(this.buildPath(endpoint), data);
|
|
259
|
+
async update(endpoint, data, csrfToken) {
|
|
260
|
+
return this.http.put(this.buildPath(endpoint), data, { csrfToken });
|
|
258
261
|
}
|
|
259
262
|
/**
|
|
260
263
|
* Handle partial update operations
|
|
261
264
|
*/
|
|
262
|
-
async patch(endpoint, data) {
|
|
263
|
-
return this.http.patch(this.buildPath(endpoint), data);
|
|
265
|
+
async patch(endpoint, data, csrfToken) {
|
|
266
|
+
return this.http.patch(this.buildPath(endpoint), data, { csrfToken });
|
|
264
267
|
}
|
|
265
268
|
/**
|
|
266
269
|
* Handle delete operations
|
|
267
270
|
*/
|
|
268
|
-
async delete(endpoint) {
|
|
269
|
-
return this.http.delete(this.buildPath(endpoint));
|
|
271
|
+
async delete(endpoint, csrfToken) {
|
|
272
|
+
return this.http.delete(this.buildPath(endpoint), { csrfToken });
|
|
270
273
|
}
|
|
271
274
|
};
|
|
272
275
|
|
|
@@ -1133,9 +1136,15 @@ var ContactClient = class extends BaseClient {
|
|
|
1133
1136
|
}
|
|
1134
1137
|
/**
|
|
1135
1138
|
* Submit contact form
|
|
1139
|
+
* @param siteName - The site to submit contact form to
|
|
1140
|
+
* @param data - Contact form data
|
|
1141
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
1136
1142
|
*/
|
|
1137
|
-
async submitContact(siteName, data) {
|
|
1138
|
-
|
|
1143
|
+
async submitContact(siteName, data, csrfToken) {
|
|
1144
|
+
if (typeof window !== "undefined" && !csrfToken && !data.turnstileToken) {
|
|
1145
|
+
console.warn("CSRF token recommended for browser-based contact form submissions");
|
|
1146
|
+
}
|
|
1147
|
+
return this.create(this.contactEndpoint(siteName, "/contact/submit"), data, csrfToken);
|
|
1139
1148
|
}
|
|
1140
1149
|
/**
|
|
1141
1150
|
* Get contact submission status
|
|
@@ -1217,6 +1226,201 @@ var ContactClient = class extends BaseClient {
|
|
|
1217
1226
|
}
|
|
1218
1227
|
};
|
|
1219
1228
|
|
|
1229
|
+
// src/client/newsletter-client.ts
|
|
1230
|
+
var NewsletterClient = class extends BaseClient {
|
|
1231
|
+
constructor(http) {
|
|
1232
|
+
super(http, "/api/v1");
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Build a newsletter endpoint scoped to a site (without /sites prefix)
|
|
1236
|
+
*/
|
|
1237
|
+
newsletterEndpoint(siteName, endpoint) {
|
|
1238
|
+
return this.siteScopedEndpoint(siteName, endpoint, { includeSitesSegment: false });
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Subscribe to newsletter
|
|
1242
|
+
* @param siteName - The site to subscribe to
|
|
1243
|
+
* @param data - Subscription data
|
|
1244
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
1245
|
+
*/
|
|
1246
|
+
async subscribe(siteName, data, csrfToken) {
|
|
1247
|
+
if (typeof window !== "undefined" && !csrfToken && !data.turnstile_token) {
|
|
1248
|
+
console.warn("CSRF token recommended for browser-based newsletter subscriptions");
|
|
1249
|
+
}
|
|
1250
|
+
return this.create(
|
|
1251
|
+
this.newsletterEndpoint(siteName, "/newsletter/subscribe"),
|
|
1252
|
+
data,
|
|
1253
|
+
csrfToken
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Confirm newsletter subscription via token
|
|
1258
|
+
*/
|
|
1259
|
+
async confirmSubscription(siteName, token) {
|
|
1260
|
+
return this.getSingle(
|
|
1261
|
+
this.newsletterEndpoint(siteName, `/newsletter/confirm/${encodeURIComponent(token)}`)
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Unsubscribe from newsletter
|
|
1266
|
+
* @param siteName - The site to unsubscribe from
|
|
1267
|
+
* @param data - Unsubscribe data
|
|
1268
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
1269
|
+
*/
|
|
1270
|
+
async unsubscribe(siteName, data, csrfToken) {
|
|
1271
|
+
return this.create(
|
|
1272
|
+
this.newsletterEndpoint(siteName, "/newsletter/unsubscribe"),
|
|
1273
|
+
data,
|
|
1274
|
+
csrfToken
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* One-click unsubscribe via token (GET request)
|
|
1279
|
+
*/
|
|
1280
|
+
async unsubscribeByToken(siteName, token) {
|
|
1281
|
+
return this.http.get(
|
|
1282
|
+
this.buildPath(this.newsletterEndpoint(siteName, `/newsletter/unsubscribe/${encodeURIComponent(token)}`))
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Update subscription preferences
|
|
1287
|
+
* @param siteName - The site name
|
|
1288
|
+
* @param email - Subscriber email
|
|
1289
|
+
* @param preferences - New preferences
|
|
1290
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
1291
|
+
*/
|
|
1292
|
+
async updatePreferences(siteName, email, preferences, csrfToken) {
|
|
1293
|
+
return this.patch(
|
|
1294
|
+
this.newsletterEndpoint(siteName, "/newsletter/preferences"),
|
|
1295
|
+
{ email, ...preferences },
|
|
1296
|
+
csrfToken
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Get available newsletter lists
|
|
1301
|
+
*/
|
|
1302
|
+
async getLists(siteName) {
|
|
1303
|
+
return this.getSingle(
|
|
1304
|
+
this.newsletterEndpoint(siteName, "/newsletter/lists")
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Check subscription status by email
|
|
1309
|
+
*/
|
|
1310
|
+
async getStatus(siteName, email) {
|
|
1311
|
+
return this.http.get(
|
|
1312
|
+
this.buildPath(this.newsletterEndpoint(siteName, "/newsletter/status")),
|
|
1313
|
+
{ email }
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
// Admin methods (require authentication)
|
|
1317
|
+
/**
|
|
1318
|
+
* Get all newsletter subscriptions (admin only)
|
|
1319
|
+
*/
|
|
1320
|
+
async getSubscriptions(siteName, params) {
|
|
1321
|
+
return this.getPaginated(
|
|
1322
|
+
this.newsletterEndpoint(siteName, "/newsletter/subscriptions"),
|
|
1323
|
+
params
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* Get subscription by ID (admin only)
|
|
1328
|
+
*/
|
|
1329
|
+
async getSubscriptionById(siteName, id) {
|
|
1330
|
+
return this.getSingle(
|
|
1331
|
+
this.newsletterEndpoint(siteName, `/newsletter/subscriptions/${encodeURIComponent(id)}`)
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Update subscription status (admin only)
|
|
1336
|
+
*/
|
|
1337
|
+
async updateSubscriptionStatus(siteName, id, status, notes) {
|
|
1338
|
+
return this.patch(
|
|
1339
|
+
this.newsletterEndpoint(siteName, `/newsletter/subscriptions/${encodeURIComponent(id)}`),
|
|
1340
|
+
{ status, notes }
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Delete subscription (admin only)
|
|
1345
|
+
*/
|
|
1346
|
+
async deleteSubscription(siteName, id) {
|
|
1347
|
+
return this.delete(
|
|
1348
|
+
this.newsletterEndpoint(siteName, `/newsletter/subscriptions/${encodeURIComponent(id)}`)
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Bulk update subscriptions (admin only)
|
|
1353
|
+
*/
|
|
1354
|
+
async bulkUpdateSubscriptions(siteName, data) {
|
|
1355
|
+
return this.create(
|
|
1356
|
+
this.newsletterEndpoint(siteName, "/newsletter/subscriptions/bulk-update"),
|
|
1357
|
+
data
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Create newsletter list (admin only)
|
|
1362
|
+
*/
|
|
1363
|
+
async createList(siteName, data) {
|
|
1364
|
+
return this.create(
|
|
1365
|
+
this.newsletterEndpoint(siteName, "/newsletter/lists"),
|
|
1366
|
+
data
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* Update newsletter list (admin only)
|
|
1371
|
+
*/
|
|
1372
|
+
async updateList(siteName, listId, data) {
|
|
1373
|
+
return this.update(
|
|
1374
|
+
this.newsletterEndpoint(siteName, `/newsletter/lists/${encodeURIComponent(listId)}`),
|
|
1375
|
+
data
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Delete newsletter list (admin only)
|
|
1380
|
+
*/
|
|
1381
|
+
async deleteList(siteName, listId) {
|
|
1382
|
+
return this.delete(
|
|
1383
|
+
this.newsletterEndpoint(siteName, `/newsletter/lists/${encodeURIComponent(listId)}`)
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Get newsletter statistics (admin only)
|
|
1388
|
+
*/
|
|
1389
|
+
async getStatistics(siteName, params) {
|
|
1390
|
+
return this.http.get(
|
|
1391
|
+
this.buildPath(this.newsletterEndpoint(siteName, "/newsletter/statistics")),
|
|
1392
|
+
params
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* Export newsletter subscriptions (admin only)
|
|
1397
|
+
*/
|
|
1398
|
+
async exportSubscriptions(siteName, params) {
|
|
1399
|
+
return this.create(
|
|
1400
|
+
this.newsletterEndpoint(siteName, "/newsletter/export"),
|
|
1401
|
+
params || {}
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Import newsletter subscriptions (admin only)
|
|
1406
|
+
*/
|
|
1407
|
+
async importSubscriptions(siteName, data) {
|
|
1408
|
+
return this.create(
|
|
1409
|
+
this.newsletterEndpoint(siteName, "/newsletter/import"),
|
|
1410
|
+
data
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Send test newsletter (admin only)
|
|
1415
|
+
*/
|
|
1416
|
+
async sendTestNewsletter(siteName, data) {
|
|
1417
|
+
return this.create(
|
|
1418
|
+
this.newsletterEndpoint(siteName, "/newsletter/test"),
|
|
1419
|
+
data
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1220
1424
|
// src/perspect-api-client.ts
|
|
1221
1425
|
var PerspectApiClient = class {
|
|
1222
1426
|
http;
|
|
@@ -1231,6 +1435,7 @@ var PerspectApiClient = class {
|
|
|
1231
1435
|
webhooks;
|
|
1232
1436
|
checkout;
|
|
1233
1437
|
contact;
|
|
1438
|
+
newsletter;
|
|
1234
1439
|
constructor(config) {
|
|
1235
1440
|
if (!config.baseUrl) {
|
|
1236
1441
|
throw new Error("baseUrl is required in PerspectApiConfig");
|
|
@@ -1246,6 +1451,7 @@ var PerspectApiClient = class {
|
|
|
1246
1451
|
this.webhooks = new WebhooksClient(this.http);
|
|
1247
1452
|
this.checkout = new CheckoutClient(this.http);
|
|
1248
1453
|
this.contact = new ContactClient(this.http);
|
|
1454
|
+
this.newsletter = new NewsletterClient(this.http);
|
|
1249
1455
|
}
|
|
1250
1456
|
/**
|
|
1251
1457
|
* Update authentication token
|
|
@@ -1707,6 +1913,7 @@ export {
|
|
|
1707
1913
|
ContactClient,
|
|
1708
1914
|
ContentClient,
|
|
1709
1915
|
HttpClient,
|
|
1916
|
+
NewsletterClient,
|
|
1710
1917
|
OrganizationsClient,
|
|
1711
1918
|
PerspectApiClient,
|
|
1712
1919
|
ProductsClient,
|
package/package.json
CHANGED
|
@@ -66,9 +66,10 @@ export abstract class BaseClient {
|
|
|
66
66
|
*/
|
|
67
67
|
protected async create<T, R = T>(
|
|
68
68
|
endpoint: string,
|
|
69
|
-
data: T
|
|
69
|
+
data: T,
|
|
70
|
+
csrfToken?: string
|
|
70
71
|
): Promise<ApiResponse<R>> {
|
|
71
|
-
return this.http.post<R>(this.buildPath(endpoint), data);
|
|
72
|
+
return this.http.post<R>(this.buildPath(endpoint), data, { csrfToken });
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
/**
|
|
@@ -76,9 +77,10 @@ export abstract class BaseClient {
|
|
|
76
77
|
*/
|
|
77
78
|
protected async update<T, R = T>(
|
|
78
79
|
endpoint: string,
|
|
79
|
-
data: T
|
|
80
|
+
data: T,
|
|
81
|
+
csrfToken?: string
|
|
80
82
|
): Promise<ApiResponse<R>> {
|
|
81
|
-
return this.http.put<R>(this.buildPath(endpoint), data);
|
|
83
|
+
return this.http.put<R>(this.buildPath(endpoint), data, { csrfToken });
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
/**
|
|
@@ -86,15 +88,16 @@ export abstract class BaseClient {
|
|
|
86
88
|
*/
|
|
87
89
|
protected async patch<T, R = T>(
|
|
88
90
|
endpoint: string,
|
|
89
|
-
data: T
|
|
91
|
+
data: T,
|
|
92
|
+
csrfToken?: string
|
|
90
93
|
): Promise<ApiResponse<R>> {
|
|
91
|
-
return this.http.patch<R>(this.buildPath(endpoint), data);
|
|
94
|
+
return this.http.patch<R>(this.buildPath(endpoint), data, { csrfToken });
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
98
|
* Handle delete operations
|
|
96
99
|
*/
|
|
97
|
-
protected async delete<T = any>(endpoint: string): Promise<ApiResponse<T>> {
|
|
98
|
-
return this.http.delete<T>(this.buildPath(endpoint));
|
|
100
|
+
protected async delete<T = any>(endpoint: string, csrfToken?: string): Promise<ApiResponse<T>> {
|
|
101
|
+
return this.http.delete<T>(this.buildPath(endpoint), { csrfToken });
|
|
99
102
|
}
|
|
100
103
|
}
|
|
@@ -24,17 +24,29 @@ export class ContactClient extends BaseClient {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Submit contact form
|
|
27
|
+
* @param siteName - The site to submit contact form to
|
|
28
|
+
* @param data - Contact form data
|
|
29
|
+
* @param csrfToken - CSRF token (required for browser-based submissions)
|
|
27
30
|
*/
|
|
28
|
-
async submitContact(
|
|
31
|
+
async submitContact(
|
|
32
|
+
siteName: string,
|
|
33
|
+
data: CreateContactRequest,
|
|
34
|
+
csrfToken?: string
|
|
35
|
+
): Promise<ApiResponse<{
|
|
29
36
|
id: string;
|
|
30
37
|
message: string;
|
|
31
38
|
status: string;
|
|
32
39
|
}>> {
|
|
40
|
+
// CSRF token is required for browser submissions
|
|
41
|
+
if (typeof window !== 'undefined' && !csrfToken && !data.turnstileToken) {
|
|
42
|
+
console.warn('CSRF token recommended for browser-based contact form submissions');
|
|
43
|
+
}
|
|
44
|
+
|
|
33
45
|
return this.create<CreateContactRequest, {
|
|
34
46
|
id: string;
|
|
35
47
|
message: string;
|
|
36
48
|
status: string;
|
|
37
|
-
}>(this.contactEndpoint(siteName, '/contact/submit'), data);
|
|
49
|
+
}>(this.contactEndpoint(siteName, '/contact/submit'), data, csrfToken);
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
/**
|