perspectapi-ts-sdk 7.2.8 → 7.4.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/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  PerspectV2Error,
8
8
  createApiError,
9
9
  createPerspectApiV2Client
10
- } from "./chunk-WD62IBI5.mjs";
10
+ } from "./chunk-PWZSSX4V.mjs";
11
11
 
12
12
  // src/deprecation.ts
13
13
  var V1_SUNSET_DATE = "2026-06-01";
@@ -1 +1 @@
1
- export { cq as ApiKeysV2Client, cf as BaseV2Client, ci as CategoriesV2Client, cj as CollectionsV2Client, cn as ContactsV2Client, cg as ContentV2Client, ct as CreditsV2Client, cu as EmailV2Client, cm as NewsletterV2Client, ck as OrdersV2Client, co as OrganizationsV2Client, ay as PerspectApiV2Client, ce as PerspectApiV2Config, aA as PerspectV2Error, ch as ProductsV2Client, cl as SiteUsersV2Client, cp as SitesV2Client, cs as SubscriptionsV2Client, bH as V2ApiKey, bS as V2CancelSubscriptionResult, b4 as V2Category, b5 as V2CategoryCreateParams, b6 as V2CategoryUpdateParams, b7 as V2Collection, b9 as V2CollectionCreateParams, b8 as V2CollectionItem, ba as V2CollectionUpdateParams, bE as V2ContactSubmission, aY as V2Content, aZ as V2ContentCreateParams, a$ as V2ContentListParams, a_ as V2ContentUpdateParams, bU as V2CreditBalance, bT as V2CreditTransaction, aT as V2Deleted, bX as V2EmailSendParams, bY as V2EmailSendResult, aU as V2Error, aV as V2ErrorType, bV as V2GrantCreditParams, bW as V2GrantCreditResult, aS as V2List, aX as V2Media, bv as V2NewsletterCampaign, bC as V2NewsletterImportRequest, bD as V2NewsletterImportResult, bu as V2NewsletterList, bx as V2NewsletterListCreateParams, by as V2NewsletterListUpdateParams, bt as V2NewsletterSubscription, bB as V2NewsletterSubscriptionListMembershipUpdate, bz as V2NewsletterSyncInput, bA as V2NewsletterSyncResult, bw as V2NewsletterTrackingResponse, aR as V2Object, bb as V2Order, bf as V2OrderAddress, bh as V2OrderCreateParams, bm as V2OrderCreateResult, bj as V2OrderFulfillmentNotificationLineItem, bk as V2OrderFulfillmentNotificationParams, bl as V2OrderFulfillmentNotificationResult, bi as V2OrderFulfillmentUpdate, be as V2OrderLineItem, bd as V2OrderLineItemPriceData, bc as V2OrderListParams, bg as V2OrderTaxRequest, bF as V2Organization, aW as V2PaginationParams, b0 as V2Product, b1 as V2ProductCreateParams, b3 as V2ProductListParams, b2 as V2ProductUpdateParams, bG as V2Site, bn as V2SiteUser, bq as V2SiteUserListParams, bp as V2SiteUserMeUpdateParams, bs as V2SiteUserProfile, bM as V2SiteUserSubscription, bo as V2SiteUserUpdateParams, br as V2SiteUserWithProfile, bO as V2SubscriptionCancelParams, bP as V2SubscriptionChangePlanParams, bQ as V2SubscriptionChargeParams, bR as V2SubscriptionChargeResult, bN as V2SubscriptionPauseParams, bJ as V2Webhook, bK as V2WebhookCreateParams, bI as V2WebhookEventType, bL as V2WebhookUpdateParams, cr as WebhooksV2Client, az as createPerspectApiV2Client } from '../index-BbTVcEl5.mjs';
1
+ export { cI as ApiKeysV2Client, cx as BaseV2Client, cA as CategoriesV2Client, cB as CollectionsV2Client, cF as ContactsV2Client, cy as ContentV2Client, cL as CreditsV2Client, cN as EmailTemplatesV2Client, cM as EmailV2Client, cE as NewsletterV2Client, cC as OrdersV2Client, cG as OrganizationsV2Client, ay as PerspectApiV2Client, cw as PerspectApiV2Config, aA as PerspectV2Error, cz as ProductsV2Client, cD as SiteUsersV2Client, cH as SitesV2Client, cK as SubscriptionsV2Client, bS as V2ApiKey, c1 as V2CancelSubscriptionResult, b4 as V2Category, b5 as V2CategoryCreateParams, b6 as V2CategoryUpdateParams, b7 as V2Collection, b9 as V2CollectionCreateParams, b8 as V2CollectionItem, ba as V2CollectionUpdateParams, bP as V2ContactSubmission, aY as V2Content, aZ as V2ContentCreateParams, a$ as V2ContentListParams, a_ as V2ContentUpdateParams, c3 as V2CreditBalance, c2 as V2CreditTransaction, aT as V2Deleted, c8 as V2EmailSendParams, ce as V2EmailSendResult, c9 as V2EmailTemplate, cd as V2EmailTemplateCloneParams, cc as V2EmailTemplateCreateParams, cb as V2EmailTemplateListParams, c7 as V2EmailTemplateStatus, c6 as V2EmailTemplateType, ca as V2EmailTemplateType_Listing, aU as V2Error, aV as V2ErrorType, c4 as V2GrantCreditParams, c5 as V2GrantCreditResult, aS as V2List, aX as V2Media, bN as V2NewsletterBulkParams, bO as V2NewsletterBulkResult, bw as V2NewsletterCampaign, bH as V2NewsletterCampaignCreateParams, bv as V2NewsletterCampaignStatus, bI as V2NewsletterCampaignUpdateParams, bF as V2NewsletterImportRequest, bG as V2NewsletterImportResult, bu as V2NewsletterList, bA as V2NewsletterListCreateParams, bB as V2NewsletterListUpdateParams, bx as V2NewsletterSeries, bJ as V2NewsletterSeriesCreateParams, bK as V2NewsletterSeriesUpdateParams, by as V2NewsletterStatistics, bL as V2NewsletterStatisticsParams, bt as V2NewsletterSubscription, bE as V2NewsletterSubscriptionListMembershipUpdate, bM as V2NewsletterSubscriptionStatusUpdate, bC as V2NewsletterSyncInput, bD as V2NewsletterSyncResult, bz as V2NewsletterTrackingResponse, aR as V2Object, bb as V2Order, bf as V2OrderAddress, bh as V2OrderCreateParams, bm as V2OrderCreateResult, bj as V2OrderFulfillmentNotificationLineItem, bk as V2OrderFulfillmentNotificationParams, bl as V2OrderFulfillmentNotificationResult, bi as V2OrderFulfillmentUpdate, be as V2OrderLineItem, bd as V2OrderLineItemPriceData, bc as V2OrderListParams, bg as V2OrderTaxRequest, bQ as V2Organization, aW as V2PaginationParams, b0 as V2Product, b1 as V2ProductCreateParams, b3 as V2ProductListParams, b2 as V2ProductUpdateParams, bR as V2Site, bn as V2SiteUser, bq as V2SiteUserListParams, bp as V2SiteUserMeUpdateParams, bs as V2SiteUserProfile, bX as V2SiteUserSubscription, bo as V2SiteUserUpdateParams, br as V2SiteUserWithProfile, bZ as V2SubscriptionCancelParams, b_ as V2SubscriptionChangePlanParams, b$ as V2SubscriptionChargeParams, c0 as V2SubscriptionChargeResult, bY as V2SubscriptionPauseParams, bU as V2Webhook, bV as V2WebhookCreateParams, bT as V2WebhookEventType, bW as V2WebhookUpdateParams, cJ as WebhooksV2Client, az as createPerspectApiV2Client } from '../index-CmcHYKO8.mjs';
@@ -1 +1 @@
1
- export { cq as ApiKeysV2Client, cf as BaseV2Client, ci as CategoriesV2Client, cj as CollectionsV2Client, cn as ContactsV2Client, cg as ContentV2Client, ct as CreditsV2Client, cu as EmailV2Client, cm as NewsletterV2Client, ck as OrdersV2Client, co as OrganizationsV2Client, ay as PerspectApiV2Client, ce as PerspectApiV2Config, aA as PerspectV2Error, ch as ProductsV2Client, cl as SiteUsersV2Client, cp as SitesV2Client, cs as SubscriptionsV2Client, bH as V2ApiKey, bS as V2CancelSubscriptionResult, b4 as V2Category, b5 as V2CategoryCreateParams, b6 as V2CategoryUpdateParams, b7 as V2Collection, b9 as V2CollectionCreateParams, b8 as V2CollectionItem, ba as V2CollectionUpdateParams, bE as V2ContactSubmission, aY as V2Content, aZ as V2ContentCreateParams, a$ as V2ContentListParams, a_ as V2ContentUpdateParams, bU as V2CreditBalance, bT as V2CreditTransaction, aT as V2Deleted, bX as V2EmailSendParams, bY as V2EmailSendResult, aU as V2Error, aV as V2ErrorType, bV as V2GrantCreditParams, bW as V2GrantCreditResult, aS as V2List, aX as V2Media, bv as V2NewsletterCampaign, bC as V2NewsletterImportRequest, bD as V2NewsletterImportResult, bu as V2NewsletterList, bx as V2NewsletterListCreateParams, by as V2NewsletterListUpdateParams, bt as V2NewsletterSubscription, bB as V2NewsletterSubscriptionListMembershipUpdate, bz as V2NewsletterSyncInput, bA as V2NewsletterSyncResult, bw as V2NewsletterTrackingResponse, aR as V2Object, bb as V2Order, bf as V2OrderAddress, bh as V2OrderCreateParams, bm as V2OrderCreateResult, bj as V2OrderFulfillmentNotificationLineItem, bk as V2OrderFulfillmentNotificationParams, bl as V2OrderFulfillmentNotificationResult, bi as V2OrderFulfillmentUpdate, be as V2OrderLineItem, bd as V2OrderLineItemPriceData, bc as V2OrderListParams, bg as V2OrderTaxRequest, bF as V2Organization, aW as V2PaginationParams, b0 as V2Product, b1 as V2ProductCreateParams, b3 as V2ProductListParams, b2 as V2ProductUpdateParams, bG as V2Site, bn as V2SiteUser, bq as V2SiteUserListParams, bp as V2SiteUserMeUpdateParams, bs as V2SiteUserProfile, bM as V2SiteUserSubscription, bo as V2SiteUserUpdateParams, br as V2SiteUserWithProfile, bO as V2SubscriptionCancelParams, bP as V2SubscriptionChangePlanParams, bQ as V2SubscriptionChargeParams, bR as V2SubscriptionChargeResult, bN as V2SubscriptionPauseParams, bJ as V2Webhook, bK as V2WebhookCreateParams, bI as V2WebhookEventType, bL as V2WebhookUpdateParams, cr as WebhooksV2Client, az as createPerspectApiV2Client } from '../index-BbTVcEl5.js';
1
+ export { cI as ApiKeysV2Client, cx as BaseV2Client, cA as CategoriesV2Client, cB as CollectionsV2Client, cF as ContactsV2Client, cy as ContentV2Client, cL as CreditsV2Client, cN as EmailTemplatesV2Client, cM as EmailV2Client, cE as NewsletterV2Client, cC as OrdersV2Client, cG as OrganizationsV2Client, ay as PerspectApiV2Client, cw as PerspectApiV2Config, aA as PerspectV2Error, cz as ProductsV2Client, cD as SiteUsersV2Client, cH as SitesV2Client, cK as SubscriptionsV2Client, bS as V2ApiKey, c1 as V2CancelSubscriptionResult, b4 as V2Category, b5 as V2CategoryCreateParams, b6 as V2CategoryUpdateParams, b7 as V2Collection, b9 as V2CollectionCreateParams, b8 as V2CollectionItem, ba as V2CollectionUpdateParams, bP as V2ContactSubmission, aY as V2Content, aZ as V2ContentCreateParams, a$ as V2ContentListParams, a_ as V2ContentUpdateParams, c3 as V2CreditBalance, c2 as V2CreditTransaction, aT as V2Deleted, c8 as V2EmailSendParams, ce as V2EmailSendResult, c9 as V2EmailTemplate, cd as V2EmailTemplateCloneParams, cc as V2EmailTemplateCreateParams, cb as V2EmailTemplateListParams, c7 as V2EmailTemplateStatus, c6 as V2EmailTemplateType, ca as V2EmailTemplateType_Listing, aU as V2Error, aV as V2ErrorType, c4 as V2GrantCreditParams, c5 as V2GrantCreditResult, aS as V2List, aX as V2Media, bN as V2NewsletterBulkParams, bO as V2NewsletterBulkResult, bw as V2NewsletterCampaign, bH as V2NewsletterCampaignCreateParams, bv as V2NewsletterCampaignStatus, bI as V2NewsletterCampaignUpdateParams, bF as V2NewsletterImportRequest, bG as V2NewsletterImportResult, bu as V2NewsletterList, bA as V2NewsletterListCreateParams, bB as V2NewsletterListUpdateParams, bx as V2NewsletterSeries, bJ as V2NewsletterSeriesCreateParams, bK as V2NewsletterSeriesUpdateParams, by as V2NewsletterStatistics, bL as V2NewsletterStatisticsParams, bt as V2NewsletterSubscription, bE as V2NewsletterSubscriptionListMembershipUpdate, bM as V2NewsletterSubscriptionStatusUpdate, bC as V2NewsletterSyncInput, bD as V2NewsletterSyncResult, bz as V2NewsletterTrackingResponse, aR as V2Object, bb as V2Order, bf as V2OrderAddress, bh as V2OrderCreateParams, bm as V2OrderCreateResult, bj as V2OrderFulfillmentNotificationLineItem, bk as V2OrderFulfillmentNotificationParams, bl as V2OrderFulfillmentNotificationResult, bi as V2OrderFulfillmentUpdate, be as V2OrderLineItem, bd as V2OrderLineItemPriceData, bc as V2OrderListParams, bg as V2OrderTaxRequest, bQ as V2Organization, aW as V2PaginationParams, b0 as V2Product, b1 as V2ProductCreateParams, b3 as V2ProductListParams, b2 as V2ProductUpdateParams, bR as V2Site, bn as V2SiteUser, bq as V2SiteUserListParams, bp as V2SiteUserMeUpdateParams, bs as V2SiteUserProfile, bX as V2SiteUserSubscription, bo as V2SiteUserUpdateParams, br as V2SiteUserWithProfile, bZ as V2SubscriptionCancelParams, b_ as V2SubscriptionChangePlanParams, b$ as V2SubscriptionChargeParams, c0 as V2SubscriptionChargeResult, bY as V2SubscriptionPauseParams, bU as V2Webhook, bV as V2WebhookCreateParams, bT as V2WebhookEventType, bW as V2WebhookUpdateParams, cJ as WebhooksV2Client, az as createPerspectApiV2Client } from '../index-CmcHYKO8.js';
package/dist/v2/index.js CHANGED
@@ -27,6 +27,7 @@ __export(v2_exports, {
27
27
  ContactsV2Client: () => ContactsV2Client,
28
28
  ContentV2Client: () => ContentV2Client,
29
29
  CreditsV2Client: () => CreditsV2Client,
30
+ EmailTemplatesV2Client: () => EmailTemplatesV2Client,
30
31
  EmailV2Client: () => EmailV2Client,
31
32
  NewsletterV2Client: () => NewsletterV2Client,
32
33
  OrdersV2Client: () => OrdersV2Client,
@@ -140,6 +141,8 @@ var HttpClient = class {
140
141
  }
141
142
  this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
142
143
  let lastError;
144
+ const method = (options.method || "GET").toUpperCase();
145
+ const isIdempotent = method === "GET" || method === "HEAD";
143
146
  for (let attempt = 0; attempt <= this.retries; attempt++) {
144
147
  try {
145
148
  const response = await this.fetchWithTimeout(url, requestOptions);
@@ -149,6 +152,9 @@ var HttpClient = class {
149
152
  if (error && typeof error === "object" && "status" in error && typeof error.status === "number" && error.status < 500) {
150
153
  throw error;
151
154
  }
155
+ if (!isIdempotent) {
156
+ throw error;
157
+ }
152
158
  if (attempt === this.retries) {
153
159
  break;
154
160
  }
@@ -1293,6 +1299,97 @@ var NewsletterV2Client = class extends BaseV2Client {
1293
1299
  data
1294
1300
  );
1295
1301
  }
1302
+ // --- Lists (get by id) ---
1303
+ async getListById(siteName, id, cachePolicy) {
1304
+ return this.getOne(
1305
+ this.sitePath(siteName, "newsletter", `lists/${encodeURIComponent(id)}`),
1306
+ void 0,
1307
+ cachePolicy
1308
+ );
1309
+ }
1310
+ // --- Subscriptions (admin: lookup / status / delete / bulk) ---
1311
+ async getSubscriptionByEmail(siteName, email, cachePolicy) {
1312
+ return this.getOne(
1313
+ this.sitePath(siteName, "newsletter", "subscriptions/by-email"),
1314
+ { email },
1315
+ cachePolicy
1316
+ );
1317
+ }
1318
+ async updateSubscriptionStatus(siteName, id, data) {
1319
+ return this.post(
1320
+ this.sitePath(siteName, "newsletter", `subscriptions/${encodeURIComponent(id)}/status`),
1321
+ data
1322
+ );
1323
+ }
1324
+ async deleteSubscription(siteName, id) {
1325
+ return this.deleteOne(
1326
+ this.sitePath(siteName, "newsletter", `subscriptions/${encodeURIComponent(id)}`)
1327
+ );
1328
+ }
1329
+ async bulkUpdateSubscriptions(siteName, data) {
1330
+ return this.post(
1331
+ this.sitePath(siteName, "newsletter", "subscriptions/bulk"),
1332
+ data
1333
+ );
1334
+ }
1335
+ // --- Statistics ---
1336
+ async getStatistics(siteName, params, cachePolicy) {
1337
+ return this.getOne(
1338
+ this.sitePath(siteName, "newsletter", "statistics"),
1339
+ params,
1340
+ cachePolicy
1341
+ );
1342
+ }
1343
+ // --- Campaigns (create / update / delete) ---
1344
+ async createCampaign(siteName, data) {
1345
+ return this.post(
1346
+ this.sitePath(siteName, "newsletter", "campaigns"),
1347
+ data
1348
+ );
1349
+ }
1350
+ async updateCampaign(siteName, id, data) {
1351
+ return this.patchOne(
1352
+ this.sitePath(siteName, "newsletter", `campaigns/${encodeURIComponent(id)}`),
1353
+ data
1354
+ );
1355
+ }
1356
+ async deleteCampaign(siteName, id) {
1357
+ return this.deleteOne(
1358
+ this.sitePath(siteName, "newsletter", `campaigns/${encodeURIComponent(id)}`)
1359
+ );
1360
+ }
1361
+ // --- Series ---
1362
+ async listSeries(siteName, params, cachePolicy) {
1363
+ return this.getList(
1364
+ this.sitePath(siteName, "newsletter", "series"),
1365
+ params,
1366
+ cachePolicy
1367
+ );
1368
+ }
1369
+ async getSeries(siteName, id, cachePolicy) {
1370
+ return this.getOne(
1371
+ this.sitePath(siteName, "newsletter", `series/${encodeURIComponent(id)}`),
1372
+ void 0,
1373
+ cachePolicy
1374
+ );
1375
+ }
1376
+ async createSeries(siteName, data) {
1377
+ return this.post(
1378
+ this.sitePath(siteName, "newsletter", "series"),
1379
+ data
1380
+ );
1381
+ }
1382
+ async updateSeries(siteName, id, data) {
1383
+ return this.patchOne(
1384
+ this.sitePath(siteName, "newsletter", `series/${encodeURIComponent(id)}`),
1385
+ data
1386
+ );
1387
+ }
1388
+ async deleteSeries(siteName, id) {
1389
+ return this.deleteOne(
1390
+ this.sitePath(siteName, "newsletter", `series/${encodeURIComponent(id)}`)
1391
+ );
1392
+ }
1296
1393
  };
1297
1394
 
1298
1395
  // src/v2/client/contacts-client.ts
@@ -1481,11 +1578,18 @@ var CreditsV2Client = class extends BaseV2Client {
1481
1578
  // src/v2/client/email-client.ts
1482
1579
  var EmailV2Client = class extends BaseV2Client {
1483
1580
  /**
1484
- * Send a transactional email using the site's configured email provider.
1581
+ * Send a transactional email through the site's email provider.
1582
+ *
1583
+ * Requires a server-side API key — never call this from a browser. Sites
1584
+ * without a configured provider fall back to the platform default with
1585
+ * policy restrictions (owner-only recipients, daily quota).
1485
1586
  *
1486
- * Requires a server-side API key never call this from a browser.
1487
- * The site must have an email provider configured in its settings.
1488
- * At least one of `html` or `text` must be provided.
1587
+ * Provide content one of two ways (mutually exclusive):
1588
+ * - Raw: `subject` plus at least one of `html` / `text`.
1589
+ * - Template: `template_type` (published template for that type) or
1590
+ * `template_id` (published template by ID) plus optional `variables`; the
1591
+ * template is rendered server-side. `subject` is optional here and
1592
+ * overrides the rendered one.
1489
1593
  */
1490
1594
  async send(siteName, params) {
1491
1595
  return this.post(
@@ -1495,6 +1599,66 @@ var EmailV2Client = class extends BaseV2Client {
1495
1599
  }
1496
1600
  };
1497
1601
 
1602
+ // src/v2/client/email-templates-client.ts
1603
+ var EmailTemplatesV2Client = class extends BaseV2Client {
1604
+ path(siteName, suffix = "") {
1605
+ return this.sitePath(siteName, "email", suffix ? `templates/${suffix}` : "templates");
1606
+ }
1607
+ /** List every supported template type with its allowed variables. */
1608
+ async listTypes(siteName, cachePolicy) {
1609
+ return this.getList(
1610
+ this.path(siteName, "types"),
1611
+ void 0,
1612
+ cachePolicy
1613
+ );
1614
+ }
1615
+ /** Get the allowed variables for a single template type. */
1616
+ async getTypeVariables(siteName, templateType, cachePolicy) {
1617
+ return this.getOne(
1618
+ this.path(siteName, `types/${templateType}`),
1619
+ void 0,
1620
+ cachePolicy
1621
+ );
1622
+ }
1623
+ /** List template versions, optionally filtered by type and/or status. */
1624
+ async list(siteName, params, cachePolicy) {
1625
+ return this.getList(this.path(siteName), params, cachePolicy);
1626
+ }
1627
+ /** Get a specific template version by ID (`etpl_…`). */
1628
+ async get(siteName, templateId, cachePolicy) {
1629
+ return this.getOne(
1630
+ this.path(siteName, encodeURIComponent(templateId)),
1631
+ void 0,
1632
+ cachePolicy
1633
+ );
1634
+ }
1635
+ /** Get the currently published version for a template type. */
1636
+ async getPublished(siteName, templateType, cachePolicy) {
1637
+ return this.getOne(
1638
+ this.path(siteName, `published/${templateType}`),
1639
+ void 0,
1640
+ cachePolicy
1641
+ );
1642
+ }
1643
+ /** Create a new template version. */
1644
+ async create(siteName, params) {
1645
+ return this.post(this.path(siteName), params);
1646
+ }
1647
+ /** Clone a template version, optionally overriding fields. */
1648
+ async clone(siteName, templateId, params) {
1649
+ return this.post(
1650
+ this.path(siteName, `${encodeURIComponent(templateId)}/clone`),
1651
+ params ?? {}
1652
+ );
1653
+ }
1654
+ /** Publish a template version (archives the previously published one). */
1655
+ async publish(siteName, templateId) {
1656
+ return this.post(
1657
+ this.path(siteName, `${encodeURIComponent(templateId)}/publish`)
1658
+ );
1659
+ }
1660
+ };
1661
+
1498
1662
  // src/v2/index.ts
1499
1663
  var PerspectApiV2Client = class {
1500
1664
  http;
@@ -1514,6 +1678,7 @@ var PerspectApiV2Client = class {
1514
1678
  subscriptions;
1515
1679
  credits;
1516
1680
  email;
1681
+ emailTemplates;
1517
1682
  constructor(config) {
1518
1683
  const baseUrl = config.baseUrl.replace(/\/+$/, "");
1519
1684
  const v2BaseUrl = baseUrl.endsWith("/api/v2") ? baseUrl : `${baseUrl}/api/v2`;
@@ -1536,6 +1701,7 @@ var PerspectApiV2Client = class {
1536
1701
  this.subscriptions = new SubscriptionsV2Client(this.http, basePath, cache);
1537
1702
  this.credits = new CreditsV2Client(this.http, basePath, cache);
1538
1703
  this.email = new EmailV2Client(this.http, basePath, cache);
1704
+ this.emailTemplates = new EmailTemplatesV2Client(this.http, basePath, cache);
1539
1705
  }
1540
1706
  /** Update the JWT token for authenticated requests. */
1541
1707
  setAuth(jwt) {
@@ -1562,6 +1728,7 @@ function createPerspectApiV2Client(config) {
1562
1728
  ContactsV2Client,
1563
1729
  ContentV2Client,
1564
1730
  CreditsV2Client,
1731
+ EmailTemplatesV2Client,
1565
1732
  EmailV2Client,
1566
1733
  NewsletterV2Client,
1567
1734
  OrdersV2Client,
package/dist/v2/index.mjs CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  ContactsV2Client,
7
7
  ContentV2Client,
8
8
  CreditsV2Client,
9
+ EmailTemplatesV2Client,
9
10
  EmailV2Client,
10
11
  NewsletterV2Client,
11
12
  OrdersV2Client,
@@ -18,7 +19,7 @@ import {
18
19
  SubscriptionsV2Client,
19
20
  WebhooksV2Client,
20
21
  createPerspectApiV2Client
21
- } from "../chunk-WD62IBI5.mjs";
22
+ } from "../chunk-PWZSSX4V.mjs";
22
23
  export {
23
24
  ApiKeysV2Client,
24
25
  BaseV2Client,
@@ -27,6 +28,7 @@ export {
27
28
  ContactsV2Client,
28
29
  ContentV2Client,
29
30
  CreditsV2Client,
31
+ EmailTemplatesV2Client,
30
32
  EmailV2Client,
31
33
  NewsletterV2Client,
32
34
  OrdersV2Client,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perspectapi-ts-sdk",
3
- "version": "7.2.8",
3
+ "version": "7.4.0",
4
4
  "description": "TypeScript SDK for PerspectAPI - Cloudflare Workers compatible",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -115,25 +115,37 @@ export class HttpClient {
115
115
  this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
116
116
 
117
117
  let lastError: Error;
118
-
118
+
119
+ // Only retry idempotent methods. Retrying POST/PATCH/PUT/DELETE on a
120
+ // timeout or 5xx can duplicate a side effect the server already applied
121
+ // (e.g. send the same transactional email twice, create two campaigns).
122
+ const method = (options.method || 'GET').toUpperCase();
123
+ const isIdempotent = method === 'GET' || method === 'HEAD';
124
+
119
125
  for (let attempt = 0; attempt <= this.retries; attempt++) {
120
126
  try {
121
127
  const response = await this.fetchWithTimeout(url, requestOptions);
122
128
  return await this.handleResponse<T>(response);
123
129
  } catch (error) {
124
130
  lastError = error as Error;
125
-
131
+
126
132
  // Don't retry on client errors (4xx)
127
- if (error && typeof error === 'object' && 'status' in error &&
133
+ if (error && typeof error === 'object' && 'status' in error &&
128
134
  typeof (error as any).status === 'number' && (error as any).status < 500) {
129
135
  throw error;
130
136
  }
131
-
137
+
138
+ // Don't retry non-idempotent methods — the request may have been
139
+ // applied server-side even though we saw a timeout/5xx.
140
+ if (!isIdempotent) {
141
+ throw error;
142
+ }
143
+
132
144
  // Don't retry on last attempt
133
145
  if (attempt === this.retries) {
134
146
  break;
135
147
  }
136
-
148
+
137
149
  // Exponential backoff
138
150
  await this.delay(Math.pow(2, attempt) * 1000);
139
151
  }
@@ -8,11 +8,18 @@ import type { V2EmailSendParams, V2EmailSendResult } from '../types';
8
8
  export class EmailV2Client extends BaseV2Client {
9
9
 
10
10
  /**
11
- * Send a transactional email using the site's configured email provider.
11
+ * Send a transactional email through the site's email provider.
12
12
  *
13
- * Requires a server-side API key — never call this from a browser.
14
- * The site must have an email provider configured in its settings.
15
- * At least one of `html` or `text` must be provided.
13
+ * Requires a server-side API key — never call this from a browser. Sites
14
+ * without a configured provider fall back to the platform default with
15
+ * policy restrictions (owner-only recipients, daily quota).
16
+ *
17
+ * Provide content one of two ways (mutually exclusive):
18
+ * - Raw: `subject` plus at least one of `html` / `text`.
19
+ * - Template: `template_type` (published template for that type) or
20
+ * `template_id` (published template by ID) plus optional `variables`; the
21
+ * template is rendered server-side. `subject` is optional here and
22
+ * overrides the rendered one.
16
23
  */
17
24
  async send(siteName: string, params: V2EmailSendParams): Promise<V2EmailSendResult> {
18
25
  return this.post<V2EmailSendResult>(
@@ -0,0 +1,113 @@
1
+ /**
2
+ * v2 Email Templates Client — versioned CRUD for site email templates.
3
+ *
4
+ * Mirrors the email_template_* MCP tools. Templates live under
5
+ * /sites/:siteName/email/templates. Use `listTypes` / `getTypeVariables` to
6
+ * discover the allowed substitution variables for each template type before
7
+ * authoring, then create/clone/publish versions.
8
+ */
9
+
10
+ import { BaseV2Client } from './base-v2-client';
11
+ import type { CachePolicy } from '../../cache/types';
12
+ import type {
13
+ V2EmailTemplate,
14
+ V2EmailTemplateType,
15
+ V2EmailTemplateType_Listing,
16
+ V2EmailTemplateListParams,
17
+ V2EmailTemplateCreateParams,
18
+ V2EmailTemplateCloneParams,
19
+ V2List,
20
+ } from '../types';
21
+
22
+ export class EmailTemplatesV2Client extends BaseV2Client {
23
+ private path(siteName: string, suffix = ''): string {
24
+ return this.sitePath(siteName, 'email', suffix ? `templates/${suffix}` : 'templates');
25
+ }
26
+
27
+ /** List every supported template type with its allowed variables. */
28
+ async listTypes(
29
+ siteName: string,
30
+ cachePolicy?: CachePolicy,
31
+ ): Promise<V2List<V2EmailTemplateType_Listing>> {
32
+ return this.getList<V2EmailTemplateType_Listing>(
33
+ this.path(siteName, 'types'),
34
+ undefined,
35
+ cachePolicy,
36
+ );
37
+ }
38
+
39
+ /** Get the allowed variables for a single template type. */
40
+ async getTypeVariables(
41
+ siteName: string,
42
+ templateType: V2EmailTemplateType,
43
+ cachePolicy?: CachePolicy,
44
+ ): Promise<V2EmailTemplateType_Listing> {
45
+ return this.getOne<V2EmailTemplateType_Listing>(
46
+ this.path(siteName, `types/${templateType}`),
47
+ undefined,
48
+ cachePolicy,
49
+ );
50
+ }
51
+
52
+ /** List template versions, optionally filtered by type and/or status. */
53
+ async list(
54
+ siteName: string,
55
+ params?: V2EmailTemplateListParams,
56
+ cachePolicy?: CachePolicy,
57
+ ): Promise<V2List<V2EmailTemplate>> {
58
+ return this.getList<V2EmailTemplate>(this.path(siteName), params, cachePolicy);
59
+ }
60
+
61
+ /** Get a specific template version by ID (`etpl_…`). */
62
+ async get(
63
+ siteName: string,
64
+ templateId: string,
65
+ cachePolicy?: CachePolicy,
66
+ ): Promise<V2EmailTemplate> {
67
+ return this.getOne<V2EmailTemplate>(
68
+ this.path(siteName, encodeURIComponent(templateId)),
69
+ undefined,
70
+ cachePolicy,
71
+ );
72
+ }
73
+
74
+ /** Get the currently published version for a template type. */
75
+ async getPublished(
76
+ siteName: string,
77
+ templateType: V2EmailTemplateType,
78
+ cachePolicy?: CachePolicy,
79
+ ): Promise<V2EmailTemplate> {
80
+ return this.getOne<V2EmailTemplate>(
81
+ this.path(siteName, `published/${templateType}`),
82
+ undefined,
83
+ cachePolicy,
84
+ );
85
+ }
86
+
87
+ /** Create a new template version. */
88
+ async create(
89
+ siteName: string,
90
+ params: V2EmailTemplateCreateParams,
91
+ ): Promise<V2EmailTemplate> {
92
+ return this.post<V2EmailTemplate>(this.path(siteName), params);
93
+ }
94
+
95
+ /** Clone a template version, optionally overriding fields. */
96
+ async clone(
97
+ siteName: string,
98
+ templateId: string,
99
+ params?: V2EmailTemplateCloneParams,
100
+ ): Promise<V2EmailTemplate> {
101
+ return this.post<V2EmailTemplate>(
102
+ this.path(siteName, `${encodeURIComponent(templateId)}/clone`),
103
+ params ?? {},
104
+ );
105
+ }
106
+
107
+ /** Publish a template version (archives the previously published one). */
108
+ async publish(siteName: string, templateId: string): Promise<V2EmailTemplate> {
109
+ return this.post<V2EmailTemplate>(
110
+ this.path(siteName, `${encodeURIComponent(templateId)}/publish`),
111
+ );
112
+ }
113
+ }
@@ -6,11 +6,16 @@ import { BaseV2Client } from './base-v2-client';
6
6
  import type { CachePolicy } from '../../cache/types';
7
7
  import type {
8
8
  V2NewsletterSubscription, V2NewsletterList, V2NewsletterCampaign,
9
+ V2NewsletterSeries, V2NewsletterStatistics,
9
10
  V2PaginationParams, V2List, V2Deleted, V2NewsletterTrackingResponse,
10
11
  V2NewsletterListCreateParams, V2NewsletterListUpdateParams,
11
12
  V2NewsletterSyncInput, V2NewsletterSyncResult,
12
13
  V2NewsletterSubscriptionListMembershipUpdate,
13
14
  V2NewsletterImportRequest, V2NewsletterImportResult,
15
+ V2NewsletterCampaignCreateParams, V2NewsletterCampaignUpdateParams,
16
+ V2NewsletterSeriesCreateParams, V2NewsletterSeriesUpdateParams,
17
+ V2NewsletterStatisticsParams, V2NewsletterSubscriptionStatusUpdate,
18
+ V2NewsletterBulkParams, V2NewsletterBulkResult,
14
19
  } from '../types';
15
20
 
16
21
  export class NewsletterV2Client extends BaseV2Client {
@@ -206,4 +211,155 @@ export class NewsletterV2Client extends BaseV2Client {
206
211
  data,
207
212
  );
208
213
  }
214
+
215
+ // --- Lists (get by id) ---
216
+
217
+ async getListById(
218
+ siteName: string,
219
+ id: string,
220
+ cachePolicy?: CachePolicy,
221
+ ): Promise<V2NewsletterList> {
222
+ return this.getOne<V2NewsletterList>(
223
+ this.sitePath(siteName, 'newsletter', `lists/${encodeURIComponent(id)}`),
224
+ undefined,
225
+ cachePolicy,
226
+ );
227
+ }
228
+
229
+ // --- Subscriptions (admin: lookup / status / delete / bulk) ---
230
+
231
+ async getSubscriptionByEmail(
232
+ siteName: string,
233
+ email: string,
234
+ cachePolicy?: CachePolicy,
235
+ ): Promise<V2NewsletterSubscription> {
236
+ return this.getOne<V2NewsletterSubscription>(
237
+ this.sitePath(siteName, 'newsletter', 'subscriptions/by-email'),
238
+ { email },
239
+ cachePolicy,
240
+ );
241
+ }
242
+
243
+ async updateSubscriptionStatus(
244
+ siteName: string,
245
+ id: string,
246
+ data: V2NewsletterSubscriptionStatusUpdate,
247
+ ): Promise<V2NewsletterSubscription> {
248
+ return this.post<V2NewsletterSubscription>(
249
+ this.sitePath(siteName, 'newsletter', `subscriptions/${encodeURIComponent(id)}/status`),
250
+ data,
251
+ );
252
+ }
253
+
254
+ async deleteSubscription(siteName: string, id: string): Promise<V2Deleted> {
255
+ return this.deleteOne(
256
+ this.sitePath(siteName, 'newsletter', `subscriptions/${encodeURIComponent(id)}`),
257
+ );
258
+ }
259
+
260
+ async bulkUpdateSubscriptions(
261
+ siteName: string,
262
+ data: V2NewsletterBulkParams,
263
+ ): Promise<V2NewsletterBulkResult> {
264
+ return this.post<V2NewsletterBulkResult>(
265
+ this.sitePath(siteName, 'newsletter', 'subscriptions/bulk'),
266
+ data,
267
+ );
268
+ }
269
+
270
+ // --- Statistics ---
271
+
272
+ async getStatistics(
273
+ siteName: string,
274
+ params?: V2NewsletterStatisticsParams,
275
+ cachePolicy?: CachePolicy,
276
+ ): Promise<V2NewsletterStatistics> {
277
+ return this.getOne<V2NewsletterStatistics>(
278
+ this.sitePath(siteName, 'newsletter', 'statistics'),
279
+ params,
280
+ cachePolicy,
281
+ );
282
+ }
283
+
284
+ // --- Campaigns (create / update / delete) ---
285
+
286
+ async createCampaign(
287
+ siteName: string,
288
+ data: V2NewsletterCampaignCreateParams,
289
+ ): Promise<V2NewsletterCampaign> {
290
+ return this.post<V2NewsletterCampaign>(
291
+ this.sitePath(siteName, 'newsletter', 'campaigns'),
292
+ data,
293
+ );
294
+ }
295
+
296
+ async updateCampaign(
297
+ siteName: string,
298
+ id: string,
299
+ data: V2NewsletterCampaignUpdateParams,
300
+ ): Promise<V2NewsletterCampaign> {
301
+ return this.patchOne<V2NewsletterCampaign>(
302
+ this.sitePath(siteName, 'newsletter', `campaigns/${encodeURIComponent(id)}`),
303
+ data,
304
+ );
305
+ }
306
+
307
+ async deleteCampaign(siteName: string, id: string): Promise<V2Deleted> {
308
+ return this.deleteOne(
309
+ this.sitePath(siteName, 'newsletter', `campaigns/${encodeURIComponent(id)}`),
310
+ );
311
+ }
312
+
313
+ // --- Series ---
314
+
315
+ async listSeries(
316
+ siteName: string,
317
+ params?: { status?: 'active' | 'paused' | 'archived' },
318
+ cachePolicy?: CachePolicy,
319
+ ): Promise<V2List<V2NewsletterSeries>> {
320
+ return this.getList<V2NewsletterSeries>(
321
+ this.sitePath(siteName, 'newsletter', 'series'),
322
+ params,
323
+ cachePolicy,
324
+ );
325
+ }
326
+
327
+ async getSeries(
328
+ siteName: string,
329
+ id: string,
330
+ cachePolicy?: CachePolicy,
331
+ ): Promise<V2NewsletterSeries> {
332
+ return this.getOne<V2NewsletterSeries>(
333
+ this.sitePath(siteName, 'newsletter', `series/${encodeURIComponent(id)}`),
334
+ undefined,
335
+ cachePolicy,
336
+ );
337
+ }
338
+
339
+ async createSeries(
340
+ siteName: string,
341
+ data: V2NewsletterSeriesCreateParams,
342
+ ): Promise<V2NewsletterSeries> {
343
+ return this.post<V2NewsletterSeries>(
344
+ this.sitePath(siteName, 'newsletter', 'series'),
345
+ data,
346
+ );
347
+ }
348
+
349
+ async updateSeries(
350
+ siteName: string,
351
+ id: string,
352
+ data: V2NewsletterSeriesUpdateParams,
353
+ ): Promise<V2NewsletterSeries> {
354
+ return this.patchOne<V2NewsletterSeries>(
355
+ this.sitePath(siteName, 'newsletter', `series/${encodeURIComponent(id)}`),
356
+ data,
357
+ );
358
+ }
359
+
360
+ async deleteSeries(siteName: string, id: string): Promise<V2Deleted> {
361
+ return this.deleteOne(
362
+ this.sitePath(siteName, 'newsletter', `series/${encodeURIComponent(id)}`),
363
+ );
364
+ }
209
365
  }