perspectapi-ts-sdk 7.2.6 → 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/README.md +54 -0
- package/dist/{chunk-WD62IBI5.mjs → chunk-PWZSSX4V.mjs} +170 -4
- package/dist/{index-BbTVcEl5.d.mts → index-CmcHYKO8.d.mts} +259 -7
- package/dist/{index-BbTVcEl5.d.ts → index-CmcHYKO8.d.ts} +259 -7
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +176 -7
- package/dist/index.mjs +8 -4
- package/dist/v2/index.d.mts +1 -1
- package/dist/v2/index.d.ts +1 -1
- package/dist/v2/index.js +171 -4
- package/dist/v2/index.mjs +3 -1
- package/package.json +1 -1
- package/src/ab/ab-client.ts +8 -4
- package/src/utils/http-client.ts +17 -5
- package/src/v2/client/email-client.ts +11 -4
- package/src/v2/client/email-templates-client.ts +113 -0
- package/src/v2/client/newsletter-client.ts +156 -0
- package/src/v2/index.ts +4 -0
- package/src/v2/types.ts +233 -2
package/dist/index.js
CHANGED
|
@@ -182,6 +182,8 @@ var HttpClient = class {
|
|
|
182
182
|
}
|
|
183
183
|
this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
|
|
184
184
|
let lastError;
|
|
185
|
+
const method = (options.method || "GET").toUpperCase();
|
|
186
|
+
const isIdempotent = method === "GET" || method === "HEAD";
|
|
185
187
|
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
186
188
|
try {
|
|
187
189
|
const response = await this.fetchWithTimeout(url, requestOptions);
|
|
@@ -191,6 +193,9 @@ var HttpClient = class {
|
|
|
191
193
|
if (error && typeof error === "object" && "status" in error && typeof error.status === "number" && error.status < 500) {
|
|
192
194
|
throw error;
|
|
193
195
|
}
|
|
196
|
+
if (!isIdempotent) {
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
194
199
|
if (attempt === this.retries) {
|
|
195
200
|
break;
|
|
196
201
|
}
|
|
@@ -1347,6 +1352,97 @@ var NewsletterV2Client = class extends BaseV2Client {
|
|
|
1347
1352
|
data
|
|
1348
1353
|
);
|
|
1349
1354
|
}
|
|
1355
|
+
// --- Lists (get by id) ---
|
|
1356
|
+
async getListById(siteName, id, cachePolicy) {
|
|
1357
|
+
return this.getOne(
|
|
1358
|
+
this.sitePath(siteName, "newsletter", `lists/${encodeURIComponent(id)}`),
|
|
1359
|
+
void 0,
|
|
1360
|
+
cachePolicy
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
// --- Subscriptions (admin: lookup / status / delete / bulk) ---
|
|
1364
|
+
async getSubscriptionByEmail(siteName, email, cachePolicy) {
|
|
1365
|
+
return this.getOne(
|
|
1366
|
+
this.sitePath(siteName, "newsletter", "subscriptions/by-email"),
|
|
1367
|
+
{ email },
|
|
1368
|
+
cachePolicy
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
async updateSubscriptionStatus(siteName, id, data) {
|
|
1372
|
+
return this.post(
|
|
1373
|
+
this.sitePath(siteName, "newsletter", `subscriptions/${encodeURIComponent(id)}/status`),
|
|
1374
|
+
data
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
async deleteSubscription(siteName, id) {
|
|
1378
|
+
return this.deleteOne(
|
|
1379
|
+
this.sitePath(siteName, "newsletter", `subscriptions/${encodeURIComponent(id)}`)
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
async bulkUpdateSubscriptions(siteName, data) {
|
|
1383
|
+
return this.post(
|
|
1384
|
+
this.sitePath(siteName, "newsletter", "subscriptions/bulk"),
|
|
1385
|
+
data
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
// --- Statistics ---
|
|
1389
|
+
async getStatistics(siteName, params, cachePolicy) {
|
|
1390
|
+
return this.getOne(
|
|
1391
|
+
this.sitePath(siteName, "newsletter", "statistics"),
|
|
1392
|
+
params,
|
|
1393
|
+
cachePolicy
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
// --- Campaigns (create / update / delete) ---
|
|
1397
|
+
async createCampaign(siteName, data) {
|
|
1398
|
+
return this.post(
|
|
1399
|
+
this.sitePath(siteName, "newsletter", "campaigns"),
|
|
1400
|
+
data
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
async updateCampaign(siteName, id, data) {
|
|
1404
|
+
return this.patchOne(
|
|
1405
|
+
this.sitePath(siteName, "newsletter", `campaigns/${encodeURIComponent(id)}`),
|
|
1406
|
+
data
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
async deleteCampaign(siteName, id) {
|
|
1410
|
+
return this.deleteOne(
|
|
1411
|
+
this.sitePath(siteName, "newsletter", `campaigns/${encodeURIComponent(id)}`)
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
// --- Series ---
|
|
1415
|
+
async listSeries(siteName, params, cachePolicy) {
|
|
1416
|
+
return this.getList(
|
|
1417
|
+
this.sitePath(siteName, "newsletter", "series"),
|
|
1418
|
+
params,
|
|
1419
|
+
cachePolicy
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
async getSeries(siteName, id, cachePolicy) {
|
|
1423
|
+
return this.getOne(
|
|
1424
|
+
this.sitePath(siteName, "newsletter", `series/${encodeURIComponent(id)}`),
|
|
1425
|
+
void 0,
|
|
1426
|
+
cachePolicy
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
async createSeries(siteName, data) {
|
|
1430
|
+
return this.post(
|
|
1431
|
+
this.sitePath(siteName, "newsletter", "series"),
|
|
1432
|
+
data
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
async updateSeries(siteName, id, data) {
|
|
1436
|
+
return this.patchOne(
|
|
1437
|
+
this.sitePath(siteName, "newsletter", `series/${encodeURIComponent(id)}`),
|
|
1438
|
+
data
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
async deleteSeries(siteName, id) {
|
|
1442
|
+
return this.deleteOne(
|
|
1443
|
+
this.sitePath(siteName, "newsletter", `series/${encodeURIComponent(id)}`)
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1350
1446
|
};
|
|
1351
1447
|
|
|
1352
1448
|
// src/v2/client/contacts-client.ts
|
|
@@ -1535,11 +1631,18 @@ var CreditsV2Client = class extends BaseV2Client {
|
|
|
1535
1631
|
// src/v2/client/email-client.ts
|
|
1536
1632
|
var EmailV2Client = class extends BaseV2Client {
|
|
1537
1633
|
/**
|
|
1538
|
-
* Send a transactional email
|
|
1634
|
+
* Send a transactional email through the site's email provider.
|
|
1635
|
+
*
|
|
1636
|
+
* Requires a server-side API key — never call this from a browser. Sites
|
|
1637
|
+
* without a configured provider fall back to the platform default with
|
|
1638
|
+
* policy restrictions (owner-only recipients, daily quota).
|
|
1539
1639
|
*
|
|
1540
|
-
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1640
|
+
* Provide content one of two ways (mutually exclusive):
|
|
1641
|
+
* - Raw: `subject` plus at least one of `html` / `text`.
|
|
1642
|
+
* - Template: `template_type` (published template for that type) or
|
|
1643
|
+
* `template_id` (published template by ID) plus optional `variables`; the
|
|
1644
|
+
* template is rendered server-side. `subject` is optional here and
|
|
1645
|
+
* overrides the rendered one.
|
|
1543
1646
|
*/
|
|
1544
1647
|
async send(siteName, params) {
|
|
1545
1648
|
return this.post(
|
|
@@ -1549,6 +1652,66 @@ var EmailV2Client = class extends BaseV2Client {
|
|
|
1549
1652
|
}
|
|
1550
1653
|
};
|
|
1551
1654
|
|
|
1655
|
+
// src/v2/client/email-templates-client.ts
|
|
1656
|
+
var EmailTemplatesV2Client = class extends BaseV2Client {
|
|
1657
|
+
path(siteName, suffix = "") {
|
|
1658
|
+
return this.sitePath(siteName, "email", suffix ? `templates/${suffix}` : "templates");
|
|
1659
|
+
}
|
|
1660
|
+
/** List every supported template type with its allowed variables. */
|
|
1661
|
+
async listTypes(siteName, cachePolicy) {
|
|
1662
|
+
return this.getList(
|
|
1663
|
+
this.path(siteName, "types"),
|
|
1664
|
+
void 0,
|
|
1665
|
+
cachePolicy
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
/** Get the allowed variables for a single template type. */
|
|
1669
|
+
async getTypeVariables(siteName, templateType, cachePolicy) {
|
|
1670
|
+
return this.getOne(
|
|
1671
|
+
this.path(siteName, `types/${templateType}`),
|
|
1672
|
+
void 0,
|
|
1673
|
+
cachePolicy
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
/** List template versions, optionally filtered by type and/or status. */
|
|
1677
|
+
async list(siteName, params, cachePolicy) {
|
|
1678
|
+
return this.getList(this.path(siteName), params, cachePolicy);
|
|
1679
|
+
}
|
|
1680
|
+
/** Get a specific template version by ID (`etpl_…`). */
|
|
1681
|
+
async get(siteName, templateId, cachePolicy) {
|
|
1682
|
+
return this.getOne(
|
|
1683
|
+
this.path(siteName, encodeURIComponent(templateId)),
|
|
1684
|
+
void 0,
|
|
1685
|
+
cachePolicy
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
/** Get the currently published version for a template type. */
|
|
1689
|
+
async getPublished(siteName, templateType, cachePolicy) {
|
|
1690
|
+
return this.getOne(
|
|
1691
|
+
this.path(siteName, `published/${templateType}`),
|
|
1692
|
+
void 0,
|
|
1693
|
+
cachePolicy
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1696
|
+
/** Create a new template version. */
|
|
1697
|
+
async create(siteName, params) {
|
|
1698
|
+
return this.post(this.path(siteName), params);
|
|
1699
|
+
}
|
|
1700
|
+
/** Clone a template version, optionally overriding fields. */
|
|
1701
|
+
async clone(siteName, templateId, params) {
|
|
1702
|
+
return this.post(
|
|
1703
|
+
this.path(siteName, `${encodeURIComponent(templateId)}/clone`),
|
|
1704
|
+
params ?? {}
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
/** Publish a template version (archives the previously published one). */
|
|
1708
|
+
async publish(siteName, templateId) {
|
|
1709
|
+
return this.post(
|
|
1710
|
+
this.path(siteName, `${encodeURIComponent(templateId)}/publish`)
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1552
1715
|
// src/v2/index.ts
|
|
1553
1716
|
var PerspectApiV2Client = class {
|
|
1554
1717
|
http;
|
|
@@ -1568,6 +1731,7 @@ var PerspectApiV2Client = class {
|
|
|
1568
1731
|
subscriptions;
|
|
1569
1732
|
credits;
|
|
1570
1733
|
email;
|
|
1734
|
+
emailTemplates;
|
|
1571
1735
|
constructor(config) {
|
|
1572
1736
|
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
1573
1737
|
const v2BaseUrl = baseUrl.endsWith("/api/v2") ? baseUrl : `${baseUrl}/api/v2`;
|
|
@@ -1590,6 +1754,7 @@ var PerspectApiV2Client = class {
|
|
|
1590
1754
|
this.subscriptions = new SubscriptionsV2Client(this.http, basePath, cache);
|
|
1591
1755
|
this.credits = new CreditsV2Client(this.http, basePath, cache);
|
|
1592
1756
|
this.email = new EmailV2Client(this.http, basePath, cache);
|
|
1757
|
+
this.emailTemplates = new EmailTemplatesV2Client(this.http, basePath, cache);
|
|
1593
1758
|
}
|
|
1594
1759
|
/** Update the JWT token for authenticated requests. */
|
|
1595
1760
|
setAuth(jwt) {
|
|
@@ -4478,7 +4643,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot)
|
|
|
4478
4643
|
return { variant: flag.defaultVariant, enrolled: false, config: null };
|
|
4479
4644
|
}
|
|
4480
4645
|
const variantCfg = flag.variants.find((v) => v.key === assigned)?.config ?? null;
|
|
4481
|
-
emit(apiKey, baseUrl, ctx, {
|
|
4646
|
+
await emit(apiKey, baseUrl, ctx, {
|
|
4482
4647
|
site: siteName,
|
|
4483
4648
|
kind: "exposure",
|
|
4484
4649
|
flag: flagKey,
|
|
@@ -4499,7 +4664,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot)
|
|
|
4499
4664
|
const bucket = bucketFor(visitorId, flagKey, flag.currentVersion);
|
|
4500
4665
|
const assigned = variantForBucket(bucket, flag.variants, flag.trafficAllocationBp);
|
|
4501
4666
|
if (assigned === null) continue;
|
|
4502
|
-
emit(apiKey, baseUrl, ctx, {
|
|
4667
|
+
await emit(apiKey, baseUrl, ctx, {
|
|
4503
4668
|
site: siteName,
|
|
4504
4669
|
kind: "conversion",
|
|
4505
4670
|
flag: flagKey,
|
|
@@ -4543,7 +4708,11 @@ function emit(apiKey, baseUrl, ctx, body) {
|
|
|
4543
4708
|
headers: { "content-type": "application/json", "x-api-key": apiKey },
|
|
4544
4709
|
body: JSON.stringify(body)
|
|
4545
4710
|
}).then(() => void 0).catch(() => void 0);
|
|
4546
|
-
if (ctx)
|
|
4711
|
+
if (ctx) {
|
|
4712
|
+
ctx.waitUntil(task);
|
|
4713
|
+
return Promise.resolve();
|
|
4714
|
+
}
|
|
4715
|
+
return task;
|
|
4547
4716
|
}
|
|
4548
4717
|
function classifyBotFromCfRequest(request) {
|
|
4549
4718
|
const cf = request.cf;
|
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
PerspectV2Error,
|
|
8
8
|
createApiError,
|
|
9
9
|
createPerspectApiV2Client
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PWZSSX4V.mjs";
|
|
11
11
|
|
|
12
12
|
// src/deprecation.ts
|
|
13
13
|
var V1_SUNSET_DATE = "2026-06-01";
|
|
@@ -2889,7 +2889,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot)
|
|
|
2889
2889
|
return { variant: flag.defaultVariant, enrolled: false, config: null };
|
|
2890
2890
|
}
|
|
2891
2891
|
const variantCfg = flag.variants.find((v) => v.key === assigned)?.config ?? null;
|
|
2892
|
-
emit(apiKey, baseUrl, ctx, {
|
|
2892
|
+
await emit(apiKey, baseUrl, ctx, {
|
|
2893
2893
|
site: siteName,
|
|
2894
2894
|
kind: "exposure",
|
|
2895
2895
|
flag: flagKey,
|
|
@@ -2910,7 +2910,7 @@ function buildAbClient(apiKey, siteName, baseUrl, ctx, config, visitorId, isBot)
|
|
|
2910
2910
|
const bucket = bucketFor(visitorId, flagKey, flag.currentVersion);
|
|
2911
2911
|
const assigned = variantForBucket(bucket, flag.variants, flag.trafficAllocationBp);
|
|
2912
2912
|
if (assigned === null) continue;
|
|
2913
|
-
emit(apiKey, baseUrl, ctx, {
|
|
2913
|
+
await emit(apiKey, baseUrl, ctx, {
|
|
2914
2914
|
site: siteName,
|
|
2915
2915
|
kind: "conversion",
|
|
2916
2916
|
flag: flagKey,
|
|
@@ -2954,7 +2954,11 @@ function emit(apiKey, baseUrl, ctx, body) {
|
|
|
2954
2954
|
headers: { "content-type": "application/json", "x-api-key": apiKey },
|
|
2955
2955
|
body: JSON.stringify(body)
|
|
2956
2956
|
}).then(() => void 0).catch(() => void 0);
|
|
2957
|
-
if (ctx)
|
|
2957
|
+
if (ctx) {
|
|
2958
|
+
ctx.waitUntil(task);
|
|
2959
|
+
return Promise.resolve();
|
|
2960
|
+
}
|
|
2961
|
+
return task;
|
|
2958
2962
|
}
|
|
2959
2963
|
function classifyBotFromCfRequest(request) {
|
|
2960
2964
|
const cf = request.cf;
|
package/dist/v2/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
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';
|
package/dist/v2/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
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
|
|
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
|
-
*
|
|
1487
|
-
*
|
|
1488
|
-
*
|
|
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-
|
|
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
package/src/ab/ab-client.ts
CHANGED
|
@@ -124,7 +124,7 @@ function buildAbClient(
|
|
|
124
124
|
return { variant: flag.defaultVariant, enrolled: false, config: null };
|
|
125
125
|
}
|
|
126
126
|
const variantCfg = flag.variants.find((v) => v.key === assigned)?.config ?? null;
|
|
127
|
-
emit(apiKey, baseUrl, ctx, {
|
|
127
|
+
await emit(apiKey, baseUrl, ctx, {
|
|
128
128
|
site: siteName,
|
|
129
129
|
kind: 'exposure',
|
|
130
130
|
flag: flagKey,
|
|
@@ -146,7 +146,7 @@ function buildAbClient(
|
|
|
146
146
|
const bucket = bucketFor(visitorId, flagKey, flag.currentVersion);
|
|
147
147
|
const assigned = variantForBucket(bucket, flag.variants, flag.trafficAllocationBp);
|
|
148
148
|
if (assigned === null) continue;
|
|
149
|
-
emit(apiKey, baseUrl, ctx, {
|
|
149
|
+
await emit(apiKey, baseUrl, ctx, {
|
|
150
150
|
site: siteName,
|
|
151
151
|
kind: 'conversion',
|
|
152
152
|
flag: flagKey,
|
|
@@ -225,7 +225,7 @@ function emit(
|
|
|
225
225
|
baseUrl: string,
|
|
226
226
|
ctx: { waitUntil(p: Promise<unknown>): void } | undefined,
|
|
227
227
|
body: EventBody,
|
|
228
|
-
): void {
|
|
228
|
+
): Promise<void> {
|
|
229
229
|
const task = fetch(`${baseUrl}/_ab/event`, {
|
|
230
230
|
method: 'POST',
|
|
231
231
|
headers: { 'content-type': 'application/json', 'x-api-key': apiKey },
|
|
@@ -233,7 +233,11 @@ function emit(
|
|
|
233
233
|
})
|
|
234
234
|
.then(() => undefined)
|
|
235
235
|
.catch(() => undefined);
|
|
236
|
-
if (ctx)
|
|
236
|
+
if (ctx) {
|
|
237
|
+
ctx.waitUntil(task);
|
|
238
|
+
return Promise.resolve();
|
|
239
|
+
}
|
|
240
|
+
return task;
|
|
237
241
|
}
|
|
238
242
|
|
|
239
243
|
// ---------------------------------------------------------------------------
|
package/src/utils/http-client.ts
CHANGED
|
@@ -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
|
}
|