perspectapi-ts-sdk 7.2.0 → 7.2.3

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.
@@ -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
- console.log(`[HTTP Client] ====== Request Details ======`);
70
- console.log(`[HTTP Client] Method: ${options.method || "GET"}`);
71
- console.log(`[HTTP Client] Base URL: ${this.baseUrl}`);
72
- console.log(`[HTTP Client] Endpoint: ${endpoint}`);
73
- console.log(`[HTTP Client] Full URL: ${url}`);
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
- console.log(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
85
+ this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
76
86
  if (options.params.slug_prefix) {
77
- console.log(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
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
- console.log(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
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
- console.log(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
142
- console.log(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
143
- console.log(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
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
- console.log(`[HTTP Client - URL Builder] No params, returning: ${url}`);
155
+ this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
146
156
  return url;
147
157
  }
148
- console.log(`[HTTP Client - URL Builder] Processing params:`, params);
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
- console.log(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
162
+ this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
153
163
  searchParams.append(key, String(value));
154
164
  } else {
155
- console.log(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
165
+ this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
156
166
  }
157
167
  });
158
168
  const finalUrl = `${url}?${searchParams.toString()}`;
159
- console.log(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
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
- console.log(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
209
- console.log(`[HTTP Client - Response] Content-Type: ${contentType}`);
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
- console.error(`[HTTP Client - Response] Failed to parse response:`, error);
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
- console.log(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
229
+ this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
220
230
  } else {
221
- console.log(`[HTTP Client - Response] Data:`, data);
231
+ this.dbg(`[HTTP Client - Response] Data:`, data);
222
232
  }
223
233
  if (!response.ok) {
224
- console.error(`[HTTP Client - Response] Error response received`);
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
- console.error(`[HTTP Client - Response] Throwing error:`, error);
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
- console.log(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
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
- console.log(`[HTTP Client - Response] Wrapping response in data property`);
250
+ this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
241
251
  return { data, success: true };
242
252
  }
243
- console.log(`[HTTP Client - Response] Returning text response`);
253
+ this.dbg(`[HTTP Client - Response] Returning text response`);
244
254
  return { data, success: true };
245
255
  }
246
256
  /**
@@ -945,6 +955,12 @@ var OrdersV2Client = class extends BaseV2Client {
945
955
  *
946
956
  * Set `notify_customer: true` when moving the order into a terminal
947
957
  * fulfillment state to send the customer fulfillment email.
958
+ *
959
+ * When cancelling (`fulfillment_status: 'cancelled'`/`'canceled'`) with
960
+ * `notify_customer: true`, `cancellation_reason` is **required**: the API
961
+ * responds `400` if it is missing or blank, and the order is not mutated.
962
+ * `cancellation_details_*` are no longer derived from `fulfillment_details_*`
963
+ * — pass them explicitly if you need them.
948
964
  */
949
965
  async updateFulfillment(siteName, id, data) {
950
966
  const result = await this.patchOne(
@@ -960,6 +976,9 @@ var OrdersV2Client = class extends BaseV2Client {
960
976
  /**
961
977
  * Send the customer fulfillment template for an external delivery/packing
962
978
  * record without mutating a checkout session.
979
+ *
980
+ * When `fulfillment_status` is `cancelled`/`canceled`, `cancellation_reason`
981
+ * is **required**: the API responds `400` if it is missing or blank.
963
982
  */
964
983
  async sendFulfillmentNotification(siteName, data) {
965
984
  return this.post(
@@ -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
@@ -1457,13 +1469,32 @@ interface V2OrderCreateParams {
1457
1469
  currency?: string;
1458
1470
  referral_code?: string;
1459
1471
  referrer_site_user_id?: string;
1472
+ /**
1473
+ * Subscription billing-cycle anchor as a Unix timestamp (seconds). When set
1474
+ * on a `subscription` checkout, no charge is taken at checkout; the first
1475
+ * invoice and the recurring cycle are aligned to this instant via Stripe
1476
+ * `subscription_data.billing_cycle_anchor` with `proration_behavior: none`.
1477
+ */
1478
+ billing_cycle_anchor?: number;
1460
1479
  }
1461
1480
  interface V2OrderFulfillmentUpdate {
1462
1481
  fulfillment_status: string;
1463
1482
  tracking_number?: string;
1483
+ /** Internal operator notes. Never shown to the customer. */
1464
1484
  notes?: string;
1465
1485
  fulfillment_details_text?: string;
1466
1486
  fulfillment_details_html?: string;
1487
+ /**
1488
+ * Customer-visible cancellation reason. **Required** when
1489
+ * `fulfillment_status` is `cancelled`/`canceled` and `notify_customer` is
1490
+ * `true` — the request is rejected with `400` if it is missing or blank.
1491
+ * Not derived from `notes` or `fulfillment_details_*`.
1492
+ */
1493
+ cancellation_reason?: string;
1494
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
1495
+ cancellation_details_text?: string;
1496
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
1497
+ cancellation_details_html?: string;
1467
1498
  /** When true, a terminal fulfillment status triggers a customer email. */
1468
1499
  notify_customer?: boolean;
1469
1500
  }
@@ -1481,6 +1512,17 @@ interface V2OrderFulfillmentNotificationParams {
1481
1512
  fulfillment_status?: string;
1482
1513
  fulfillment_details_text?: string;
1483
1514
  fulfillment_details_html?: string;
1515
+ /**
1516
+ * Customer-visible cancellation reason. **Required** when
1517
+ * `fulfillment_status` is `cancelled`/`canceled` — the request is rejected
1518
+ * with `400` if it is missing or blank. Not derived from
1519
+ * `fulfillment_details_*`.
1520
+ */
1521
+ cancellation_reason?: string;
1522
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
1523
+ cancellation_details_text?: string;
1524
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
1525
+ cancellation_details_html?: string;
1484
1526
  line_items?: V2OrderFulfillmentNotificationLineItem[];
1485
1527
  amount_total?: number;
1486
1528
  currency?: string;
@@ -2003,11 +2045,20 @@ declare class OrdersV2Client extends BaseV2Client {
2003
2045
  *
2004
2046
  * Set `notify_customer: true` when moving the order into a terminal
2005
2047
  * fulfillment state to send the customer fulfillment email.
2048
+ *
2049
+ * When cancelling (`fulfillment_status: 'cancelled'`/`'canceled'`) with
2050
+ * `notify_customer: true`, `cancellation_reason` is **required**: the API
2051
+ * responds `400` if it is missing or blank, and the order is not mutated.
2052
+ * `cancellation_details_*` are no longer derived from `fulfillment_details_*`
2053
+ * — pass them explicitly if you need them.
2006
2054
  */
2007
2055
  updateFulfillment(siteName: string, id: string, data: V2OrderFulfillmentUpdate): Promise<V2Order>;
2008
2056
  /**
2009
2057
  * Send the customer fulfillment template for an external delivery/packing
2010
2058
  * record without mutating a checkout session.
2059
+ *
2060
+ * When `fulfillment_status` is `cancelled`/`canceled`, `cancellation_reason`
2061
+ * is **required**: the API responds `400` if it is missing or blank.
2011
2062
  */
2012
2063
  sendFulfillmentNotification(siteName: string, data: V2OrderFulfillmentNotificationParams): Promise<V2OrderFulfillmentNotificationResult>;
2013
2064
  private withOrderTags;
@@ -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
@@ -1457,13 +1469,32 @@ interface V2OrderCreateParams {
1457
1469
  currency?: string;
1458
1470
  referral_code?: string;
1459
1471
  referrer_site_user_id?: string;
1472
+ /**
1473
+ * Subscription billing-cycle anchor as a Unix timestamp (seconds). When set
1474
+ * on a `subscription` checkout, no charge is taken at checkout; the first
1475
+ * invoice and the recurring cycle are aligned to this instant via Stripe
1476
+ * `subscription_data.billing_cycle_anchor` with `proration_behavior: none`.
1477
+ */
1478
+ billing_cycle_anchor?: number;
1460
1479
  }
1461
1480
  interface V2OrderFulfillmentUpdate {
1462
1481
  fulfillment_status: string;
1463
1482
  tracking_number?: string;
1483
+ /** Internal operator notes. Never shown to the customer. */
1464
1484
  notes?: string;
1465
1485
  fulfillment_details_text?: string;
1466
1486
  fulfillment_details_html?: string;
1487
+ /**
1488
+ * Customer-visible cancellation reason. **Required** when
1489
+ * `fulfillment_status` is `cancelled`/`canceled` and `notify_customer` is
1490
+ * `true` — the request is rejected with `400` if it is missing or blank.
1491
+ * Not derived from `notes` or `fulfillment_details_*`.
1492
+ */
1493
+ cancellation_reason?: string;
1494
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
1495
+ cancellation_details_text?: string;
1496
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
1497
+ cancellation_details_html?: string;
1467
1498
  /** When true, a terminal fulfillment status triggers a customer email. */
1468
1499
  notify_customer?: boolean;
1469
1500
  }
@@ -1481,6 +1512,17 @@ interface V2OrderFulfillmentNotificationParams {
1481
1512
  fulfillment_status?: string;
1482
1513
  fulfillment_details_text?: string;
1483
1514
  fulfillment_details_html?: string;
1515
+ /**
1516
+ * Customer-visible cancellation reason. **Required** when
1517
+ * `fulfillment_status` is `cancelled`/`canceled` — the request is rejected
1518
+ * with `400` if it is missing or blank. Not derived from
1519
+ * `fulfillment_details_*`.
1520
+ */
1521
+ cancellation_reason?: string;
1522
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
1523
+ cancellation_details_text?: string;
1524
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
1525
+ cancellation_details_html?: string;
1484
1526
  line_items?: V2OrderFulfillmentNotificationLineItem[];
1485
1527
  amount_total?: number;
1486
1528
  currency?: string;
@@ -2003,11 +2045,20 @@ declare class OrdersV2Client extends BaseV2Client {
2003
2045
  *
2004
2046
  * Set `notify_customer: true` when moving the order into a terminal
2005
2047
  * fulfillment state to send the customer fulfillment email.
2048
+ *
2049
+ * When cancelling (`fulfillment_status: 'cancelled'`/`'canceled'`) with
2050
+ * `notify_customer: true`, `cancellation_reason` is **required**: the API
2051
+ * responds `400` if it is missing or blank, and the order is not mutated.
2052
+ * `cancellation_details_*` are no longer derived from `fulfillment_details_*`
2053
+ * — pass them explicitly if you need them.
2006
2054
  */
2007
2055
  updateFulfillment(siteName: string, id: string, data: V2OrderFulfillmentUpdate): Promise<V2Order>;
2008
2056
  /**
2009
2057
  * Send the customer fulfillment template for an external delivery/packing
2010
2058
  * record without mutating a checkout session.
2059
+ *
2060
+ * When `fulfillment_status` is `cancelled`/`canceled`, `cancellation_reason`
2061
+ * is **required**: the API responds `400` if it is missing or blank.
2011
2062
  */
2012
2063
  sendFulfillmentNotification(siteName: string, data: V2OrderFulfillmentNotificationParams): Promise<V2OrderFulfillmentNotificationResult>;
2013
2064
  private withOrderTags;
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-fBvdMvWa.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-fBvdMvWa.mjs';
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-hSqTwbPy.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-hSqTwbPy.mjs';
3
3
 
4
4
  /**
5
5
  * v1 deprecation constants — kept in sync with the backend's
@@ -1774,9 +1774,21 @@ declare class SiteUsersClient extends BaseClient {
1774
1774
  updateOrderFulfillment(siteName: string, sessionId: string, data: {
1775
1775
  fulfillment_status: string;
1776
1776
  tracking_number?: string;
1777
+ /** Internal operator notes. Never shown to the customer. */
1777
1778
  notes?: string;
1778
1779
  fulfillment_details_text?: string;
1779
1780
  fulfillment_details_html?: string;
1781
+ /**
1782
+ * Customer-visible cancellation reason. Required when
1783
+ * `fulfillment_status` is `cancelled`/`canceled` and `notify_customer`
1784
+ * is `true` — the request is rejected with `400` if missing or blank.
1785
+ * Not derived from `notes` or `fulfillment_details_*`.
1786
+ */
1787
+ cancellation_reason?: string;
1788
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
1789
+ cancellation_details_text?: string;
1790
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
1791
+ cancellation_details_html?: string;
1780
1792
  notify_customer?: boolean;
1781
1793
  }): Promise<ApiResponse<{
1782
1794
  success: boolean;
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-fBvdMvWa.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-fBvdMvWa.js';
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-hSqTwbPy.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-hSqTwbPy.js';
3
3
 
4
4
  /**
5
5
  * v1 deprecation constants — kept in sync with the backend's
@@ -1774,9 +1774,21 @@ declare class SiteUsersClient extends BaseClient {
1774
1774
  updateOrderFulfillment(siteName: string, sessionId: string, data: {
1775
1775
  fulfillment_status: string;
1776
1776
  tracking_number?: string;
1777
+ /** Internal operator notes. Never shown to the customer. */
1777
1778
  notes?: string;
1778
1779
  fulfillment_details_text?: string;
1779
1780
  fulfillment_details_html?: string;
1781
+ /**
1782
+ * Customer-visible cancellation reason. Required when
1783
+ * `fulfillment_status` is `cancelled`/`canceled` and `notify_customer`
1784
+ * is `true` — the request is rejected with `400` if missing or blank.
1785
+ * Not derived from `notes` or `fulfillment_details_*`.
1786
+ */
1787
+ cancellation_reason?: string;
1788
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
1789
+ cancellation_details_text?: string;
1790
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
1791
+ cancellation_details_html?: string;
1780
1792
  notify_customer?: boolean;
1781
1793
  }): Promise<ApiResponse<{
1782
1794
  success: boolean;
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
- console.log(`[HTTP Client] ====== Request Details ======`);
156
- console.log(`[HTTP Client] Method: ${options.method || "GET"}`);
157
- console.log(`[HTTP Client] Base URL: ${this.baseUrl}`);
158
- console.log(`[HTTP Client] Endpoint: ${endpoint}`);
159
- console.log(`[HTTP Client] Full URL: ${url}`);
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
- console.log(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
171
+ this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
162
172
  if (options.params.slug_prefix) {
163
- console.log(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
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
- console.log(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
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
- console.log(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
228
- console.log(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
229
- console.log(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
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
- console.log(`[HTTP Client - URL Builder] No params, returning: ${url}`);
241
+ this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
232
242
  return url;
233
243
  }
234
- console.log(`[HTTP Client - URL Builder] Processing params:`, params);
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
- console.log(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
248
+ this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
239
249
  searchParams.append(key, String(value));
240
250
  } else {
241
- console.log(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
251
+ this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
242
252
  }
243
253
  });
244
254
  const finalUrl = `${url}?${searchParams.toString()}`;
245
- console.log(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
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
- console.log(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
295
- console.log(`[HTTP Client - Response] Content-Type: ${contentType}`);
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
- console.error(`[HTTP Client - Response] Failed to parse response:`, error);
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
- console.log(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
315
+ this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
306
316
  } else {
307
- console.log(`[HTTP Client - Response] Data:`, data);
317
+ this.dbg(`[HTTP Client - Response] Data:`, data);
308
318
  }
309
319
  if (!response.ok) {
310
- console.error(`[HTTP Client - Response] Error response received`);
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
- console.error(`[HTTP Client - Response] Throwing error:`, error);
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
- console.log(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
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
- console.log(`[HTTP Client - Response] Wrapping response in data property`);
336
+ this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
327
337
  return { data, success: true };
328
338
  }
329
- console.log(`[HTTP Client - Response] Returning text response`);
339
+ this.dbg(`[HTTP Client - Response] Returning text response`);
330
340
  return { data, success: true };
331
341
  }
332
342
  /**
@@ -1031,6 +1041,12 @@ var OrdersV2Client = class extends BaseV2Client {
1031
1041
  *
1032
1042
  * Set `notify_customer: true` when moving the order into a terminal
1033
1043
  * fulfillment state to send the customer fulfillment email.
1044
+ *
1045
+ * When cancelling (`fulfillment_status: 'cancelled'`/`'canceled'`) with
1046
+ * `notify_customer: true`, `cancellation_reason` is **required**: the API
1047
+ * responds `400` if it is missing or blank, and the order is not mutated.
1048
+ * `cancellation_details_*` are no longer derived from `fulfillment_details_*`
1049
+ * — pass them explicitly if you need them.
1034
1050
  */
1035
1051
  async updateFulfillment(siteName, id, data) {
1036
1052
  const result = await this.patchOne(
@@ -1046,6 +1062,9 @@ var OrdersV2Client = class extends BaseV2Client {
1046
1062
  /**
1047
1063
  * Send the customer fulfillment template for an external delivery/packing
1048
1064
  * record without mutating a checkout session.
1065
+ *
1066
+ * When `fulfillment_status` is `cancelled`/`canceled`, `cancellation_reason`
1067
+ * is **required**: the API responds `400` if it is missing or blank.
1049
1068
  */
1050
1069
  async sendFulfillmentNotification(siteName, data) {
1051
1070
  return this.post(
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  PerspectV2Error,
8
8
  createApiError,
9
9
  createPerspectApiV2Client
10
- } from "./chunk-OG4UB2MD.mjs";
10
+ } from "./chunk-TFN5IR35.mjs";
11
11
 
12
12
  // src/deprecation.ts
13
13
  var V1_SUNSET_DATE = "2026-06-01";
@@ -1 +1 @@
1
- export { cq as ApiKeysV2Client, cf as BaseV2Client, ci as CategoriesV2Client, cj as CollectionsV2Client, cn as ContactsV2Client, cg as ContentV2Client, ct as CreditsV2Client, cu as EmailV2Client, cm as NewsletterV2Client, ck as OrdersV2Client, co as OrganizationsV2Client, ay as PerspectApiV2Client, ce as PerspectApiV2Config, aA as PerspectV2Error, ch as ProductsV2Client, cl as SiteUsersV2Client, cp as SitesV2Client, cs as SubscriptionsV2Client, bH as V2ApiKey, bS as V2CancelSubscriptionResult, b4 as V2Category, b5 as V2CategoryCreateParams, b6 as V2CategoryUpdateParams, b7 as V2Collection, b9 as V2CollectionCreateParams, b8 as V2CollectionItem, ba as V2CollectionUpdateParams, bE as V2ContactSubmission, aY as V2Content, aZ as V2ContentCreateParams, a$ as V2ContentListParams, a_ as V2ContentUpdateParams, bU as V2CreditBalance, bT as V2CreditTransaction, aT as V2Deleted, bX as V2EmailSendParams, bY as V2EmailSendResult, aU as V2Error, aV as V2ErrorType, bV as V2GrantCreditParams, bW as V2GrantCreditResult, aS as V2List, aX as V2Media, bv as V2NewsletterCampaign, bC as V2NewsletterImportRequest, bD as V2NewsletterImportResult, bu as V2NewsletterList, bx as V2NewsletterListCreateParams, by as V2NewsletterListUpdateParams, bt as V2NewsletterSubscription, bB as V2NewsletterSubscriptionListMembershipUpdate, bz as V2NewsletterSyncInput, bA as V2NewsletterSyncResult, bw as V2NewsletterTrackingResponse, aR as V2Object, bb as V2Order, bf as V2OrderAddress, bh as V2OrderCreateParams, bm as V2OrderCreateResult, bj as V2OrderFulfillmentNotificationLineItem, bk as V2OrderFulfillmentNotificationParams, bl as V2OrderFulfillmentNotificationResult, bi as V2OrderFulfillmentUpdate, be as V2OrderLineItem, bd as V2OrderLineItemPriceData, bc as V2OrderListParams, bg as V2OrderTaxRequest, bF as V2Organization, aW as V2PaginationParams, b0 as V2Product, b1 as V2ProductCreateParams, b3 as V2ProductListParams, b2 as V2ProductUpdateParams, bG as V2Site, bn as V2SiteUser, bq as V2SiteUserListParams, bp as V2SiteUserMeUpdateParams, bs as V2SiteUserProfile, bM as V2SiteUserSubscription, bo as V2SiteUserUpdateParams, br as V2SiteUserWithProfile, bO as V2SubscriptionCancelParams, bP as V2SubscriptionChangePlanParams, bQ as V2SubscriptionChargeParams, bR as V2SubscriptionChargeResult, bN as V2SubscriptionPauseParams, bJ as V2Webhook, bK as V2WebhookCreateParams, bI as V2WebhookEventType, bL as V2WebhookUpdateParams, cr as WebhooksV2Client, az as createPerspectApiV2Client } from '../index-fBvdMvWa.mjs';
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-hSqTwbPy.mjs';
@@ -1 +1 @@
1
- export { cq as ApiKeysV2Client, cf as BaseV2Client, ci as CategoriesV2Client, cj as CollectionsV2Client, cn as ContactsV2Client, cg as ContentV2Client, ct as CreditsV2Client, cu as EmailV2Client, cm as NewsletterV2Client, ck as OrdersV2Client, co as OrganizationsV2Client, ay as PerspectApiV2Client, ce as PerspectApiV2Config, aA as PerspectV2Error, ch as ProductsV2Client, cl as SiteUsersV2Client, cp as SitesV2Client, cs as SubscriptionsV2Client, bH as V2ApiKey, bS as V2CancelSubscriptionResult, b4 as V2Category, b5 as V2CategoryCreateParams, b6 as V2CategoryUpdateParams, b7 as V2Collection, b9 as V2CollectionCreateParams, b8 as V2CollectionItem, ba as V2CollectionUpdateParams, bE as V2ContactSubmission, aY as V2Content, aZ as V2ContentCreateParams, a$ as V2ContentListParams, a_ as V2ContentUpdateParams, bU as V2CreditBalance, bT as V2CreditTransaction, aT as V2Deleted, bX as V2EmailSendParams, bY as V2EmailSendResult, aU as V2Error, aV as V2ErrorType, bV as V2GrantCreditParams, bW as V2GrantCreditResult, aS as V2List, aX as V2Media, bv as V2NewsletterCampaign, bC as V2NewsletterImportRequest, bD as V2NewsletterImportResult, bu as V2NewsletterList, bx as V2NewsletterListCreateParams, by as V2NewsletterListUpdateParams, bt as V2NewsletterSubscription, bB as V2NewsletterSubscriptionListMembershipUpdate, bz as V2NewsletterSyncInput, bA as V2NewsletterSyncResult, bw as V2NewsletterTrackingResponse, aR as V2Object, bb as V2Order, bf as V2OrderAddress, bh as V2OrderCreateParams, bm as V2OrderCreateResult, bj as V2OrderFulfillmentNotificationLineItem, bk as V2OrderFulfillmentNotificationParams, bl as V2OrderFulfillmentNotificationResult, bi as V2OrderFulfillmentUpdate, be as V2OrderLineItem, bd as V2OrderLineItemPriceData, bc as V2OrderListParams, bg as V2OrderTaxRequest, bF as V2Organization, aW as V2PaginationParams, b0 as V2Product, b1 as V2ProductCreateParams, b3 as V2ProductListParams, b2 as V2ProductUpdateParams, bG as V2Site, bn as V2SiteUser, bq as V2SiteUserListParams, bp as V2SiteUserMeUpdateParams, bs as V2SiteUserProfile, bM as V2SiteUserSubscription, bo as V2SiteUserUpdateParams, br as V2SiteUserWithProfile, bO as V2SubscriptionCancelParams, bP as V2SubscriptionChangePlanParams, bQ as V2SubscriptionChargeParams, bR as V2SubscriptionChargeResult, bN as V2SubscriptionPauseParams, bJ as V2Webhook, bK as V2WebhookCreateParams, bI as V2WebhookEventType, bL as V2WebhookUpdateParams, cr as WebhooksV2Client, az as createPerspectApiV2Client } from '../index-fBvdMvWa.js';
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-hSqTwbPy.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
- console.log(`[HTTP Client] ====== Request Details ======`);
114
- console.log(`[HTTP Client] Method: ${options.method || "GET"}`);
115
- console.log(`[HTTP Client] Base URL: ${this.baseUrl}`);
116
- console.log(`[HTTP Client] Endpoint: ${endpoint}`);
117
- console.log(`[HTTP Client] Full URL: ${url}`);
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
- console.log(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
129
+ this.dbg(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
120
130
  if (options.params.slug_prefix) {
121
- console.log(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
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
- console.log(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
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
- console.log(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
186
- console.log(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
187
- console.log(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
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
- console.log(`[HTTP Client - URL Builder] No params, returning: ${url}`);
199
+ this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
190
200
  return url;
191
201
  }
192
- console.log(`[HTTP Client - URL Builder] Processing params:`, params);
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
- console.log(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
206
+ this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
197
207
  searchParams.append(key, String(value));
198
208
  } else {
199
- console.log(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
209
+ this.dbg(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
200
210
  }
201
211
  });
202
212
  const finalUrl = `${url}?${searchParams.toString()}`;
203
- console.log(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
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
- console.log(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
253
- console.log(`[HTTP Client - Response] Content-Type: ${contentType}`);
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
- console.error(`[HTTP Client - Response] Failed to parse response:`, error);
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
- console.log(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
273
+ this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
264
274
  } else {
265
- console.log(`[HTTP Client - Response] Data:`, data);
275
+ this.dbg(`[HTTP Client - Response] Data:`, data);
266
276
  }
267
277
  if (!response.ok) {
268
- console.error(`[HTTP Client - Response] Error response received`);
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
- console.error(`[HTTP Client - Response] Throwing error:`, error);
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
- console.log(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
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
- console.log(`[HTTP Client - Response] Wrapping response in data property`);
294
+ this.dbg(`[HTTP Client - Response] Wrapping response in data property`);
285
295
  return { data, success: true };
286
296
  }
287
- console.log(`[HTTP Client - Response] Returning text response`);
297
+ this.dbg(`[HTTP Client - Response] Returning text response`);
288
298
  return { data, success: true };
289
299
  }
290
300
  /**
@@ -977,6 +987,12 @@ var OrdersV2Client = class extends BaseV2Client {
977
987
  *
978
988
  * Set `notify_customer: true` when moving the order into a terminal
979
989
  * fulfillment state to send the customer fulfillment email.
990
+ *
991
+ * When cancelling (`fulfillment_status: 'cancelled'`/`'canceled'`) with
992
+ * `notify_customer: true`, `cancellation_reason` is **required**: the API
993
+ * responds `400` if it is missing or blank, and the order is not mutated.
994
+ * `cancellation_details_*` are no longer derived from `fulfillment_details_*`
995
+ * — pass them explicitly if you need them.
980
996
  */
981
997
  async updateFulfillment(siteName, id, data) {
982
998
  const result = await this.patchOne(
@@ -992,6 +1008,9 @@ var OrdersV2Client = class extends BaseV2Client {
992
1008
  /**
993
1009
  * Send the customer fulfillment template for an external delivery/packing
994
1010
  * record without mutating a checkout session.
1011
+ *
1012
+ * When `fulfillment_status` is `cancelled`/`canceled`, `cancellation_reason`
1013
+ * is **required**: the API responds `400` if it is missing or blank.
995
1014
  */
996
1015
  async sendFulfillmentNotification(siteName, data) {
997
1016
  return this.post(
package/dist/v2/index.mjs CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  SubscriptionsV2Client,
19
19
  WebhooksV2Client,
20
20
  createPerspectApiV2Client
21
- } from "../chunk-OG4UB2MD.mjs";
21
+ } from "../chunk-TFN5IR35.mjs";
22
22
  export {
23
23
  ApiKeysV2Client,
24
24
  BaseV2Client,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perspectapi-ts-sdk",
3
- "version": "7.2.0",
3
+ "version": "7.2.3",
4
4
  "description": "TypeScript SDK for PerspectAPI - Cloudflare Workers compatible",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -518,9 +518,21 @@ export class SiteUsersClient extends BaseClient {
518
518
  data: {
519
519
  fulfillment_status: string;
520
520
  tracking_number?: string;
521
+ /** Internal operator notes. Never shown to the customer. */
521
522
  notes?: string;
522
523
  fulfillment_details_text?: string;
523
524
  fulfillment_details_html?: string;
525
+ /**
526
+ * Customer-visible cancellation reason. Required when
527
+ * `fulfillment_status` is `cancelled`/`canceled` and `notify_customer`
528
+ * is `true` — the request is rejected with `400` if missing or blank.
529
+ * Not derived from `notes` or `fulfillment_details_*`.
530
+ */
531
+ cancellation_reason?: string;
532
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
533
+ cancellation_details_text?: string;
534
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
535
+ cancellation_details_html?: string;
524
536
  notify_customer?: boolean;
525
537
  }
526
538
  ): Promise<ApiResponse<{ success: boolean }>> {
@@ -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
@@ -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
- console.log(`[HTTP Client] ====== Request Details ======`);
82
- console.log(`[HTTP Client] Method: ${options.method || 'GET'}`);
83
- console.log(`[HTTP Client] Base URL: ${this.baseUrl}`);
84
- console.log(`[HTTP Client] Endpoint: ${endpoint}`);
85
- console.log(`[HTTP Client] Full URL: ${url}`);
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
- console.log(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
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
- console.log(`[HTTP Client] ⚠️ slug_prefix detected: "${options.params.slug_prefix}"`);
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
- console.log(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
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
- console.log(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
176
- console.log(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
177
- console.log(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
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
- console.log(`[HTTP Client - URL Builder] No params, returning: ${url}`);
191
+ this.dbg(`[HTTP Client - URL Builder] No params, returning: ${url}`);
181
192
  return url;
182
193
  }
183
194
 
184
- console.log(`[HTTP Client - URL Builder] Processing params:`, params);
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
- console.log(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
200
+ this.dbg(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
190
201
  searchParams.append(key, String(value));
191
202
  } else {
192
- console.log(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
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
- console.log(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
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
- console.log(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
258
- console.log(`[HTTP Client - Response] Content-Type: ${contentType}`);
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
- console.error(`[HTTP Client - Response] Failed to parse response:`, error);
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
- console.log(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1000) + '...');
282
+ this.dbg(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1000) + '...');
272
283
  } else {
273
- console.log(`[HTTP Client - Response] Data:`, data);
284
+ this.dbg(`[HTTP Client - Response] Data:`, data);
274
285
  }
275
286
 
276
287
  if (!response.ok) {
277
- console.error(`[HTTP Client - Response] Error response received`);
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
- console.error(`[HTTP Client - Response] Throwing error:`, error);
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
- console.log(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : 'N/A'}`);
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
- console.log(`[HTTP Client - Response] Wrapping response in data property`);
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
- console.log(`[HTTP Client - Response] Returning text response`);
312
+ this.dbg(`[HTTP Client - Response] Returning text response`);
302
313
  return { data: data as T, success: true };
303
314
  }
304
315
 
@@ -88,6 +88,12 @@ export class OrdersV2Client extends BaseV2Client {
88
88
  *
89
89
  * Set `notify_customer: true` when moving the order into a terminal
90
90
  * fulfillment state to send the customer fulfillment email.
91
+ *
92
+ * When cancelling (`fulfillment_status: 'cancelled'`/`'canceled'`) with
93
+ * `notify_customer: true`, `cancellation_reason` is **required**: the API
94
+ * responds `400` if it is missing or blank, and the order is not mutated.
95
+ * `cancellation_details_*` are no longer derived from `fulfillment_details_*`
96
+ * — pass them explicitly if you need them.
91
97
  */
92
98
  async updateFulfillment(
93
99
  siteName: string,
@@ -108,6 +114,9 @@ export class OrdersV2Client extends BaseV2Client {
108
114
  /**
109
115
  * Send the customer fulfillment template for an external delivery/packing
110
116
  * record without mutating a checkout session.
117
+ *
118
+ * When `fulfillment_status` is `cancelled`/`canceled`, `cancellation_reason`
119
+ * is **required**: the API responds `400` if it is missing or blank.
111
120
  */
112
121
  async sendFulfillmentNotification(
113
122
  siteName: string,
package/src/v2/types.ts CHANGED
@@ -322,14 +322,33 @@ export interface V2OrderCreateParams {
322
322
  currency?: string;
323
323
  referral_code?: string;
324
324
  referrer_site_user_id?: string;
325
+ /**
326
+ * Subscription billing-cycle anchor as a Unix timestamp (seconds). When set
327
+ * on a `subscription` checkout, no charge is taken at checkout; the first
328
+ * invoice and the recurring cycle are aligned to this instant via Stripe
329
+ * `subscription_data.billing_cycle_anchor` with `proration_behavior: none`.
330
+ */
331
+ billing_cycle_anchor?: number;
325
332
  }
326
333
 
327
334
  export interface V2OrderFulfillmentUpdate {
328
335
  fulfillment_status: string;
329
336
  tracking_number?: string;
337
+ /** Internal operator notes. Never shown to the customer. */
330
338
  notes?: string;
331
339
  fulfillment_details_text?: string;
332
340
  fulfillment_details_html?: string;
341
+ /**
342
+ * Customer-visible cancellation reason. **Required** when
343
+ * `fulfillment_status` is `cancelled`/`canceled` and `notify_customer` is
344
+ * `true` — the request is rejected with `400` if it is missing or blank.
345
+ * Not derived from `notes` or `fulfillment_details_*`.
346
+ */
347
+ cancellation_reason?: string;
348
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
349
+ cancellation_details_text?: string;
350
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
351
+ cancellation_details_html?: string;
333
352
  /** When true, a terminal fulfillment status triggers a customer email. */
334
353
  notify_customer?: boolean;
335
354
  }
@@ -349,6 +368,17 @@ export interface V2OrderFulfillmentNotificationParams {
349
368
  fulfillment_status?: string;
350
369
  fulfillment_details_text?: string;
351
370
  fulfillment_details_html?: string;
371
+ /**
372
+ * Customer-visible cancellation reason. **Required** when
373
+ * `fulfillment_status` is `cancelled`/`canceled` — the request is rejected
374
+ * with `400` if it is missing or blank. Not derived from
375
+ * `fulfillment_details_*`.
376
+ */
377
+ cancellation_reason?: string;
378
+ /** Customer-visible cancellation detail (plain text). Only used if provided. */
379
+ cancellation_details_text?: string;
380
+ /** Customer-visible cancellation detail (HTML). Only used if provided. */
381
+ cancellation_details_html?: string;
352
382
  line_items?: V2OrderFulfillmentNotificationLineItem[];
353
383
  amount_total?: number;
354
384
  currency?: string;