perspectapi-ts-sdk 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -98,6 +98,74 @@ interface CreateSiteRequest {
98
98
  description?: string;
99
99
  organizationId: number;
100
100
  }
101
+ interface NewsletterSubscription {
102
+ id: string;
103
+ email: string;
104
+ name?: string;
105
+ status: 'pending' | 'confirmed' | 'unsubscribed' | 'bounced' | 'complained';
106
+ frequency: 'instant' | 'daily' | 'weekly' | 'monthly';
107
+ topics?: string[];
108
+ language: string;
109
+ confirmedAt?: string;
110
+ unsubscribedAt?: string;
111
+ createdAt: string;
112
+ updatedAt: string;
113
+ }
114
+ interface CreateNewsletterSubscriptionRequest {
115
+ email: string;
116
+ name?: string;
117
+ list_ids?: string[];
118
+ frequency?: 'instant' | 'daily' | 'weekly' | 'monthly';
119
+ topics?: string[];
120
+ language?: string;
121
+ source?: string;
122
+ source_url?: string;
123
+ double_opt_in?: boolean;
124
+ turnstile_token?: string;
125
+ metadata?: Record<string, any>;
126
+ }
127
+ interface NewsletterList {
128
+ id: string;
129
+ list_name: string;
130
+ slug: string;
131
+ description?: string;
132
+ is_default: boolean;
133
+ subscriber_count?: number;
134
+ }
135
+ interface NewsletterPreferences {
136
+ frequency?: 'instant' | 'daily' | 'weekly' | 'monthly';
137
+ topics?: string[];
138
+ language?: string;
139
+ email_format?: 'html' | 'text' | 'both';
140
+ timezone?: string;
141
+ track_opens?: boolean;
142
+ track_clicks?: boolean;
143
+ }
144
+ interface NewsletterStatusResponse {
145
+ subscribed: boolean;
146
+ status: string;
147
+ frequency?: string;
148
+ created_at?: string;
149
+ confirmed_at?: string;
150
+ }
151
+ interface NewsletterSubscribeResponse {
152
+ message: string;
153
+ status: string;
154
+ subscription_id?: string;
155
+ }
156
+ interface NewsletterConfirmResponse {
157
+ message: string;
158
+ subscription?: {
159
+ email: string;
160
+ name?: string;
161
+ frequency: string;
162
+ };
163
+ }
164
+ interface NewsletterUnsubscribeRequest {
165
+ token?: string;
166
+ email?: string;
167
+ reason?: string;
168
+ }
101
169
  type ContentStatus = 'draft' | 'publish' | 'private' | 'trash';
102
170
  type ContentType = 'post' | 'page';
103
171
  interface Content {
@@ -329,6 +397,7 @@ interface RequestOptions {
329
397
  body?: any;
330
398
  params?: Record<string, string | number | boolean>;
331
399
  timeout?: number;
400
+ csrfToken?: string;
332
401
  }
333
402
 
334
403
  /**
@@ -365,19 +434,19 @@ declare class HttpClient {
365
434
  /**
366
435
  * POST request
367
436
  */
368
- post<T = any>(endpoint: string, body?: any): Promise<ApiResponse<T>>;
437
+ post<T = any>(endpoint: string, body?: any, options?: Partial<RequestOptions>): Promise<ApiResponse<T>>;
369
438
  /**
370
439
  * PUT request
371
440
  */
372
- put<T = any>(endpoint: string, body?: any): Promise<ApiResponse<T>>;
441
+ put<T = any>(endpoint: string, body?: any, options?: Partial<RequestOptions>): Promise<ApiResponse<T>>;
373
442
  /**
374
443
  * DELETE request
375
444
  */
376
- delete<T = any>(endpoint: string): Promise<ApiResponse<T>>;
445
+ delete<T = any>(endpoint: string, options?: Partial<RequestOptions>): Promise<ApiResponse<T>>;
377
446
  /**
378
447
  * PATCH request
379
448
  */
380
- patch<T = any>(endpoint: string, body?: any): Promise<ApiResponse<T>>;
449
+ patch<T = any>(endpoint: string, body?: any, options?: Partial<RequestOptions>): Promise<ApiResponse<T>>;
381
450
  /**
382
451
  * Build full URL with query parameters
383
452
  */
@@ -433,19 +502,19 @@ declare abstract class BaseClient {
433
502
  /**
434
503
  * Handle create operations
435
504
  */
436
- protected create<T, R = T>(endpoint: string, data: T): Promise<ApiResponse<R>>;
505
+ protected create<T, R = T>(endpoint: string, data: T, csrfToken?: string): Promise<ApiResponse<R>>;
437
506
  /**
438
507
  * Handle update operations
439
508
  */
440
- protected update<T, R = T>(endpoint: string, data: T): Promise<ApiResponse<R>>;
509
+ protected update<T, R = T>(endpoint: string, data: T, csrfToken?: string): Promise<ApiResponse<R>>;
441
510
  /**
442
511
  * Handle partial update operations
443
512
  */
444
- protected patch<T, R = T>(endpoint: string, data: T): Promise<ApiResponse<R>>;
513
+ protected patch<T, R = T>(endpoint: string, data: T, csrfToken?: string): Promise<ApiResponse<R>>;
445
514
  /**
446
515
  * Handle delete operations
447
516
  */
448
- protected delete<T = any>(endpoint: string): Promise<ApiResponse<T>>;
517
+ protected delete<T = any>(endpoint: string, csrfToken?: string): Promise<ApiResponse<T>>;
449
518
  }
450
519
 
451
520
  /**
@@ -1389,8 +1458,11 @@ declare class ContactClient extends BaseClient {
1389
1458
  private contactEndpoint;
1390
1459
  /**
1391
1460
  * Submit contact form
1461
+ * @param siteName - The site to submit contact form to
1462
+ * @param data - Contact form data
1463
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1392
1464
  */
1393
- submitContact(siteName: string, data: CreateContactRequest): Promise<ApiResponse<{
1465
+ submitContact(siteName: string, data: CreateContactRequest, csrfToken?: string): Promise<ApiResponse<{
1394
1466
  id: string;
1395
1467
  message: string;
1396
1468
  status: string;
@@ -1532,6 +1604,208 @@ declare class ContactClient extends BaseClient {
1532
1604
  }>>;
1533
1605
  }
1534
1606
 
1607
+ /**
1608
+ * Newsletter subscription client for PerspectAPI SDK
1609
+ */
1610
+
1611
+ declare class NewsletterClient extends BaseClient {
1612
+ constructor(http: any);
1613
+ /**
1614
+ * Build a newsletter endpoint scoped to a site (without /sites prefix)
1615
+ */
1616
+ private newsletterEndpoint;
1617
+ /**
1618
+ * Subscribe to newsletter
1619
+ * @param siteName - The site to subscribe to
1620
+ * @param data - Subscription data
1621
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1622
+ */
1623
+ subscribe(siteName: string, data: CreateNewsletterSubscriptionRequest, csrfToken?: string): Promise<ApiResponse<NewsletterSubscribeResponse>>;
1624
+ /**
1625
+ * Confirm newsletter subscription via token
1626
+ */
1627
+ confirmSubscription(siteName: string, token: string): Promise<ApiResponse<NewsletterConfirmResponse>>;
1628
+ /**
1629
+ * Unsubscribe from newsletter
1630
+ * @param siteName - The site to unsubscribe from
1631
+ * @param data - Unsubscribe data
1632
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1633
+ */
1634
+ unsubscribe(siteName: string, data: NewsletterUnsubscribeRequest, csrfToken?: string): Promise<ApiResponse<{
1635
+ message: string;
1636
+ }>>;
1637
+ /**
1638
+ * One-click unsubscribe via token (GET request)
1639
+ */
1640
+ unsubscribeByToken(siteName: string, token: string): Promise<ApiResponse<string>>;
1641
+ /**
1642
+ * Update subscription preferences
1643
+ * @param siteName - The site name
1644
+ * @param email - Subscriber email
1645
+ * @param preferences - New preferences
1646
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1647
+ */
1648
+ updatePreferences(siteName: string, email: string, preferences: NewsletterPreferences, csrfToken?: string): Promise<ApiResponse<{
1649
+ message: string;
1650
+ preferences: NewsletterPreferences;
1651
+ }>>;
1652
+ /**
1653
+ * Get available newsletter lists
1654
+ */
1655
+ getLists(siteName: string): Promise<ApiResponse<{
1656
+ lists: NewsletterList[];
1657
+ total: number;
1658
+ }>>;
1659
+ /**
1660
+ * Check subscription status by email
1661
+ */
1662
+ getStatus(siteName: string, email: string): Promise<ApiResponse<NewsletterStatusResponse>>;
1663
+ /**
1664
+ * Get all newsletter subscriptions (admin only)
1665
+ */
1666
+ getSubscriptions(siteName: string, params?: {
1667
+ page?: number;
1668
+ limit?: number;
1669
+ status?: string;
1670
+ list_id?: string;
1671
+ search?: string;
1672
+ startDate?: string;
1673
+ endDate?: string;
1674
+ }): Promise<PaginatedResponse<NewsletterSubscription>>;
1675
+ /**
1676
+ * Get subscription by ID (admin only)
1677
+ */
1678
+ getSubscriptionById(siteName: string, id: string): Promise<ApiResponse<NewsletterSubscription>>;
1679
+ /**
1680
+ * Update subscription status (admin only)
1681
+ */
1682
+ updateSubscriptionStatus(siteName: string, id: string, status: 'confirmed' | 'unsubscribed' | 'bounced' | 'complained', notes?: string): Promise<ApiResponse<{
1683
+ message: string;
1684
+ }>>;
1685
+ /**
1686
+ * Delete subscription (admin only)
1687
+ */
1688
+ deleteSubscription(siteName: string, id: string): Promise<ApiResponse<{
1689
+ message: string;
1690
+ }>>;
1691
+ /**
1692
+ * Bulk update subscriptions (admin only)
1693
+ */
1694
+ bulkUpdateSubscriptions(siteName: string, data: {
1695
+ ids: string[];
1696
+ action: 'confirm' | 'unsubscribe' | 'delete' | 'add_to_list' | 'remove_from_list';
1697
+ list_id?: string;
1698
+ }): Promise<ApiResponse<{
1699
+ success: boolean;
1700
+ updatedCount: number;
1701
+ failedCount: number;
1702
+ }>>;
1703
+ /**
1704
+ * Create newsletter list (admin only)
1705
+ */
1706
+ createList(siteName: string, data: {
1707
+ list_name: string;
1708
+ slug: string;
1709
+ description?: string;
1710
+ is_public?: boolean;
1711
+ is_default?: boolean;
1712
+ double_opt_in?: boolean;
1713
+ welcome_email_enabled?: boolean;
1714
+ }): Promise<ApiResponse<NewsletterList>>;
1715
+ /**
1716
+ * Update newsletter list (admin only)
1717
+ */
1718
+ updateList(siteName: string, listId: string, data: Partial<{
1719
+ list_name: string;
1720
+ description: string;
1721
+ is_public: boolean;
1722
+ is_default: boolean;
1723
+ double_opt_in: boolean;
1724
+ welcome_email_enabled: boolean;
1725
+ }>): Promise<ApiResponse<{
1726
+ message: string;
1727
+ }>>;
1728
+ /**
1729
+ * Delete newsletter list (admin only)
1730
+ */
1731
+ deleteList(siteName: string, listId: string): Promise<ApiResponse<{
1732
+ message: string;
1733
+ }>>;
1734
+ /**
1735
+ * Get newsletter statistics (admin only)
1736
+ */
1737
+ getStatistics(siteName: string, params?: {
1738
+ startDate?: string;
1739
+ endDate?: string;
1740
+ list_id?: string;
1741
+ }): Promise<ApiResponse<{
1742
+ totalSubscribers: number;
1743
+ confirmedSubscribers: number;
1744
+ pendingSubscribers: number;
1745
+ unsubscribedCount: number;
1746
+ bouncedCount: number;
1747
+ subscribersByDay: Array<{
1748
+ date: string;
1749
+ count: number;
1750
+ }>;
1751
+ subscribersByList: Array<{
1752
+ list_id: string;
1753
+ list_name: string;
1754
+ count: number;
1755
+ }>;
1756
+ engagementMetrics: {
1757
+ averageOpenRate: number;
1758
+ averageClickRate: number;
1759
+ };
1760
+ }>>;
1761
+ /**
1762
+ * Export newsletter subscriptions (admin only)
1763
+ */
1764
+ exportSubscriptions(siteName: string, params?: {
1765
+ format?: 'csv' | 'json' | 'xlsx';
1766
+ status?: string;
1767
+ list_id?: string;
1768
+ startDate?: string;
1769
+ endDate?: string;
1770
+ }): Promise<ApiResponse<{
1771
+ downloadUrl: string;
1772
+ expiresAt: string;
1773
+ }>>;
1774
+ /**
1775
+ * Import newsletter subscriptions (admin only)
1776
+ */
1777
+ importSubscriptions(siteName: string, data: {
1778
+ subscriptions: Array<{
1779
+ email: string;
1780
+ name?: string;
1781
+ status?: string;
1782
+ lists?: string[];
1783
+ }>;
1784
+ skip_confirmation?: boolean;
1785
+ update_existing?: boolean;
1786
+ }): Promise<ApiResponse<{
1787
+ imported: number;
1788
+ updated: number;
1789
+ failed: number;
1790
+ errors?: Array<{
1791
+ email: string;
1792
+ error: string;
1793
+ }>;
1794
+ }>>;
1795
+ /**
1796
+ * Send test newsletter (admin only)
1797
+ */
1798
+ sendTestNewsletter(siteName: string, data: {
1799
+ to: string;
1800
+ subject: string;
1801
+ html_content: string;
1802
+ text_content?: string;
1803
+ }): Promise<ApiResponse<{
1804
+ message: string;
1805
+ sent: boolean;
1806
+ }>>;
1807
+ }
1808
+
1535
1809
  /**
1536
1810
  * Main PerspectAPI SDK Client
1537
1811
  * Cloudflare Workers compatible TypeScript SDK
@@ -1549,6 +1823,7 @@ declare class PerspectApiClient {
1549
1823
  readonly webhooks: WebhooksClient;
1550
1824
  readonly checkout: CheckoutClient;
1551
1825
  readonly contact: ContactClient;
1826
+ readonly newsletter: NewsletterClient;
1552
1827
  constructor(config: PerspectApiConfig);
1553
1828
  /**
1554
1829
  * Update authentication token
@@ -1767,4 +2042,4 @@ declare function createCheckoutSession(options: CheckoutSessionOptions): Promise
1767
2042
  error: string;
1768
2043
  }>;
1769
2044
 
1770
- export { type ApiError, type ApiKey, ApiKeysClient, type ApiResponse, AuthClient, type AuthResponse, BaseClient, type BlogPost, CategoriesClient, type Category, CheckoutClient, type CheckoutMetadata, type CheckoutMetadataValue, type CheckoutSession, type CheckoutSessionOptions, ContactClient, type ContactSubmission, type Content, ContentClient, type ContentQueryParams, type ContentStatus, type ContentType, type CreateApiKeyRequest, type CreateCategoryRequest, type CreateCheckoutSessionRequest, type CreateContactRequest, type CreateContentRequest, type CreateOrganizationRequest, type CreatePaymentGatewayRequest, type CreateProductRequest, type CreateSiteRequest, type CreateWebhookRequest, HttpClient, type HttpMethod, type LoadContentBySlugOptions, type LoadContentOptions, type LoadProductBySlugOptions, type LoadProductsOptions, type LoaderLogger, type LoaderOptions, type MediaItem, type Organization, OrganizationsClient, type PaginatedResponse, type PaginationParams, type PaymentGateway, PerspectApiClient, type PerspectApiConfig, type Product, type ProductQueryParams, ProductsClient, type RequestOptions, type SignInRequest, type SignUpRequest, type Site, SitesClient, type UpdateApiKeyRequest, type UpdateContentRequest, type User, type Webhook, WebhooksClient, createApiError, createCheckoutSession, createPerspectApiClient, PerspectApiClient as default, loadAllContent, loadContentBySlug, loadPages, loadPosts, loadProductBySlug, loadProducts, transformContent, transformProduct };
2045
+ export { type ApiError, type ApiKey, ApiKeysClient, type ApiResponse, AuthClient, type AuthResponse, BaseClient, type BlogPost, CategoriesClient, type Category, CheckoutClient, type CheckoutMetadata, type CheckoutMetadataValue, type CheckoutSession, type CheckoutSessionOptions, ContactClient, type ContactSubmission, type Content, ContentClient, type ContentQueryParams, type ContentStatus, type ContentType, type CreateApiKeyRequest, type CreateCategoryRequest, type CreateCheckoutSessionRequest, type CreateContactRequest, type CreateContentRequest, type CreateNewsletterSubscriptionRequest, type CreateOrganizationRequest, type CreatePaymentGatewayRequest, type CreateProductRequest, type CreateSiteRequest, type CreateWebhookRequest, HttpClient, type HttpMethod, type LoadContentBySlugOptions, type LoadContentOptions, type LoadProductBySlugOptions, type LoadProductsOptions, type LoaderLogger, type LoaderOptions, type MediaItem, NewsletterClient, type NewsletterConfirmResponse, type NewsletterList, type NewsletterPreferences, type NewsletterStatusResponse, type NewsletterSubscribeResponse, type NewsletterSubscription, type NewsletterUnsubscribeRequest, type Organization, OrganizationsClient, type PaginatedResponse, type PaginationParams, type PaymentGateway, PerspectApiClient, type PerspectApiConfig, type Product, type ProductQueryParams, ProductsClient, type RequestOptions, type SignInRequest, type SignUpRequest, type Site, SitesClient, type UpdateApiKeyRequest, type UpdateContentRequest, type User, type Webhook, WebhooksClient, createApiError, createCheckoutSession, createPerspectApiClient, PerspectApiClient as default, loadAllContent, loadContentBySlug, loadPages, loadPosts, loadProductBySlug, loadProducts, transformContent, transformProduct };
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ __export(index_exports, {
28
28
  ContactClient: () => ContactClient,
29
29
  ContentClient: () => ContentClient,
30
30
  HttpClient: () => HttpClient,
31
+ NewsletterClient: () => NewsletterClient,
31
32
  OrganizationsClient: () => OrganizationsClient,
32
33
  PerspectApiClient: () => PerspectApiClient,
33
34
  ProductsClient: () => ProductsClient,
@@ -129,26 +130,26 @@ var HttpClient = class {
129
130
  /**
130
131
  * POST request
131
132
  */
132
- async post(endpoint, body) {
133
- return this.request(endpoint, { method: "POST", body });
133
+ async post(endpoint, body, options) {
134
+ return this.request(endpoint, { method: "POST", body, ...options });
134
135
  }
135
136
  /**
136
137
  * PUT request
137
138
  */
138
- async put(endpoint, body) {
139
- return this.request(endpoint, { method: "PUT", body });
139
+ async put(endpoint, body, options) {
140
+ return this.request(endpoint, { method: "PUT", body, ...options });
140
141
  }
141
142
  /**
142
143
  * DELETE request
143
144
  */
144
- async delete(endpoint) {
145
- return this.request(endpoint, { method: "DELETE" });
145
+ async delete(endpoint, options) {
146
+ return this.request(endpoint, { method: "DELETE", ...options });
146
147
  }
147
148
  /**
148
149
  * PATCH request
149
150
  */
150
- async patch(endpoint, body) {
151
- return this.request(endpoint, { method: "PATCH", body });
151
+ async patch(endpoint, body, options) {
152
+ return this.request(endpoint, { method: "PATCH", body, ...options });
152
153
  }
153
154
  /**
154
155
  * Build full URL with query parameters
@@ -174,6 +175,9 @@ var HttpClient = class {
174
175
  ...this.defaultHeaders,
175
176
  ...options.headers
176
177
  };
178
+ if (options.csrfToken) {
179
+ headers["X-CSRF-Token"] = options.csrfToken;
180
+ }
177
181
  const requestOptions = {
178
182
  method: options.method || "GET",
179
183
  headers
@@ -297,26 +301,26 @@ var BaseClient = class {
297
301
  /**
298
302
  * Handle create operations
299
303
  */
300
- async create(endpoint, data) {
301
- return this.http.post(this.buildPath(endpoint), data);
304
+ async create(endpoint, data, csrfToken) {
305
+ return this.http.post(this.buildPath(endpoint), data, { csrfToken });
302
306
  }
303
307
  /**
304
308
  * Handle update operations
305
309
  */
306
- async update(endpoint, data) {
307
- return this.http.put(this.buildPath(endpoint), data);
310
+ async update(endpoint, data, csrfToken) {
311
+ return this.http.put(this.buildPath(endpoint), data, { csrfToken });
308
312
  }
309
313
  /**
310
314
  * Handle partial update operations
311
315
  */
312
- async patch(endpoint, data) {
313
- return this.http.patch(this.buildPath(endpoint), data);
316
+ async patch(endpoint, data, csrfToken) {
317
+ return this.http.patch(this.buildPath(endpoint), data, { csrfToken });
314
318
  }
315
319
  /**
316
320
  * Handle delete operations
317
321
  */
318
- async delete(endpoint) {
319
- return this.http.delete(this.buildPath(endpoint));
322
+ async delete(endpoint, csrfToken) {
323
+ return this.http.delete(this.buildPath(endpoint), { csrfToken });
320
324
  }
321
325
  };
322
326
 
@@ -1183,9 +1187,15 @@ var ContactClient = class extends BaseClient {
1183
1187
  }
1184
1188
  /**
1185
1189
  * Submit contact form
1190
+ * @param siteName - The site to submit contact form to
1191
+ * @param data - Contact form data
1192
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1186
1193
  */
1187
- async submitContact(siteName, data) {
1188
- return this.create(this.contactEndpoint(siteName, "/contact/submit"), data);
1194
+ async submitContact(siteName, data, csrfToken) {
1195
+ if (typeof window !== "undefined" && !csrfToken && !data.turnstileToken) {
1196
+ console.warn("CSRF token recommended for browser-based contact form submissions");
1197
+ }
1198
+ return this.create(this.contactEndpoint(siteName, "/contact/submit"), data, csrfToken);
1189
1199
  }
1190
1200
  /**
1191
1201
  * Get contact submission status
@@ -1267,6 +1277,201 @@ var ContactClient = class extends BaseClient {
1267
1277
  }
1268
1278
  };
1269
1279
 
1280
+ // src/client/newsletter-client.ts
1281
+ var NewsletterClient = class extends BaseClient {
1282
+ constructor(http) {
1283
+ super(http, "/api/v1");
1284
+ }
1285
+ /**
1286
+ * Build a newsletter endpoint scoped to a site (without /sites prefix)
1287
+ */
1288
+ newsletterEndpoint(siteName, endpoint) {
1289
+ return this.siteScopedEndpoint(siteName, endpoint, { includeSitesSegment: false });
1290
+ }
1291
+ /**
1292
+ * Subscribe to newsletter
1293
+ * @param siteName - The site to subscribe to
1294
+ * @param data - Subscription data
1295
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1296
+ */
1297
+ async subscribe(siteName, data, csrfToken) {
1298
+ if (typeof window !== "undefined" && !csrfToken && !data.turnstile_token) {
1299
+ console.warn("CSRF token recommended for browser-based newsletter subscriptions");
1300
+ }
1301
+ return this.create(
1302
+ this.newsletterEndpoint(siteName, "/newsletter/subscribe"),
1303
+ data,
1304
+ csrfToken
1305
+ );
1306
+ }
1307
+ /**
1308
+ * Confirm newsletter subscription via token
1309
+ */
1310
+ async confirmSubscription(siteName, token) {
1311
+ return this.getSingle(
1312
+ this.newsletterEndpoint(siteName, `/newsletter/confirm/${encodeURIComponent(token)}`)
1313
+ );
1314
+ }
1315
+ /**
1316
+ * Unsubscribe from newsletter
1317
+ * @param siteName - The site to unsubscribe from
1318
+ * @param data - Unsubscribe data
1319
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1320
+ */
1321
+ async unsubscribe(siteName, data, csrfToken) {
1322
+ return this.create(
1323
+ this.newsletterEndpoint(siteName, "/newsletter/unsubscribe"),
1324
+ data,
1325
+ csrfToken
1326
+ );
1327
+ }
1328
+ /**
1329
+ * One-click unsubscribe via token (GET request)
1330
+ */
1331
+ async unsubscribeByToken(siteName, token) {
1332
+ return this.http.get(
1333
+ this.buildPath(this.newsletterEndpoint(siteName, `/newsletter/unsubscribe/${encodeURIComponent(token)}`))
1334
+ );
1335
+ }
1336
+ /**
1337
+ * Update subscription preferences
1338
+ * @param siteName - The site name
1339
+ * @param email - Subscriber email
1340
+ * @param preferences - New preferences
1341
+ * @param csrfToken - CSRF token (required for browser-based submissions)
1342
+ */
1343
+ async updatePreferences(siteName, email, preferences, csrfToken) {
1344
+ return this.patch(
1345
+ this.newsletterEndpoint(siteName, "/newsletter/preferences"),
1346
+ { email, ...preferences },
1347
+ csrfToken
1348
+ );
1349
+ }
1350
+ /**
1351
+ * Get available newsletter lists
1352
+ */
1353
+ async getLists(siteName) {
1354
+ return this.getSingle(
1355
+ this.newsletterEndpoint(siteName, "/newsletter/lists")
1356
+ );
1357
+ }
1358
+ /**
1359
+ * Check subscription status by email
1360
+ */
1361
+ async getStatus(siteName, email) {
1362
+ return this.http.get(
1363
+ this.buildPath(this.newsletterEndpoint(siteName, "/newsletter/status")),
1364
+ { email }
1365
+ );
1366
+ }
1367
+ // Admin methods (require authentication)
1368
+ /**
1369
+ * Get all newsletter subscriptions (admin only)
1370
+ */
1371
+ async getSubscriptions(siteName, params) {
1372
+ return this.getPaginated(
1373
+ this.newsletterEndpoint(siteName, "/newsletter/subscriptions"),
1374
+ params
1375
+ );
1376
+ }
1377
+ /**
1378
+ * Get subscription by ID (admin only)
1379
+ */
1380
+ async getSubscriptionById(siteName, id) {
1381
+ return this.getSingle(
1382
+ this.newsletterEndpoint(siteName, `/newsletter/subscriptions/${encodeURIComponent(id)}`)
1383
+ );
1384
+ }
1385
+ /**
1386
+ * Update subscription status (admin only)
1387
+ */
1388
+ async updateSubscriptionStatus(siteName, id, status, notes) {
1389
+ return this.patch(
1390
+ this.newsletterEndpoint(siteName, `/newsletter/subscriptions/${encodeURIComponent(id)}`),
1391
+ { status, notes }
1392
+ );
1393
+ }
1394
+ /**
1395
+ * Delete subscription (admin only)
1396
+ */
1397
+ async deleteSubscription(siteName, id) {
1398
+ return this.delete(
1399
+ this.newsletterEndpoint(siteName, `/newsletter/subscriptions/${encodeURIComponent(id)}`)
1400
+ );
1401
+ }
1402
+ /**
1403
+ * Bulk update subscriptions (admin only)
1404
+ */
1405
+ async bulkUpdateSubscriptions(siteName, data) {
1406
+ return this.create(
1407
+ this.newsletterEndpoint(siteName, "/newsletter/subscriptions/bulk-update"),
1408
+ data
1409
+ );
1410
+ }
1411
+ /**
1412
+ * Create newsletter list (admin only)
1413
+ */
1414
+ async createList(siteName, data) {
1415
+ return this.create(
1416
+ this.newsletterEndpoint(siteName, "/newsletter/lists"),
1417
+ data
1418
+ );
1419
+ }
1420
+ /**
1421
+ * Update newsletter list (admin only)
1422
+ */
1423
+ async updateList(siteName, listId, data) {
1424
+ return this.update(
1425
+ this.newsletterEndpoint(siteName, `/newsletter/lists/${encodeURIComponent(listId)}`),
1426
+ data
1427
+ );
1428
+ }
1429
+ /**
1430
+ * Delete newsletter list (admin only)
1431
+ */
1432
+ async deleteList(siteName, listId) {
1433
+ return this.delete(
1434
+ this.newsletterEndpoint(siteName, `/newsletter/lists/${encodeURIComponent(listId)}`)
1435
+ );
1436
+ }
1437
+ /**
1438
+ * Get newsletter statistics (admin only)
1439
+ */
1440
+ async getStatistics(siteName, params) {
1441
+ return this.http.get(
1442
+ this.buildPath(this.newsletterEndpoint(siteName, "/newsletter/statistics")),
1443
+ params
1444
+ );
1445
+ }
1446
+ /**
1447
+ * Export newsletter subscriptions (admin only)
1448
+ */
1449
+ async exportSubscriptions(siteName, params) {
1450
+ return this.create(
1451
+ this.newsletterEndpoint(siteName, "/newsletter/export"),
1452
+ params || {}
1453
+ );
1454
+ }
1455
+ /**
1456
+ * Import newsletter subscriptions (admin only)
1457
+ */
1458
+ async importSubscriptions(siteName, data) {
1459
+ return this.create(
1460
+ this.newsletterEndpoint(siteName, "/newsletter/import"),
1461
+ data
1462
+ );
1463
+ }
1464
+ /**
1465
+ * Send test newsletter (admin only)
1466
+ */
1467
+ async sendTestNewsletter(siteName, data) {
1468
+ return this.create(
1469
+ this.newsletterEndpoint(siteName, "/newsletter/test"),
1470
+ data
1471
+ );
1472
+ }
1473
+ };
1474
+
1270
1475
  // src/perspect-api-client.ts
1271
1476
  var PerspectApiClient = class {
1272
1477
  http;
@@ -1281,6 +1486,7 @@ var PerspectApiClient = class {
1281
1486
  webhooks;
1282
1487
  checkout;
1283
1488
  contact;
1489
+ newsletter;
1284
1490
  constructor(config) {
1285
1491
  if (!config.baseUrl) {
1286
1492
  throw new Error("baseUrl is required in PerspectApiConfig");
@@ -1296,6 +1502,7 @@ var PerspectApiClient = class {
1296
1502
  this.webhooks = new WebhooksClient(this.http);
1297
1503
  this.checkout = new CheckoutClient(this.http);
1298
1504
  this.contact = new ContactClient(this.http);
1505
+ this.newsletter = new NewsletterClient(this.http);
1299
1506
  }
1300
1507
  /**
1301
1508
  * Update authentication token
@@ -1758,6 +1965,7 @@ async function createCheckoutSession(options) {
1758
1965
  ContactClient,
1759
1966
  ContentClient,
1760
1967
  HttpClient,
1968
+ NewsletterClient,
1761
1969
  OrganizationsClient,
1762
1970
  PerspectApiClient,
1763
1971
  ProductsClient,