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/README.md +127 -0
- package/dist/index.d.mts +285 -10
- package/dist/index.d.ts +285 -10
- package/dist/index.js +226 -18
- package/dist/index.mjs +225 -18
- package/package.json +1 -1
- package/src/client/base-client.ts +11 -8
- package/src/client/contact-client.ts +14 -2
- package/src/client/newsletter-client.ts +381 -0
- package/src/index.ts +9 -0
- package/src/perspect-api-client.ts +3 -0
- package/src/types/index.ts +78 -0
- package/src/utils/http-client.ts +13 -8
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
|
-
|
|
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,
|