perspectapi-ts-sdk 7.2.2 → 7.2.4
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/{chunk-Z2LA2IWQ.mjs → chunk-UFVZ7CRS.mjs} +78 -32
- package/dist/{index-uyP4WdHB.d.mts → index-DVyssmFb.d.mts} +25 -0
- package/dist/{index-uyP4WdHB.d.ts → index-DVyssmFb.d.ts} +25 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +78 -32
- package/dist/index.mjs +1 -1
- package/dist/v2/index.d.mts +1 -1
- package/dist/v2/index.d.ts +1 -1
- package/dist/v2/index.js +78 -32
- package/dist/v2/index.mjs +1 -1
- package/package.json +1 -1
- package/src/types/index.ts +5 -0
- package/src/utils/http-client.ts +37 -26
- package/src/v2/client/base-v2-client.ts +49 -6
|
@@ -18,10 +18,20 @@ var HttpClient = class {
|
|
|
18
18
|
defaultHeaders;
|
|
19
19
|
timeout;
|
|
20
20
|
retries;
|
|
21
|
+
debug;
|
|
22
|
+
/**
|
|
23
|
+
* Debug-only logger. Off by default so request URLs, params, headers, and
|
|
24
|
+
* response bodies (emails, profiles, orders, Stripe identifiers) never
|
|
25
|
+
* leak into host logs. Opt in explicitly via `config.debug`.
|
|
26
|
+
*/
|
|
27
|
+
dbg(...args) {
|
|
28
|
+
if (this.debug) console["log"](...args);
|
|
29
|
+
}
|
|
21
30
|
constructor(config) {
|
|
22
31
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
23
32
|
this.timeout = config.timeout || 3e4;
|
|
24
33
|
this.retries = config.retries || 3;
|
|
34
|
+
this.debug = config.debug ?? false;
|
|
25
35
|
this.defaultHeaders = {
|
|
26
36
|
"Content-Type": "application/json",
|
|
27
37
|
"User-Agent": "perspectapi-ts-sdk/1.0.0",
|
|
@@ -66,15 +76,15 @@ var HttpClient = class {
|
|
|
66
76
|
async request(endpoint, options = {}) {
|
|
67
77
|
const url = this.buildUrl(endpoint, options.params);
|
|
68
78
|
const requestOptions = this.buildRequestOptions(options);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
this.dbg(`[HTTP Client] ====== Request Details ======`);
|
|
80
|
+
this.dbg(`[HTTP Client] Method: ${options.method || "GET"}`);
|
|
81
|
+
this.dbg(`[HTTP Client] Base URL: ${this.baseUrl}`);
|
|
82
|
+
this.dbg(`[HTTP Client] Endpoint: ${endpoint}`);
|
|
83
|
+
this.dbg(`[HTTP Client] Full URL: ${url}`);
|
|
74
84
|
if (options.params) {
|
|
75
|
-
|
|
85
|
+
this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
|
|
76
86
|
if (options.params.slug_prefix) {
|
|
77
|
-
|
|
87
|
+
this.dbg(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
|
|
78
88
|
}
|
|
79
89
|
}
|
|
80
90
|
const safeHeaders = { ...requestOptions.headers };
|
|
@@ -84,7 +94,7 @@ var HttpClient = class {
|
|
|
84
94
|
if (safeHeaders["X-API-Key"]) {
|
|
85
95
|
safeHeaders["X-API-Key"] = "[REDACTED]";
|
|
86
96
|
}
|
|
87
|
-
|
|
97
|
+
this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
|
|
88
98
|
let lastError;
|
|
89
99
|
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
90
100
|
try {
|
|
@@ -138,25 +148,25 @@ var HttpClient = class {
|
|
|
138
148
|
*/
|
|
139
149
|
buildUrl(endpoint, params) {
|
|
140
150
|
const url = `${this.baseUrl}${endpoint.startsWith("/") ? "" : "/"}${endpoint}`;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
151
|
+
this.dbg(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
|
|
152
|
+
this.dbg(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
|
|
153
|
+
this.dbg(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
|
|
144
154
|
if (!params || Object.keys(params).length === 0) {
|
|
145
|
-
|
|
155
|
+
this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
|
|
146
156
|
return url;
|
|
147
157
|
}
|
|
148
|
-
|
|
158
|
+
this.dbg(`[HTTP Client - URL Builder] Processing params:`, params);
|
|
149
159
|
const searchParams = new URLSearchParams();
|
|
150
160
|
Object.entries(params).forEach(([key, value]) => {
|
|
151
161
|
if (value !== void 0 && value !== null) {
|
|
152
|
-
|
|
162
|
+
this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
|
|
153
163
|
searchParams.append(key, String(value));
|
|
154
164
|
} else {
|
|
155
|
-
|
|
165
|
+
this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
|
|
156
166
|
}
|
|
157
167
|
});
|
|
158
168
|
const finalUrl = `${url}?${searchParams.toString()}`;
|
|
159
|
-
|
|
169
|
+
this.dbg(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
|
|
160
170
|
return finalUrl;
|
|
161
171
|
}
|
|
162
172
|
/**
|
|
@@ -205,42 +215,42 @@ var HttpClient = class {
|
|
|
205
215
|
async handleResponse(response) {
|
|
206
216
|
const contentType = response.headers.get("content-type");
|
|
207
217
|
const isJson = contentType?.includes("application/json");
|
|
208
|
-
|
|
209
|
-
|
|
218
|
+
this.dbg(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
|
|
219
|
+
this.dbg(`[HTTP Client - Response] Content-Type: ${contentType}`);
|
|
210
220
|
let data;
|
|
211
221
|
try {
|
|
212
222
|
data = isJson ? await response.json() : await response.text();
|
|
213
223
|
} catch (error) {
|
|
214
|
-
|
|
224
|
+
this.dbg(`[HTTP Client - Response] Failed to parse response:`, error);
|
|
215
225
|
data = null;
|
|
216
226
|
}
|
|
217
227
|
const dataStr = JSON.stringify(data);
|
|
218
228
|
if (dataStr && dataStr.length > 1e3) {
|
|
219
|
-
|
|
229
|
+
this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
|
|
220
230
|
} else {
|
|
221
|
-
|
|
231
|
+
this.dbg(`[HTTP Client - Response] Data:`, data);
|
|
222
232
|
}
|
|
223
233
|
if (!response.ok) {
|
|
224
|
-
|
|
234
|
+
this.dbg(`[HTTP Client - Response] Error response received`);
|
|
225
235
|
const error = new PerspectApiError({
|
|
226
236
|
message: data?.error || data?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
227
237
|
status: response.status,
|
|
228
238
|
code: data?.code,
|
|
229
239
|
details: data
|
|
230
240
|
});
|
|
231
|
-
|
|
241
|
+
this.dbg(`[HTTP Client - Response] Throwing error:`, error);
|
|
232
242
|
throw error;
|
|
233
243
|
}
|
|
234
244
|
if (isJson && typeof data === "object") {
|
|
235
245
|
if ("data" in data || "message" in data || "error" in data) {
|
|
236
246
|
const apiResponse = data;
|
|
237
|
-
|
|
247
|
+
this.dbg(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
|
|
238
248
|
return apiResponse;
|
|
239
249
|
}
|
|
240
|
-
|
|
250
|
+
this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
|
|
241
251
|
return { data, success: true };
|
|
242
252
|
}
|
|
243
|
-
|
|
253
|
+
this.dbg(`[HTTP Client - Response] Returning text response`);
|
|
244
254
|
return { data, success: true };
|
|
245
255
|
}
|
|
246
256
|
/**
|
|
@@ -570,7 +580,9 @@ var BaseV2Client = class {
|
|
|
570
580
|
/** GET a single resource, with optional caching. */
|
|
571
581
|
async getOne(path, params, cachePolicy) {
|
|
572
582
|
const fetcher = async () => {
|
|
573
|
-
const response = await this.
|
|
583
|
+
const response = await this.runRequest(
|
|
584
|
+
() => this.http.get(path, this.toParams(params))
|
|
585
|
+
);
|
|
574
586
|
return this.extractData(response);
|
|
575
587
|
};
|
|
576
588
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
@@ -578,29 +590,31 @@ var BaseV2Client = class {
|
|
|
578
590
|
/** GET a list of resources with cursor pagination, with optional caching. */
|
|
579
591
|
async getList(path, params, cachePolicy) {
|
|
580
592
|
const fetcher = async () => {
|
|
581
|
-
const response = await this.
|
|
593
|
+
const response = await this.runRequest(
|
|
594
|
+
() => this.http.get(path, this.toParams(params))
|
|
595
|
+
);
|
|
582
596
|
return this.extractData(response);
|
|
583
597
|
};
|
|
584
598
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
585
599
|
}
|
|
586
600
|
/** POST to create a resource. */
|
|
587
601
|
async post(path, body) {
|
|
588
|
-
const response = await this.http.post(path, body);
|
|
602
|
+
const response = await this.runRequest(() => this.http.post(path, body));
|
|
589
603
|
return this.extractData(response);
|
|
590
604
|
}
|
|
591
605
|
/** PATCH to update a resource. */
|
|
592
606
|
async patchOne(path, body) {
|
|
593
|
-
const response = await this.http.patch(path, body);
|
|
607
|
+
const response = await this.runRequest(() => this.http.patch(path, body));
|
|
594
608
|
return this.extractData(response);
|
|
595
609
|
}
|
|
596
610
|
/** PUT to upsert a resource. */
|
|
597
611
|
async putOne(path, body) {
|
|
598
|
-
const response = await this.http.put(path, body);
|
|
612
|
+
const response = await this.runRequest(() => this.http.put(path, body));
|
|
599
613
|
return this.extractData(response);
|
|
600
614
|
}
|
|
601
615
|
/** DELETE a resource. */
|
|
602
616
|
async deleteOne(path) {
|
|
603
|
-
const response = await this.http.delete(path);
|
|
617
|
+
const response = await this.runRequest(() => this.http.delete(path));
|
|
604
618
|
return this.extractData(response);
|
|
605
619
|
}
|
|
606
620
|
/** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
|
|
@@ -656,6 +670,38 @@ var BaseV2Client = class {
|
|
|
656
670
|
}
|
|
657
671
|
}
|
|
658
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Run an HttpClient call and convert v2 error responses to PerspectV2Error.
|
|
675
|
+
*
|
|
676
|
+
* `HttpClient` throws `PerspectApiError` on any non-2xx, with the parsed
|
|
677
|
+
* body on `.details` and the HTTP status on `.status`. For v2 endpoints
|
|
678
|
+
* that body is `{ error: { type, code, message, param? } }` — the
|
|
679
|
+
* documented `PerspectV2Error` shape. Anything else (network failures,
|
|
680
|
+
* non-JSON bodies, malformed envelopes) is rethrown unchanged so callers
|
|
681
|
+
* still see the original error. Named `runRequest` rather than `send` to
|
|
682
|
+
* avoid colliding with subclass domain methods (e.g. EmailV2Client.send).
|
|
683
|
+
*/
|
|
684
|
+
async runRequest(call) {
|
|
685
|
+
try {
|
|
686
|
+
return await call();
|
|
687
|
+
} catch (err) {
|
|
688
|
+
const v2 = this.toV2ErrorFromThrown(err);
|
|
689
|
+
if (v2) throw v2;
|
|
690
|
+
throw err;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
toV2ErrorFromThrown(err) {
|
|
694
|
+
if (!err || typeof err !== "object") return void 0;
|
|
695
|
+
const e = err;
|
|
696
|
+
const details = e.details;
|
|
697
|
+
if (!details || typeof details !== "object") return void 0;
|
|
698
|
+
const envelope = details.error;
|
|
699
|
+
if (!envelope || typeof envelope !== "object" || !("type" in envelope) || !("message" in envelope)) {
|
|
700
|
+
return void 0;
|
|
701
|
+
}
|
|
702
|
+
const status = typeof e.status === "number" ? e.status : 500;
|
|
703
|
+
return new PerspectV2Error(envelope, status);
|
|
704
|
+
}
|
|
659
705
|
toError(response) {
|
|
660
706
|
const data = response.data;
|
|
661
707
|
const errorObj = data?.error ?? response.error;
|
|
@@ -1087,6 +1087,11 @@ interface PerspectApiConfig {
|
|
|
1087
1087
|
retries?: number;
|
|
1088
1088
|
headers?: Record<string, string>;
|
|
1089
1089
|
cache?: CacheConfig;
|
|
1090
|
+
/**
|
|
1091
|
+
* Opt-in verbose HTTP logging (URLs, params, headers, response bodies).
|
|
1092
|
+
* Off by default so PII never leaks into host logs.
|
|
1093
|
+
*/
|
|
1094
|
+
debug?: boolean;
|
|
1090
1095
|
}
|
|
1091
1096
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
1092
1097
|
interface RequestOptions {
|
|
@@ -1108,6 +1113,13 @@ declare class HttpClient {
|
|
|
1108
1113
|
private defaultHeaders;
|
|
1109
1114
|
private timeout;
|
|
1110
1115
|
private retries;
|
|
1116
|
+
private debug;
|
|
1117
|
+
/**
|
|
1118
|
+
* Debug-only logger. Off by default so request URLs, params, headers, and
|
|
1119
|
+
* response bodies (emails, profiles, orders, Stripe identifiers) never
|
|
1120
|
+
* leak into host logs. Opt in explicitly via `config.debug`.
|
|
1121
|
+
*/
|
|
1122
|
+
private dbg;
|
|
1111
1123
|
constructor(config: PerspectApiConfig);
|
|
1112
1124
|
/**
|
|
1113
1125
|
* Update authentication token
|
|
@@ -1938,6 +1950,19 @@ declare abstract class BaseV2Client {
|
|
|
1938
1950
|
protected listAutoPaginate<T extends {
|
|
1939
1951
|
id: string;
|
|
1940
1952
|
}>(path: string, params?: object): AsyncGenerator<T, void, unknown>;
|
|
1953
|
+
/**
|
|
1954
|
+
* Run an HttpClient call and convert v2 error responses to PerspectV2Error.
|
|
1955
|
+
*
|
|
1956
|
+
* `HttpClient` throws `PerspectApiError` on any non-2xx, with the parsed
|
|
1957
|
+
* body on `.details` and the HTTP status on `.status`. For v2 endpoints
|
|
1958
|
+
* that body is `{ error: { type, code, message, param? } }` — the
|
|
1959
|
+
* documented `PerspectV2Error` shape. Anything else (network failures,
|
|
1960
|
+
* non-JSON bodies, malformed envelopes) is rethrown unchanged so callers
|
|
1961
|
+
* still see the original error. Named `runRequest` rather than `send` to
|
|
1962
|
+
* avoid colliding with subclass domain methods (e.g. EmailV2Client.send).
|
|
1963
|
+
*/
|
|
1964
|
+
private runRequest;
|
|
1965
|
+
private toV2ErrorFromThrown;
|
|
1941
1966
|
private toError;
|
|
1942
1967
|
}
|
|
1943
1968
|
|
|
@@ -1087,6 +1087,11 @@ interface PerspectApiConfig {
|
|
|
1087
1087
|
retries?: number;
|
|
1088
1088
|
headers?: Record<string, string>;
|
|
1089
1089
|
cache?: CacheConfig;
|
|
1090
|
+
/**
|
|
1091
|
+
* Opt-in verbose HTTP logging (URLs, params, headers, response bodies).
|
|
1092
|
+
* Off by default so PII never leaks into host logs.
|
|
1093
|
+
*/
|
|
1094
|
+
debug?: boolean;
|
|
1090
1095
|
}
|
|
1091
1096
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
1092
1097
|
interface RequestOptions {
|
|
@@ -1108,6 +1113,13 @@ declare class HttpClient {
|
|
|
1108
1113
|
private defaultHeaders;
|
|
1109
1114
|
private timeout;
|
|
1110
1115
|
private retries;
|
|
1116
|
+
private debug;
|
|
1117
|
+
/**
|
|
1118
|
+
* Debug-only logger. Off by default so request URLs, params, headers, and
|
|
1119
|
+
* response bodies (emails, profiles, orders, Stripe identifiers) never
|
|
1120
|
+
* leak into host logs. Opt in explicitly via `config.debug`.
|
|
1121
|
+
*/
|
|
1122
|
+
private dbg;
|
|
1111
1123
|
constructor(config: PerspectApiConfig);
|
|
1112
1124
|
/**
|
|
1113
1125
|
* Update authentication token
|
|
@@ -1938,6 +1950,19 @@ declare abstract class BaseV2Client {
|
|
|
1938
1950
|
protected listAutoPaginate<T extends {
|
|
1939
1951
|
id: string;
|
|
1940
1952
|
}>(path: string, params?: object): AsyncGenerator<T, void, unknown>;
|
|
1953
|
+
/**
|
|
1954
|
+
* Run an HttpClient call and convert v2 error responses to PerspectV2Error.
|
|
1955
|
+
*
|
|
1956
|
+
* `HttpClient` throws `PerspectApiError` on any non-2xx, with the parsed
|
|
1957
|
+
* body on `.details` and the HTTP status on `.status`. For v2 endpoints
|
|
1958
|
+
* that body is `{ error: { type, code, message, param? } }` — the
|
|
1959
|
+
* documented `PerspectV2Error` shape. Anything else (network failures,
|
|
1960
|
+
* non-JSON bodies, malformed envelopes) is rethrown unchanged so callers
|
|
1961
|
+
* still see the original error. Named `runRequest` rather than `send` to
|
|
1962
|
+
* avoid colliding with subclass domain methods (e.g. EmailV2Client.send).
|
|
1963
|
+
*/
|
|
1964
|
+
private runRequest;
|
|
1965
|
+
private toV2ErrorFromThrown;
|
|
1941
1966
|
private toError;
|
|
1942
1967
|
}
|
|
1943
1968
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HttpClient, C as CacheManager, A as ApiResponse, a as CachePolicy, b as CacheInvalidateOptions, U as User, c as ContentQueryParams, P as PaginatedResponse, d as Content, e as ContentCategoryResponse, f as CreateContentRequest, g as UpdateContentRequest, h as ApiKey, i as CreateApiKeyRequest, j as UpdateApiKeyRequest, O as Organization, k as CreateOrganizationRequest, S as Site, l as CreateSiteRequest, m as ProductQueryParams, n as Product, o as CreateProductRequest, p as ProductSku, q as CreateProductSkuRequest, r as Category, s as CreateCategoryRequest, W as Webhook, t as CreateWebhookRequest, u as CreateCheckoutSessionRequest, v as CheckoutSession, w as CreateContactRequest, x as ContactSubmitResponse, y as ContactStatusResponse, z as ContactSubmission, B as CreateNewsletterSubscriptionRequest, N as NewsletterSubscribeResponse, D as NewsletterConfirmResponse, E as NewsletterUnsubscribeRequest, F as NewsletterUnsubscribeResponse, G as NewsletterPreferences, I as NewsletterList, J as NewsletterCampaignListResponse, K as NewsletterCampaignDetail, L as NewsletterStatusResponse, M as NewsletterManagementSubscriptionsListResponse, Q as NewsletterManagementSubscription, R as NewsletterSubscriptionSyncRequest, T as NewsletterSubscriptionSyncResponse, V as NewsletterSubscriptionsBulkUpdateRequest, X as NewsletterSubscriptionsBulkUpdateResponse, Y as NewsletterSubscriptionMembershipUpdateRequest, Z as NewsletterSubscriptionsImportRequest, _ as NewsletterSubscriptionsImportResponse, $ as NewsletterManagementList, a0 as NewsletterManagementSeries, a1 as NewsletterManagementCampaignListResponse, a2 as NewsletterManagementCampaign, a3 as NewsletterCampaignTestSendRequest, a4 as NewsletterCampaignTestSendResponse, a5 as NewsletterManagementStatsResponse, a6 as NewsletterExportCreateRequest, a7 as NewsletterExportCreateResponse, a8 as RequestOtpRequest, a9 as VerifyOtpRequest, aa as VerifyOtpResponse, ab as SiteUser, ac as SiteUserProfile, ad as UpdateSiteUserRequest, ae as SiteUserOrder, af as SiteUserSubscription, ag as CancelSubscriptionRequest, ah as CancelSubscriptionResponse, ai as CreditBalance, aj as CreditBalanceWithTransactions, ak as GrantCreditRequest, al as ProductBundleGroup, am as CreateBundleGroupRequest, an as BundleCollection, ao as BundleCollectionItemWithProduct, ap as CreateBundleCollectionRequest, aq as AddCollectionItemRequest, ar as BundleCollectionItem, as as PerspectApiConfig, at as CacheAdapter, au as BlogPost, av as CheckoutMetadata, aw as CheckoutAddress, ax as CheckoutTaxRequest } from './index-
|
|
2
|
-
export { aE as ApiError, aD as CacheConfig, aG as CategorySummary, c4 as CheckoutMetadataValue, c9 as CheckoutSessionTax, c8 as CheckoutTaxBreakdownItem, c7 as CheckoutTaxCustomerExemptionRequest, c6 as CheckoutTaxExemptionStatus, c5 as CheckoutTaxStrategy, b_ as ContentStatus, b$ as ContentType, c2 as CreatePaymentGatewayRequest, cb as CreditTransaction, cc as HttpMethod, aF as MediaItem, aJ as NewsletterCampaignSummary, aK as NewsletterManagementListMembership, aP as NewsletterManagementPagination, aI as NewsletterSubscription, aN as NewsletterSubscriptionImportRowRequest, aL as NewsletterSubscriptionsBulkAction, aM as NewsletterSubscriptionsBulkOutcome, aO as NewsletterSubscriptionsImportRowResult, bZ as PaginationParams, aH as PaymentGateway, aC as PerspectApiError, ay as PerspectApiV2Client, aA as PerspectV2Error, c0 as ProductSkuMediaItem, c1 as ProductSkuOption, cd as RequestOptions, aQ as SetProfileValueRequest, ca as SubscriptionCancellationMode, 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, c3 as WebhookEventType, aB as createApiError, az as createPerspectApiV2Client } from './index-
|
|
1
|
+
import { H as HttpClient, C as CacheManager, A as ApiResponse, a as CachePolicy, b as CacheInvalidateOptions, U as User, c as ContentQueryParams, P as PaginatedResponse, d as Content, e as ContentCategoryResponse, f as CreateContentRequest, g as UpdateContentRequest, h as ApiKey, i as CreateApiKeyRequest, j as UpdateApiKeyRequest, O as Organization, k as CreateOrganizationRequest, S as Site, l as CreateSiteRequest, m as ProductQueryParams, n as Product, o as CreateProductRequest, p as ProductSku, q as CreateProductSkuRequest, r as Category, s as CreateCategoryRequest, W as Webhook, t as CreateWebhookRequest, u as CreateCheckoutSessionRequest, v as CheckoutSession, w as CreateContactRequest, x as ContactSubmitResponse, y as ContactStatusResponse, z as ContactSubmission, B as CreateNewsletterSubscriptionRequest, N as NewsletterSubscribeResponse, D as NewsletterConfirmResponse, E as NewsletterUnsubscribeRequest, F as NewsletterUnsubscribeResponse, G as NewsletterPreferences, I as NewsletterList, J as NewsletterCampaignListResponse, K as NewsletterCampaignDetail, L as NewsletterStatusResponse, M as NewsletterManagementSubscriptionsListResponse, Q as NewsletterManagementSubscription, R as NewsletterSubscriptionSyncRequest, T as NewsletterSubscriptionSyncResponse, V as NewsletterSubscriptionsBulkUpdateRequest, X as NewsletterSubscriptionsBulkUpdateResponse, Y as NewsletterSubscriptionMembershipUpdateRequest, Z as NewsletterSubscriptionsImportRequest, _ as NewsletterSubscriptionsImportResponse, $ as NewsletterManagementList, a0 as NewsletterManagementSeries, a1 as NewsletterManagementCampaignListResponse, a2 as NewsletterManagementCampaign, a3 as NewsletterCampaignTestSendRequest, a4 as NewsletterCampaignTestSendResponse, a5 as NewsletterManagementStatsResponse, a6 as NewsletterExportCreateRequest, a7 as NewsletterExportCreateResponse, a8 as RequestOtpRequest, a9 as VerifyOtpRequest, aa as VerifyOtpResponse, ab as SiteUser, ac as SiteUserProfile, ad as UpdateSiteUserRequest, ae as SiteUserOrder, af as SiteUserSubscription, ag as CancelSubscriptionRequest, ah as CancelSubscriptionResponse, ai as CreditBalance, aj as CreditBalanceWithTransactions, ak as GrantCreditRequest, al as ProductBundleGroup, am as CreateBundleGroupRequest, an as BundleCollection, ao as BundleCollectionItemWithProduct, ap as CreateBundleCollectionRequest, aq as AddCollectionItemRequest, ar as BundleCollectionItem, as as PerspectApiConfig, at as CacheAdapter, au as BlogPost, av as CheckoutMetadata, aw as CheckoutAddress, ax as CheckoutTaxRequest } from './index-DVyssmFb.mjs';
|
|
2
|
+
export { aE as ApiError, aD as CacheConfig, aG as CategorySummary, c4 as CheckoutMetadataValue, c9 as CheckoutSessionTax, c8 as CheckoutTaxBreakdownItem, c7 as CheckoutTaxCustomerExemptionRequest, c6 as CheckoutTaxExemptionStatus, c5 as CheckoutTaxStrategy, b_ as ContentStatus, b$ as ContentType, c2 as CreatePaymentGatewayRequest, cb as CreditTransaction, cc as HttpMethod, aF as MediaItem, aJ as NewsletterCampaignSummary, aK as NewsletterManagementListMembership, aP as NewsletterManagementPagination, aI as NewsletterSubscription, aN as NewsletterSubscriptionImportRowRequest, aL as NewsletterSubscriptionsBulkAction, aM as NewsletterSubscriptionsBulkOutcome, aO as NewsletterSubscriptionsImportRowResult, bZ as PaginationParams, aH as PaymentGateway, aC as PerspectApiError, ay as PerspectApiV2Client, aA as PerspectV2Error, c0 as ProductSkuMediaItem, c1 as ProductSkuOption, cd as RequestOptions, aQ as SetProfileValueRequest, ca as SubscriptionCancellationMode, 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, c3 as WebhookEventType, aB as createApiError, az as createPerspectApiV2Client } from './index-DVyssmFb.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* v1 deprecation constants — kept in sync with the backend's
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HttpClient, C as CacheManager, A as ApiResponse, a as CachePolicy, b as CacheInvalidateOptions, U as User, c as ContentQueryParams, P as PaginatedResponse, d as Content, e as ContentCategoryResponse, f as CreateContentRequest, g as UpdateContentRequest, h as ApiKey, i as CreateApiKeyRequest, j as UpdateApiKeyRequest, O as Organization, k as CreateOrganizationRequest, S as Site, l as CreateSiteRequest, m as ProductQueryParams, n as Product, o as CreateProductRequest, p as ProductSku, q as CreateProductSkuRequest, r as Category, s as CreateCategoryRequest, W as Webhook, t as CreateWebhookRequest, u as CreateCheckoutSessionRequest, v as CheckoutSession, w as CreateContactRequest, x as ContactSubmitResponse, y as ContactStatusResponse, z as ContactSubmission, B as CreateNewsletterSubscriptionRequest, N as NewsletterSubscribeResponse, D as NewsletterConfirmResponse, E as NewsletterUnsubscribeRequest, F as NewsletterUnsubscribeResponse, G as NewsletterPreferences, I as NewsletterList, J as NewsletterCampaignListResponse, K as NewsletterCampaignDetail, L as NewsletterStatusResponse, M as NewsletterManagementSubscriptionsListResponse, Q as NewsletterManagementSubscription, R as NewsletterSubscriptionSyncRequest, T as NewsletterSubscriptionSyncResponse, V as NewsletterSubscriptionsBulkUpdateRequest, X as NewsletterSubscriptionsBulkUpdateResponse, Y as NewsletterSubscriptionMembershipUpdateRequest, Z as NewsletterSubscriptionsImportRequest, _ as NewsletterSubscriptionsImportResponse, $ as NewsletterManagementList, a0 as NewsletterManagementSeries, a1 as NewsletterManagementCampaignListResponse, a2 as NewsletterManagementCampaign, a3 as NewsletterCampaignTestSendRequest, a4 as NewsletterCampaignTestSendResponse, a5 as NewsletterManagementStatsResponse, a6 as NewsletterExportCreateRequest, a7 as NewsletterExportCreateResponse, a8 as RequestOtpRequest, a9 as VerifyOtpRequest, aa as VerifyOtpResponse, ab as SiteUser, ac as SiteUserProfile, ad as UpdateSiteUserRequest, ae as SiteUserOrder, af as SiteUserSubscription, ag as CancelSubscriptionRequest, ah as CancelSubscriptionResponse, ai as CreditBalance, aj as CreditBalanceWithTransactions, ak as GrantCreditRequest, al as ProductBundleGroup, am as CreateBundleGroupRequest, an as BundleCollection, ao as BundleCollectionItemWithProduct, ap as CreateBundleCollectionRequest, aq as AddCollectionItemRequest, ar as BundleCollectionItem, as as PerspectApiConfig, at as CacheAdapter, au as BlogPost, av as CheckoutMetadata, aw as CheckoutAddress, ax as CheckoutTaxRequest } from './index-
|
|
2
|
-
export { aE as ApiError, aD as CacheConfig, aG as CategorySummary, c4 as CheckoutMetadataValue, c9 as CheckoutSessionTax, c8 as CheckoutTaxBreakdownItem, c7 as CheckoutTaxCustomerExemptionRequest, c6 as CheckoutTaxExemptionStatus, c5 as CheckoutTaxStrategy, b_ as ContentStatus, b$ as ContentType, c2 as CreatePaymentGatewayRequest, cb as CreditTransaction, cc as HttpMethod, aF as MediaItem, aJ as NewsletterCampaignSummary, aK as NewsletterManagementListMembership, aP as NewsletterManagementPagination, aI as NewsletterSubscription, aN as NewsletterSubscriptionImportRowRequest, aL as NewsletterSubscriptionsBulkAction, aM as NewsletterSubscriptionsBulkOutcome, aO as NewsletterSubscriptionsImportRowResult, bZ as PaginationParams, aH as PaymentGateway, aC as PerspectApiError, ay as PerspectApiV2Client, aA as PerspectV2Error, c0 as ProductSkuMediaItem, c1 as ProductSkuOption, cd as RequestOptions, aQ as SetProfileValueRequest, ca as SubscriptionCancellationMode, 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, c3 as WebhookEventType, aB as createApiError, az as createPerspectApiV2Client } from './index-
|
|
1
|
+
import { H as HttpClient, C as CacheManager, A as ApiResponse, a as CachePolicy, b as CacheInvalidateOptions, U as User, c as ContentQueryParams, P as PaginatedResponse, d as Content, e as ContentCategoryResponse, f as CreateContentRequest, g as UpdateContentRequest, h as ApiKey, i as CreateApiKeyRequest, j as UpdateApiKeyRequest, O as Organization, k as CreateOrganizationRequest, S as Site, l as CreateSiteRequest, m as ProductQueryParams, n as Product, o as CreateProductRequest, p as ProductSku, q as CreateProductSkuRequest, r as Category, s as CreateCategoryRequest, W as Webhook, t as CreateWebhookRequest, u as CreateCheckoutSessionRequest, v as CheckoutSession, w as CreateContactRequest, x as ContactSubmitResponse, y as ContactStatusResponse, z as ContactSubmission, B as CreateNewsletterSubscriptionRequest, N as NewsletterSubscribeResponse, D as NewsletterConfirmResponse, E as NewsletterUnsubscribeRequest, F as NewsletterUnsubscribeResponse, G as NewsletterPreferences, I as NewsletterList, J as NewsletterCampaignListResponse, K as NewsletterCampaignDetail, L as NewsletterStatusResponse, M as NewsletterManagementSubscriptionsListResponse, Q as NewsletterManagementSubscription, R as NewsletterSubscriptionSyncRequest, T as NewsletterSubscriptionSyncResponse, V as NewsletterSubscriptionsBulkUpdateRequest, X as NewsletterSubscriptionsBulkUpdateResponse, Y as NewsletterSubscriptionMembershipUpdateRequest, Z as NewsletterSubscriptionsImportRequest, _ as NewsletterSubscriptionsImportResponse, $ as NewsletterManagementList, a0 as NewsletterManagementSeries, a1 as NewsletterManagementCampaignListResponse, a2 as NewsletterManagementCampaign, a3 as NewsletterCampaignTestSendRequest, a4 as NewsletterCampaignTestSendResponse, a5 as NewsletterManagementStatsResponse, a6 as NewsletterExportCreateRequest, a7 as NewsletterExportCreateResponse, a8 as RequestOtpRequest, a9 as VerifyOtpRequest, aa as VerifyOtpResponse, ab as SiteUser, ac as SiteUserProfile, ad as UpdateSiteUserRequest, ae as SiteUserOrder, af as SiteUserSubscription, ag as CancelSubscriptionRequest, ah as CancelSubscriptionResponse, ai as CreditBalance, aj as CreditBalanceWithTransactions, ak as GrantCreditRequest, al as ProductBundleGroup, am as CreateBundleGroupRequest, an as BundleCollection, ao as BundleCollectionItemWithProduct, ap as CreateBundleCollectionRequest, aq as AddCollectionItemRequest, ar as BundleCollectionItem, as as PerspectApiConfig, at as CacheAdapter, au as BlogPost, av as CheckoutMetadata, aw as CheckoutAddress, ax as CheckoutTaxRequest } from './index-DVyssmFb.js';
|
|
2
|
+
export { aE as ApiError, aD as CacheConfig, aG as CategorySummary, c4 as CheckoutMetadataValue, c9 as CheckoutSessionTax, c8 as CheckoutTaxBreakdownItem, c7 as CheckoutTaxCustomerExemptionRequest, c6 as CheckoutTaxExemptionStatus, c5 as CheckoutTaxStrategy, b_ as ContentStatus, b$ as ContentType, c2 as CreatePaymentGatewayRequest, cb as CreditTransaction, cc as HttpMethod, aF as MediaItem, aJ as NewsletterCampaignSummary, aK as NewsletterManagementListMembership, aP as NewsletterManagementPagination, aI as NewsletterSubscription, aN as NewsletterSubscriptionImportRowRequest, aL as NewsletterSubscriptionsBulkAction, aM as NewsletterSubscriptionsBulkOutcome, aO as NewsletterSubscriptionsImportRowResult, bZ as PaginationParams, aH as PaymentGateway, aC as PerspectApiError, ay as PerspectApiV2Client, aA as PerspectV2Error, c0 as ProductSkuMediaItem, c1 as ProductSkuOption, cd as RequestOptions, aQ as SetProfileValueRequest, ca as SubscriptionCancellationMode, 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, c3 as WebhookEventType, aB as createApiError, az as createPerspectApiV2Client } from './index-DVyssmFb.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* v1 deprecation constants — kept in sync with the backend's
|
package/dist/index.js
CHANGED
|
@@ -104,10 +104,20 @@ var HttpClient = class {
|
|
|
104
104
|
defaultHeaders;
|
|
105
105
|
timeout;
|
|
106
106
|
retries;
|
|
107
|
+
debug;
|
|
108
|
+
/**
|
|
109
|
+
* Debug-only logger. Off by default so request URLs, params, headers, and
|
|
110
|
+
* response bodies (emails, profiles, orders, Stripe identifiers) never
|
|
111
|
+
* leak into host logs. Opt in explicitly via `config.debug`.
|
|
112
|
+
*/
|
|
113
|
+
dbg(...args) {
|
|
114
|
+
if (this.debug) console["log"](...args);
|
|
115
|
+
}
|
|
107
116
|
constructor(config) {
|
|
108
117
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
109
118
|
this.timeout = config.timeout || 3e4;
|
|
110
119
|
this.retries = config.retries || 3;
|
|
120
|
+
this.debug = config.debug ?? false;
|
|
111
121
|
this.defaultHeaders = {
|
|
112
122
|
"Content-Type": "application/json",
|
|
113
123
|
"User-Agent": "perspectapi-ts-sdk/1.0.0",
|
|
@@ -152,15 +162,15 @@ var HttpClient = class {
|
|
|
152
162
|
async request(endpoint, options = {}) {
|
|
153
163
|
const url = this.buildUrl(endpoint, options.params);
|
|
154
164
|
const requestOptions = this.buildRequestOptions(options);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
165
|
+
this.dbg(`[HTTP Client] ====== Request Details ======`);
|
|
166
|
+
this.dbg(`[HTTP Client] Method: ${options.method || "GET"}`);
|
|
167
|
+
this.dbg(`[HTTP Client] Base URL: ${this.baseUrl}`);
|
|
168
|
+
this.dbg(`[HTTP Client] Endpoint: ${endpoint}`);
|
|
169
|
+
this.dbg(`[HTTP Client] Full URL: ${url}`);
|
|
160
170
|
if (options.params) {
|
|
161
|
-
|
|
171
|
+
this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
|
|
162
172
|
if (options.params.slug_prefix) {
|
|
163
|
-
|
|
173
|
+
this.dbg(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
|
|
164
174
|
}
|
|
165
175
|
}
|
|
166
176
|
const safeHeaders = { ...requestOptions.headers };
|
|
@@ -170,7 +180,7 @@ var HttpClient = class {
|
|
|
170
180
|
if (safeHeaders["X-API-Key"]) {
|
|
171
181
|
safeHeaders["X-API-Key"] = "[REDACTED]";
|
|
172
182
|
}
|
|
173
|
-
|
|
183
|
+
this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
|
|
174
184
|
let lastError;
|
|
175
185
|
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
176
186
|
try {
|
|
@@ -224,25 +234,25 @@ var HttpClient = class {
|
|
|
224
234
|
*/
|
|
225
235
|
buildUrl(endpoint, params) {
|
|
226
236
|
const url = `${this.baseUrl}${endpoint.startsWith("/") ? "" : "/"}${endpoint}`;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
237
|
+
this.dbg(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
|
|
238
|
+
this.dbg(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
|
|
239
|
+
this.dbg(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
|
|
230
240
|
if (!params || Object.keys(params).length === 0) {
|
|
231
|
-
|
|
241
|
+
this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
|
|
232
242
|
return url;
|
|
233
243
|
}
|
|
234
|
-
|
|
244
|
+
this.dbg(`[HTTP Client - URL Builder] Processing params:`, params);
|
|
235
245
|
const searchParams = new URLSearchParams();
|
|
236
246
|
Object.entries(params).forEach(([key, value]) => {
|
|
237
247
|
if (value !== void 0 && value !== null) {
|
|
238
|
-
|
|
248
|
+
this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
|
|
239
249
|
searchParams.append(key, String(value));
|
|
240
250
|
} else {
|
|
241
|
-
|
|
251
|
+
this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
|
|
242
252
|
}
|
|
243
253
|
});
|
|
244
254
|
const finalUrl = `${url}?${searchParams.toString()}`;
|
|
245
|
-
|
|
255
|
+
this.dbg(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
|
|
246
256
|
return finalUrl;
|
|
247
257
|
}
|
|
248
258
|
/**
|
|
@@ -291,42 +301,42 @@ var HttpClient = class {
|
|
|
291
301
|
async handleResponse(response) {
|
|
292
302
|
const contentType = response.headers.get("content-type");
|
|
293
303
|
const isJson = contentType?.includes("application/json");
|
|
294
|
-
|
|
295
|
-
|
|
304
|
+
this.dbg(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
|
|
305
|
+
this.dbg(`[HTTP Client - Response] Content-Type: ${contentType}`);
|
|
296
306
|
let data;
|
|
297
307
|
try {
|
|
298
308
|
data = isJson ? await response.json() : await response.text();
|
|
299
309
|
} catch (error) {
|
|
300
|
-
|
|
310
|
+
this.dbg(`[HTTP Client - Response] Failed to parse response:`, error);
|
|
301
311
|
data = null;
|
|
302
312
|
}
|
|
303
313
|
const dataStr = JSON.stringify(data);
|
|
304
314
|
if (dataStr && dataStr.length > 1e3) {
|
|
305
|
-
|
|
315
|
+
this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
|
|
306
316
|
} else {
|
|
307
|
-
|
|
317
|
+
this.dbg(`[HTTP Client - Response] Data:`, data);
|
|
308
318
|
}
|
|
309
319
|
if (!response.ok) {
|
|
310
|
-
|
|
320
|
+
this.dbg(`[HTTP Client - Response] Error response received`);
|
|
311
321
|
const error = new PerspectApiError({
|
|
312
322
|
message: data?.error || data?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
313
323
|
status: response.status,
|
|
314
324
|
code: data?.code,
|
|
315
325
|
details: data
|
|
316
326
|
});
|
|
317
|
-
|
|
327
|
+
this.dbg(`[HTTP Client - Response] Throwing error:`, error);
|
|
318
328
|
throw error;
|
|
319
329
|
}
|
|
320
330
|
if (isJson && typeof data === "object") {
|
|
321
331
|
if ("data" in data || "message" in data || "error" in data) {
|
|
322
332
|
const apiResponse = data;
|
|
323
|
-
|
|
333
|
+
this.dbg(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
|
|
324
334
|
return apiResponse;
|
|
325
335
|
}
|
|
326
|
-
|
|
336
|
+
this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
|
|
327
337
|
return { data, success: true };
|
|
328
338
|
}
|
|
329
|
-
|
|
339
|
+
this.dbg(`[HTTP Client - Response] Returning text response`);
|
|
330
340
|
return { data, success: true };
|
|
331
341
|
}
|
|
332
342
|
/**
|
|
@@ -656,7 +666,9 @@ var BaseV2Client = class {
|
|
|
656
666
|
/** GET a single resource, with optional caching. */
|
|
657
667
|
async getOne(path, params, cachePolicy) {
|
|
658
668
|
const fetcher = async () => {
|
|
659
|
-
const response = await this.
|
|
669
|
+
const response = await this.runRequest(
|
|
670
|
+
() => this.http.get(path, this.toParams(params))
|
|
671
|
+
);
|
|
660
672
|
return this.extractData(response);
|
|
661
673
|
};
|
|
662
674
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
@@ -664,29 +676,31 @@ var BaseV2Client = class {
|
|
|
664
676
|
/** GET a list of resources with cursor pagination, with optional caching. */
|
|
665
677
|
async getList(path, params, cachePolicy) {
|
|
666
678
|
const fetcher = async () => {
|
|
667
|
-
const response = await this.
|
|
679
|
+
const response = await this.runRequest(
|
|
680
|
+
() => this.http.get(path, this.toParams(params))
|
|
681
|
+
);
|
|
668
682
|
return this.extractData(response);
|
|
669
683
|
};
|
|
670
684
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
671
685
|
}
|
|
672
686
|
/** POST to create a resource. */
|
|
673
687
|
async post(path, body) {
|
|
674
|
-
const response = await this.http.post(path, body);
|
|
688
|
+
const response = await this.runRequest(() => this.http.post(path, body));
|
|
675
689
|
return this.extractData(response);
|
|
676
690
|
}
|
|
677
691
|
/** PATCH to update a resource. */
|
|
678
692
|
async patchOne(path, body) {
|
|
679
|
-
const response = await this.http.patch(path, body);
|
|
693
|
+
const response = await this.runRequest(() => this.http.patch(path, body));
|
|
680
694
|
return this.extractData(response);
|
|
681
695
|
}
|
|
682
696
|
/** PUT to upsert a resource. */
|
|
683
697
|
async putOne(path, body) {
|
|
684
|
-
const response = await this.http.put(path, body);
|
|
698
|
+
const response = await this.runRequest(() => this.http.put(path, body));
|
|
685
699
|
return this.extractData(response);
|
|
686
700
|
}
|
|
687
701
|
/** DELETE a resource. */
|
|
688
702
|
async deleteOne(path) {
|
|
689
|
-
const response = await this.http.delete(path);
|
|
703
|
+
const response = await this.runRequest(() => this.http.delete(path));
|
|
690
704
|
return this.extractData(response);
|
|
691
705
|
}
|
|
692
706
|
/** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
|
|
@@ -742,6 +756,38 @@ var BaseV2Client = class {
|
|
|
742
756
|
}
|
|
743
757
|
}
|
|
744
758
|
}
|
|
759
|
+
/**
|
|
760
|
+
* Run an HttpClient call and convert v2 error responses to PerspectV2Error.
|
|
761
|
+
*
|
|
762
|
+
* `HttpClient` throws `PerspectApiError` on any non-2xx, with the parsed
|
|
763
|
+
* body on `.details` and the HTTP status on `.status`. For v2 endpoints
|
|
764
|
+
* that body is `{ error: { type, code, message, param? } }` — the
|
|
765
|
+
* documented `PerspectV2Error` shape. Anything else (network failures,
|
|
766
|
+
* non-JSON bodies, malformed envelopes) is rethrown unchanged so callers
|
|
767
|
+
* still see the original error. Named `runRequest` rather than `send` to
|
|
768
|
+
* avoid colliding with subclass domain methods (e.g. EmailV2Client.send).
|
|
769
|
+
*/
|
|
770
|
+
async runRequest(call) {
|
|
771
|
+
try {
|
|
772
|
+
return await call();
|
|
773
|
+
} catch (err) {
|
|
774
|
+
const v2 = this.toV2ErrorFromThrown(err);
|
|
775
|
+
if (v2) throw v2;
|
|
776
|
+
throw err;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
toV2ErrorFromThrown(err) {
|
|
780
|
+
if (!err || typeof err !== "object") return void 0;
|
|
781
|
+
const e = err;
|
|
782
|
+
const details = e.details;
|
|
783
|
+
if (!details || typeof details !== "object") return void 0;
|
|
784
|
+
const envelope = details.error;
|
|
785
|
+
if (!envelope || typeof envelope !== "object" || !("type" in envelope) || !("message" in envelope)) {
|
|
786
|
+
return void 0;
|
|
787
|
+
}
|
|
788
|
+
const status = typeof e.status === "number" ? e.status : 500;
|
|
789
|
+
return new PerspectV2Error(envelope, status);
|
|
790
|
+
}
|
|
745
791
|
toError(response) {
|
|
746
792
|
const data = response.data;
|
|
747
793
|
const errorObj = data?.error ?? response.error;
|
package/dist/index.mjs
CHANGED
package/dist/v2/index.d.mts
CHANGED
|
@@ -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-
|
|
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-DVyssmFb.mjs';
|
package/dist/v2/index.d.ts
CHANGED
|
@@ -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-
|
|
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-DVyssmFb.js';
|
package/dist/v2/index.js
CHANGED
|
@@ -62,10 +62,20 @@ var HttpClient = class {
|
|
|
62
62
|
defaultHeaders;
|
|
63
63
|
timeout;
|
|
64
64
|
retries;
|
|
65
|
+
debug;
|
|
66
|
+
/**
|
|
67
|
+
* Debug-only logger. Off by default so request URLs, params, headers, and
|
|
68
|
+
* response bodies (emails, profiles, orders, Stripe identifiers) never
|
|
69
|
+
* leak into host logs. Opt in explicitly via `config.debug`.
|
|
70
|
+
*/
|
|
71
|
+
dbg(...args) {
|
|
72
|
+
if (this.debug) console["log"](...args);
|
|
73
|
+
}
|
|
65
74
|
constructor(config) {
|
|
66
75
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
67
76
|
this.timeout = config.timeout || 3e4;
|
|
68
77
|
this.retries = config.retries || 3;
|
|
78
|
+
this.debug = config.debug ?? false;
|
|
69
79
|
this.defaultHeaders = {
|
|
70
80
|
"Content-Type": "application/json",
|
|
71
81
|
"User-Agent": "perspectapi-ts-sdk/1.0.0",
|
|
@@ -110,15 +120,15 @@ var HttpClient = class {
|
|
|
110
120
|
async request(endpoint, options = {}) {
|
|
111
121
|
const url = this.buildUrl(endpoint, options.params);
|
|
112
122
|
const requestOptions = this.buildRequestOptions(options);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
123
|
+
this.dbg(`[HTTP Client] ====== Request Details ======`);
|
|
124
|
+
this.dbg(`[HTTP Client] Method: ${options.method || "GET"}`);
|
|
125
|
+
this.dbg(`[HTTP Client] Base URL: ${this.baseUrl}`);
|
|
126
|
+
this.dbg(`[HTTP Client] Endpoint: ${endpoint}`);
|
|
127
|
+
this.dbg(`[HTTP Client] Full URL: ${url}`);
|
|
118
128
|
if (options.params) {
|
|
119
|
-
|
|
129
|
+
this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
|
|
120
130
|
if (options.params.slug_prefix) {
|
|
121
|
-
|
|
131
|
+
this.dbg(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
|
|
122
132
|
}
|
|
123
133
|
}
|
|
124
134
|
const safeHeaders = { ...requestOptions.headers };
|
|
@@ -128,7 +138,7 @@ var HttpClient = class {
|
|
|
128
138
|
if (safeHeaders["X-API-Key"]) {
|
|
129
139
|
safeHeaders["X-API-Key"] = "[REDACTED]";
|
|
130
140
|
}
|
|
131
|
-
|
|
141
|
+
this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
|
|
132
142
|
let lastError;
|
|
133
143
|
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
134
144
|
try {
|
|
@@ -182,25 +192,25 @@ var HttpClient = class {
|
|
|
182
192
|
*/
|
|
183
193
|
buildUrl(endpoint, params) {
|
|
184
194
|
const url = `${this.baseUrl}${endpoint.startsWith("/") ? "" : "/"}${endpoint}`;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
195
|
+
this.dbg(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
|
|
196
|
+
this.dbg(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
|
|
197
|
+
this.dbg(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
|
|
188
198
|
if (!params || Object.keys(params).length === 0) {
|
|
189
|
-
|
|
199
|
+
this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
|
|
190
200
|
return url;
|
|
191
201
|
}
|
|
192
|
-
|
|
202
|
+
this.dbg(`[HTTP Client - URL Builder] Processing params:`, params);
|
|
193
203
|
const searchParams = new URLSearchParams();
|
|
194
204
|
Object.entries(params).forEach(([key, value]) => {
|
|
195
205
|
if (value !== void 0 && value !== null) {
|
|
196
|
-
|
|
206
|
+
this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
|
|
197
207
|
searchParams.append(key, String(value));
|
|
198
208
|
} else {
|
|
199
|
-
|
|
209
|
+
this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
|
|
200
210
|
}
|
|
201
211
|
});
|
|
202
212
|
const finalUrl = `${url}?${searchParams.toString()}`;
|
|
203
|
-
|
|
213
|
+
this.dbg(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
|
|
204
214
|
return finalUrl;
|
|
205
215
|
}
|
|
206
216
|
/**
|
|
@@ -249,42 +259,42 @@ var HttpClient = class {
|
|
|
249
259
|
async handleResponse(response) {
|
|
250
260
|
const contentType = response.headers.get("content-type");
|
|
251
261
|
const isJson = contentType?.includes("application/json");
|
|
252
|
-
|
|
253
|
-
|
|
262
|
+
this.dbg(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
|
|
263
|
+
this.dbg(`[HTTP Client - Response] Content-Type: ${contentType}`);
|
|
254
264
|
let data;
|
|
255
265
|
try {
|
|
256
266
|
data = isJson ? await response.json() : await response.text();
|
|
257
267
|
} catch (error) {
|
|
258
|
-
|
|
268
|
+
this.dbg(`[HTTP Client - Response] Failed to parse response:`, error);
|
|
259
269
|
data = null;
|
|
260
270
|
}
|
|
261
271
|
const dataStr = JSON.stringify(data);
|
|
262
272
|
if (dataStr && dataStr.length > 1e3) {
|
|
263
|
-
|
|
273
|
+
this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
|
|
264
274
|
} else {
|
|
265
|
-
|
|
275
|
+
this.dbg(`[HTTP Client - Response] Data:`, data);
|
|
266
276
|
}
|
|
267
277
|
if (!response.ok) {
|
|
268
|
-
|
|
278
|
+
this.dbg(`[HTTP Client - Response] Error response received`);
|
|
269
279
|
const error = new PerspectApiError({
|
|
270
280
|
message: data?.error || data?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
271
281
|
status: response.status,
|
|
272
282
|
code: data?.code,
|
|
273
283
|
details: data
|
|
274
284
|
});
|
|
275
|
-
|
|
285
|
+
this.dbg(`[HTTP Client - Response] Throwing error:`, error);
|
|
276
286
|
throw error;
|
|
277
287
|
}
|
|
278
288
|
if (isJson && typeof data === "object") {
|
|
279
289
|
if ("data" in data || "message" in data || "error" in data) {
|
|
280
290
|
const apiResponse = data;
|
|
281
|
-
|
|
291
|
+
this.dbg(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
|
|
282
292
|
return apiResponse;
|
|
283
293
|
}
|
|
284
|
-
|
|
294
|
+
this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
|
|
285
295
|
return { data, success: true };
|
|
286
296
|
}
|
|
287
|
-
|
|
297
|
+
this.dbg(`[HTTP Client - Response] Returning text response`);
|
|
288
298
|
return { data, success: true };
|
|
289
299
|
}
|
|
290
300
|
/**
|
|
@@ -602,7 +612,9 @@ var BaseV2Client = class {
|
|
|
602
612
|
/** GET a single resource, with optional caching. */
|
|
603
613
|
async getOne(path, params, cachePolicy) {
|
|
604
614
|
const fetcher = async () => {
|
|
605
|
-
const response = await this.
|
|
615
|
+
const response = await this.runRequest(
|
|
616
|
+
() => this.http.get(path, this.toParams(params))
|
|
617
|
+
);
|
|
606
618
|
return this.extractData(response);
|
|
607
619
|
};
|
|
608
620
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
@@ -610,29 +622,31 @@ var BaseV2Client = class {
|
|
|
610
622
|
/** GET a list of resources with cursor pagination, with optional caching. */
|
|
611
623
|
async getList(path, params, cachePolicy) {
|
|
612
624
|
const fetcher = async () => {
|
|
613
|
-
const response = await this.
|
|
625
|
+
const response = await this.runRequest(
|
|
626
|
+
() => this.http.get(path, this.toParams(params))
|
|
627
|
+
);
|
|
614
628
|
return this.extractData(response);
|
|
615
629
|
};
|
|
616
630
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
617
631
|
}
|
|
618
632
|
/** POST to create a resource. */
|
|
619
633
|
async post(path, body) {
|
|
620
|
-
const response = await this.http.post(path, body);
|
|
634
|
+
const response = await this.runRequest(() => this.http.post(path, body));
|
|
621
635
|
return this.extractData(response);
|
|
622
636
|
}
|
|
623
637
|
/** PATCH to update a resource. */
|
|
624
638
|
async patchOne(path, body) {
|
|
625
|
-
const response = await this.http.patch(path, body);
|
|
639
|
+
const response = await this.runRequest(() => this.http.patch(path, body));
|
|
626
640
|
return this.extractData(response);
|
|
627
641
|
}
|
|
628
642
|
/** PUT to upsert a resource. */
|
|
629
643
|
async putOne(path, body) {
|
|
630
|
-
const response = await this.http.put(path, body);
|
|
644
|
+
const response = await this.runRequest(() => this.http.put(path, body));
|
|
631
645
|
return this.extractData(response);
|
|
632
646
|
}
|
|
633
647
|
/** DELETE a resource. */
|
|
634
648
|
async deleteOne(path) {
|
|
635
|
-
const response = await this.http.delete(path);
|
|
649
|
+
const response = await this.runRequest(() => this.http.delete(path));
|
|
636
650
|
return this.extractData(response);
|
|
637
651
|
}
|
|
638
652
|
/** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
|
|
@@ -688,6 +702,38 @@ var BaseV2Client = class {
|
|
|
688
702
|
}
|
|
689
703
|
}
|
|
690
704
|
}
|
|
705
|
+
/**
|
|
706
|
+
* Run an HttpClient call and convert v2 error responses to PerspectV2Error.
|
|
707
|
+
*
|
|
708
|
+
* `HttpClient` throws `PerspectApiError` on any non-2xx, with the parsed
|
|
709
|
+
* body on `.details` and the HTTP status on `.status`. For v2 endpoints
|
|
710
|
+
* that body is `{ error: { type, code, message, param? } }` — the
|
|
711
|
+
* documented `PerspectV2Error` shape. Anything else (network failures,
|
|
712
|
+
* non-JSON bodies, malformed envelopes) is rethrown unchanged so callers
|
|
713
|
+
* still see the original error. Named `runRequest` rather than `send` to
|
|
714
|
+
* avoid colliding with subclass domain methods (e.g. EmailV2Client.send).
|
|
715
|
+
*/
|
|
716
|
+
async runRequest(call) {
|
|
717
|
+
try {
|
|
718
|
+
return await call();
|
|
719
|
+
} catch (err) {
|
|
720
|
+
const v2 = this.toV2ErrorFromThrown(err);
|
|
721
|
+
if (v2) throw v2;
|
|
722
|
+
throw err;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
toV2ErrorFromThrown(err) {
|
|
726
|
+
if (!err || typeof err !== "object") return void 0;
|
|
727
|
+
const e = err;
|
|
728
|
+
const details = e.details;
|
|
729
|
+
if (!details || typeof details !== "object") return void 0;
|
|
730
|
+
const envelope = details.error;
|
|
731
|
+
if (!envelope || typeof envelope !== "object" || !("type" in envelope) || !("message" in envelope)) {
|
|
732
|
+
return void 0;
|
|
733
|
+
}
|
|
734
|
+
const status = typeof e.status === "number" ? e.status : 500;
|
|
735
|
+
return new PerspectV2Error(envelope, status);
|
|
736
|
+
}
|
|
691
737
|
toError(response) {
|
|
692
738
|
const data = response.data;
|
|
693
739
|
const errorObj = data?.error ?? response.error;
|
package/dist/v2/index.mjs
CHANGED
package/package.json
CHANGED
package/src/types/index.ts
CHANGED
|
@@ -1192,6 +1192,11 @@ export interface PerspectApiConfig {
|
|
|
1192
1192
|
retries?: number;
|
|
1193
1193
|
headers?: Record<string, string>;
|
|
1194
1194
|
cache?: CacheConfig;
|
|
1195
|
+
/**
|
|
1196
|
+
* Opt-in verbose HTTP logging (URLs, params, headers, response bodies).
|
|
1197
|
+
* Off by default so PII never leaks into host logs.
|
|
1198
|
+
*/
|
|
1199
|
+
debug?: boolean;
|
|
1195
1200
|
}
|
|
1196
1201
|
|
|
1197
1202
|
// HTTP Methods
|
package/src/utils/http-client.ts
CHANGED
|
@@ -16,11 +16,22 @@ export class HttpClient {
|
|
|
16
16
|
private defaultHeaders: Record<string, string>;
|
|
17
17
|
private timeout: number;
|
|
18
18
|
private retries: number;
|
|
19
|
+
private debug: boolean;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Debug-only logger. Off by default so request URLs, params, headers, and
|
|
23
|
+
* response bodies (emails, profiles, orders, Stripe identifiers) never
|
|
24
|
+
* leak into host logs. Opt in explicitly via `config.debug`.
|
|
25
|
+
*/
|
|
26
|
+
private dbg(...args: unknown[]): void {
|
|
27
|
+
if (this.debug) console["log"](...args);
|
|
28
|
+
}
|
|
19
29
|
|
|
20
30
|
constructor(config: PerspectApiConfig) {
|
|
21
31
|
this.baseUrl = config.baseUrl.replace(/\/$/, ''); // Remove trailing slash
|
|
22
32
|
this.timeout = config.timeout || 30000;
|
|
23
33
|
this.retries = config.retries || 3;
|
|
34
|
+
this.debug = config.debug ?? false;
|
|
24
35
|
|
|
25
36
|
this.defaultHeaders = {
|
|
26
37
|
'Content-Type': 'application/json',
|
|
@@ -78,18 +89,18 @@ export class HttpClient {
|
|
|
78
89
|
const requestOptions = this.buildRequestOptions(options);
|
|
79
90
|
|
|
80
91
|
// Enhanced logging for debugging
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
this.dbg(`[HTTP Client] ====== Request Details ======`);
|
|
93
|
+
this.dbg(`[HTTP Client] Method: ${options.method || 'GET'}`);
|
|
94
|
+
this.dbg(`[HTTP Client] Base URL: ${this.baseUrl}`);
|
|
95
|
+
this.dbg(`[HTTP Client] Endpoint: ${endpoint}`);
|
|
96
|
+
this.dbg(`[HTTP Client] Full URL: ${url}`);
|
|
86
97
|
|
|
87
98
|
if (options.params) {
|
|
88
|
-
|
|
99
|
+
this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
|
|
89
100
|
|
|
90
101
|
// Specifically log slug_prefix if present
|
|
91
102
|
if (options.params.slug_prefix) {
|
|
92
|
-
|
|
103
|
+
this.dbg(`[HTTP Client] ⚠️ slug_prefix detected: "${options.params.slug_prefix}"`);
|
|
93
104
|
}
|
|
94
105
|
}
|
|
95
106
|
|
|
@@ -101,7 +112,7 @@ export class HttpClient {
|
|
|
101
112
|
if (safeHeaders['X-API-Key']) {
|
|
102
113
|
safeHeaders['X-API-Key'] = '[REDACTED]';
|
|
103
114
|
}
|
|
104
|
-
|
|
115
|
+
this.dbg(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
|
|
105
116
|
|
|
106
117
|
let lastError: Error;
|
|
107
118
|
|
|
@@ -172,29 +183,29 @@ export class HttpClient {
|
|
|
172
183
|
private buildUrl(endpoint: string, params?: Record<string, any>): string {
|
|
173
184
|
const url = `${this.baseUrl}${endpoint.startsWith('/') ? '' : '/'}${endpoint}`;
|
|
174
185
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
186
|
+
this.dbg(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
|
|
187
|
+
this.dbg(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
|
|
188
|
+
this.dbg(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
|
|
178
189
|
|
|
179
190
|
if (!params || Object.keys(params).length === 0) {
|
|
180
|
-
|
|
191
|
+
this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
|
|
181
192
|
return url;
|
|
182
193
|
}
|
|
183
194
|
|
|
184
|
-
|
|
195
|
+
this.dbg(`[HTTP Client - URL Builder] Processing params:`, params);
|
|
185
196
|
|
|
186
197
|
const searchParams = new URLSearchParams();
|
|
187
198
|
Object.entries(params).forEach(([key, value]) => {
|
|
188
199
|
if (value !== undefined && value !== null) {
|
|
189
|
-
|
|
200
|
+
this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
|
|
190
201
|
searchParams.append(key, String(value));
|
|
191
202
|
} else {
|
|
192
|
-
|
|
203
|
+
this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
|
|
193
204
|
}
|
|
194
205
|
});
|
|
195
206
|
|
|
196
207
|
const finalUrl = `${url}?${searchParams.toString()}`;
|
|
197
|
-
|
|
208
|
+
this.dbg(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
|
|
198
209
|
|
|
199
210
|
return finalUrl;
|
|
200
211
|
}
|
|
@@ -254,34 +265,34 @@ export class HttpClient {
|
|
|
254
265
|
const contentType = response.headers.get('content-type');
|
|
255
266
|
const isJson = contentType?.includes('application/json');
|
|
256
267
|
|
|
257
|
-
|
|
258
|
-
|
|
268
|
+
this.dbg(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
|
|
269
|
+
this.dbg(`[HTTP Client - Response] Content-Type: ${contentType}`);
|
|
259
270
|
|
|
260
271
|
let data: any;
|
|
261
272
|
try {
|
|
262
273
|
data = isJson ? await response.json() : await response.text();
|
|
263
274
|
} catch (error) {
|
|
264
|
-
|
|
275
|
+
this.dbg(`[HTTP Client - Response] Failed to parse response:`, error);
|
|
265
276
|
data = null;
|
|
266
277
|
}
|
|
267
278
|
|
|
268
279
|
// Log response data (truncate if too large)
|
|
269
280
|
const dataStr = JSON.stringify(data);
|
|
270
281
|
if (dataStr && dataStr.length > 1000) {
|
|
271
|
-
|
|
282
|
+
this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1000) + '...');
|
|
272
283
|
} else {
|
|
273
|
-
|
|
284
|
+
this.dbg(`[HTTP Client - Response] Data:`, data);
|
|
274
285
|
}
|
|
275
286
|
|
|
276
287
|
if (!response.ok) {
|
|
277
|
-
|
|
288
|
+
this.dbg(`[HTTP Client - Response] Error response received`);
|
|
278
289
|
const error = new PerspectApiError({
|
|
279
290
|
message: data?.error || data?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
280
291
|
status: response.status,
|
|
281
292
|
code: data?.code,
|
|
282
293
|
details: data,
|
|
283
294
|
});
|
|
284
|
-
|
|
295
|
+
this.dbg(`[HTTP Client - Response] Throwing error:`, error);
|
|
285
296
|
throw error;
|
|
286
297
|
}
|
|
287
298
|
|
|
@@ -290,15 +301,15 @@ export class HttpClient {
|
|
|
290
301
|
// If response has data property, return as-is
|
|
291
302
|
if ('data' in data || 'message' in data || 'error' in data) {
|
|
292
303
|
const apiResponse = data as ApiResponse<T>;
|
|
293
|
-
|
|
304
|
+
this.dbg(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : 'N/A'}`);
|
|
294
305
|
return apiResponse;
|
|
295
306
|
}
|
|
296
307
|
// Otherwise wrap in data property
|
|
297
|
-
|
|
308
|
+
this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
|
|
298
309
|
return { data: data as T, success: true };
|
|
299
310
|
}
|
|
300
311
|
|
|
301
|
-
|
|
312
|
+
this.dbg(`[HTTP Client - Response] Returning text response`);
|
|
302
313
|
return { data: data as T, success: true };
|
|
303
314
|
}
|
|
304
315
|
|
|
@@ -98,7 +98,9 @@ export abstract class BaseV2Client {
|
|
|
98
98
|
/** GET a single resource, with optional caching. */
|
|
99
99
|
protected async getOne<T>(path: string, params?: object, cachePolicy?: CachePolicy): Promise<T> {
|
|
100
100
|
const fetcher = async () => {
|
|
101
|
-
const response = await this.
|
|
101
|
+
const response = await this.runRequest(() =>
|
|
102
|
+
this.http.get<T>(path, this.toParams(params)),
|
|
103
|
+
);
|
|
102
104
|
return this.extractData<T>(response);
|
|
103
105
|
};
|
|
104
106
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
@@ -111,7 +113,9 @@ export abstract class BaseV2Client {
|
|
|
111
113
|
cachePolicy?: CachePolicy,
|
|
112
114
|
): Promise<V2List<T>> {
|
|
113
115
|
const fetcher = async () => {
|
|
114
|
-
const response = await this.
|
|
116
|
+
const response = await this.runRequest(() =>
|
|
117
|
+
this.http.get<V2List<T>>(path, this.toParams(params)),
|
|
118
|
+
);
|
|
115
119
|
return this.extractData<V2List<T>>(response);
|
|
116
120
|
};
|
|
117
121
|
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
@@ -119,25 +123,25 @@ export abstract class BaseV2Client {
|
|
|
119
123
|
|
|
120
124
|
/** POST to create a resource. */
|
|
121
125
|
protected async post<T>(path: string, body?: unknown): Promise<T> {
|
|
122
|
-
const response = await this.http.post<T>(path, body);
|
|
126
|
+
const response = await this.runRequest(() => this.http.post<T>(path, body));
|
|
123
127
|
return this.extractData<T>(response);
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
/** PATCH to update a resource. */
|
|
127
131
|
protected async patchOne<T>(path: string, body?: unknown): Promise<T> {
|
|
128
|
-
const response = await this.http.patch<T>(path, body);
|
|
132
|
+
const response = await this.runRequest(() => this.http.patch<T>(path, body));
|
|
129
133
|
return this.extractData<T>(response);
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
/** PUT to upsert a resource. */
|
|
133
137
|
protected async putOne<T>(path: string, body?: unknown): Promise<T> {
|
|
134
|
-
const response = await this.http.put<T>(path, body);
|
|
138
|
+
const response = await this.runRequest(() => this.http.put<T>(path, body));
|
|
135
139
|
return this.extractData<T>(response);
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
/** DELETE a resource. */
|
|
139
143
|
protected async deleteOne(path: string): Promise<V2Deleted> {
|
|
140
|
-
const response = await this.http.delete<V2Deleted>(path);
|
|
144
|
+
const response = await this.runRequest(() => this.http.delete<V2Deleted>(path));
|
|
141
145
|
return this.extractData<V2Deleted>(response);
|
|
142
146
|
}
|
|
143
147
|
|
|
@@ -209,6 +213,45 @@ export abstract class BaseV2Client {
|
|
|
209
213
|
}
|
|
210
214
|
}
|
|
211
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Run an HttpClient call and convert v2 error responses to PerspectV2Error.
|
|
218
|
+
*
|
|
219
|
+
* `HttpClient` throws `PerspectApiError` on any non-2xx, with the parsed
|
|
220
|
+
* body on `.details` and the HTTP status on `.status`. For v2 endpoints
|
|
221
|
+
* that body is `{ error: { type, code, message, param? } }` — the
|
|
222
|
+
* documented `PerspectV2Error` shape. Anything else (network failures,
|
|
223
|
+
* non-JSON bodies, malformed envelopes) is rethrown unchanged so callers
|
|
224
|
+
* still see the original error. Named `runRequest` rather than `send` to
|
|
225
|
+
* avoid colliding with subclass domain methods (e.g. EmailV2Client.send).
|
|
226
|
+
*/
|
|
227
|
+
private async runRequest<R>(call: () => Promise<R>): Promise<R> {
|
|
228
|
+
try {
|
|
229
|
+
return await call();
|
|
230
|
+
} catch (err) {
|
|
231
|
+
const v2 = this.toV2ErrorFromThrown(err);
|
|
232
|
+
if (v2) throw v2;
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private toV2ErrorFromThrown(err: unknown): PerspectV2Error | undefined {
|
|
238
|
+
if (!err || typeof err !== 'object') return undefined;
|
|
239
|
+
const e = err as { status?: unknown; details?: unknown };
|
|
240
|
+
const details = e.details;
|
|
241
|
+
if (!details || typeof details !== 'object') return undefined;
|
|
242
|
+
const envelope = (details as { error?: unknown }).error;
|
|
243
|
+
if (
|
|
244
|
+
!envelope ||
|
|
245
|
+
typeof envelope !== 'object' ||
|
|
246
|
+
!('type' in envelope) ||
|
|
247
|
+
!('message' in envelope)
|
|
248
|
+
) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
const status = typeof e.status === 'number' ? e.status : 500;
|
|
252
|
+
return new PerspectV2Error(envelope as V2Error['error'], status);
|
|
253
|
+
}
|
|
254
|
+
|
|
212
255
|
private toError(response: { data?: unknown; error?: unknown; message?: string }): PerspectV2Error {
|
|
213
256
|
const data = response.data as Record<string, unknown> | undefined;
|
|
214
257
|
const errorObj = (data?.error ?? response.error) as V2Error['error'] | undefined;
|