perspectapi-ts-sdk 3.6.0 → 4.1.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.
@@ -8,6 +8,8 @@ import type { CachePolicy } from '../cache/types';
8
8
  import type {
9
9
  Product,
10
10
  CreateProductRequest,
11
+ CreateProductSkuRequest,
12
+ ProductSku,
11
13
  PaginatedResponse,
12
14
  ApiResponse,
13
15
  ProductQueryParams,
@@ -457,17 +459,7 @@ export class ProductsClient extends BaseClient {
457
459
  async getProductSkus(
458
460
  siteName: string,
459
461
  productId: number
460
- ): Promise<ApiResponse<Array<{
461
- sku_id: number;
462
- sku: string;
463
- price?: number;
464
- sale_price?: number;
465
- stock_quantity?: number;
466
- combination_key: string;
467
- value_ids: number[];
468
- created_at: string;
469
- updated_at: string;
470
- }>>> {
462
+ ): Promise<ApiResponse<ProductSku[]>> {
471
463
  const endpoint = this.siteScopedEndpoint(
472
464
  siteName,
473
465
  `/products/${productId}/skus`,
@@ -482,26 +474,66 @@ export class ProductsClient extends BaseClient {
482
474
  async createProductSku(
483
475
  siteName: string,
484
476
  productId: number,
485
- data: {
486
- sku: string;
487
- price?: number | null;
488
- sale_price?: number | null;
489
- stock_quantity?: number | null;
490
- value_ids: number[];
491
- }
492
- ): Promise<ApiResponse<{
493
- sku_id: number;
494
- sku: string;
495
- price?: number;
496
- sale_price?: number;
497
- stock_quantity?: number;
498
- combination_key: string;
499
- }>> {
477
+ data: CreateProductSkuRequest
478
+ ): Promise<ApiResponse<ProductSku>> {
500
479
  const endpoint = this.siteScopedEndpoint(
501
480
  siteName,
502
481
  `/products/${productId}/skus`,
503
482
  { includeSitesSegment: false }
504
483
  );
505
- return this.create(endpoint, data);
484
+
485
+ const unitAmountCandidate =
486
+ typeof data.unit_amount === 'number'
487
+ ? data.unit_amount
488
+ : typeof data.price === 'number'
489
+ ? Math.round(data.price * 100)
490
+ : undefined;
491
+
492
+ if (typeof unitAmountCandidate !== 'number' || !Number.isFinite(unitAmountCandidate)) {
493
+ throw new Error('createProductSku requires unit_amount or price');
494
+ }
495
+ const unitAmount = unitAmountCandidate;
496
+
497
+ const quantityAvailable =
498
+ data.quantity_available !== undefined
499
+ ? data.quantity_available
500
+ : (data.stock_quantity ?? null);
501
+
502
+ const payload: {
503
+ sku: string | null;
504
+ media_id?: string | null;
505
+ unit_amount: number;
506
+ currency: string;
507
+ quantity_available: number | null;
508
+ published?: boolean;
509
+ gateway_price_id_test?: string | null;
510
+ gateway_price_id_live?: string | null;
511
+ value_ids: number[];
512
+ } = {
513
+ sku: data.sku ?? null,
514
+ unit_amount: unitAmount,
515
+ currency: data.currency || 'usd',
516
+ quantity_available: quantityAvailable,
517
+ published: data.published,
518
+ gateway_price_id_test: data.gateway_price_id_test,
519
+ gateway_price_id_live: data.gateway_price_id_live,
520
+ value_ids: data.value_ids,
521
+ };
522
+
523
+ if (Object.prototype.hasOwnProperty.call(data, 'media_id')) {
524
+ if (data.media_id === null) {
525
+ payload.media_id = null;
526
+ } else if (typeof data.media_id === 'string') {
527
+ const trimmed = data.media_id.trim();
528
+ if (!trimmed) {
529
+ throw new Error('createProductSku media_id cannot be empty');
530
+ }
531
+ payload.media_id = trimmed;
532
+ } else if (data.media_id !== undefined) {
533
+ throw new Error('createProductSku media_id must be a string or null');
534
+ }
535
+ }
536
+
537
+ return this.create(endpoint, payload);
506
538
  }
507
539
  }
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ export { WebhooksClient } from './client/webhooks-client';
19
19
  export { CheckoutClient } from './client/checkout-client';
20
20
  export { ContactClient } from './client/contact-client';
21
21
  export { NewsletterClient } from './client/newsletter-client';
22
+ export { NewsletterManagementClient } from './client/newsletter-management-client';
22
23
  export { SiteUsersClient } from './client/site-users-client';
23
24
  export { BundlesClient } from './client/bundles-client';
24
25
 
@@ -109,6 +110,30 @@ export type {
109
110
  NewsletterConfirmResponse,
110
111
  NewsletterUnsubscribeRequest,
111
112
  NewsletterUnsubscribeResponse,
113
+ NewsletterManagementListMembership,
114
+ NewsletterManagementSubscription,
115
+ NewsletterSubscriptionSyncRequest,
116
+ NewsletterSubscriptionSyncResponse,
117
+ NewsletterSubscriptionsBulkAction,
118
+ NewsletterSubscriptionsBulkUpdateRequest,
119
+ NewsletterSubscriptionsBulkOutcome,
120
+ NewsletterSubscriptionsBulkUpdateResponse,
121
+ NewsletterSubscriptionMembershipUpdateRequest,
122
+ NewsletterSubscriptionImportRowRequest,
123
+ NewsletterSubscriptionsImportRequest,
124
+ NewsletterSubscriptionsImportRowResult,
125
+ NewsletterSubscriptionsImportResponse,
126
+ NewsletterManagementPagination,
127
+ NewsletterManagementSubscriptionsListResponse,
128
+ NewsletterManagementList,
129
+ NewsletterManagementSeries,
130
+ NewsletterManagementCampaign,
131
+ NewsletterManagementCampaignListResponse,
132
+ NewsletterCampaignTestSendRequest,
133
+ NewsletterCampaignTestSendResponse,
134
+ NewsletterManagementStatsResponse,
135
+ NewsletterExportCreateRequest,
136
+ NewsletterExportCreateResponse,
112
137
  ContactSubmitResponse,
113
138
  ContactStatusResponse,
114
139
  SiteUser,
@@ -16,6 +16,7 @@ import { WebhooksClient } from './client/webhooks-client';
16
16
  import { CheckoutClient } from './client/checkout-client';
17
17
  import { ContactClient } from './client/contact-client';
18
18
  import { NewsletterClient } from './client/newsletter-client';
19
+ import { NewsletterManagementClient } from './client/newsletter-management-client';
19
20
  import { SiteUsersClient } from './client/site-users-client';
20
21
  import { BundlesClient } from './client/bundles-client';
21
22
 
@@ -37,6 +38,7 @@ export class PerspectApiClient {
37
38
  public readonly checkout: CheckoutClient;
38
39
  public readonly contact: ContactClient;
39
40
  public readonly newsletter: NewsletterClient;
41
+ public readonly newsletterManagement: NewsletterManagementClient;
40
42
  public readonly siteUsers: SiteUsersClient;
41
43
  public readonly bundles: BundlesClient;
42
44
 
@@ -62,6 +64,7 @@ export class PerspectApiClient {
62
64
  this.checkout = new CheckoutClient(this.http, this.cache);
63
65
  this.contact = new ContactClient(this.http, this.cache);
64
66
  this.newsletter = new NewsletterClient(this.http, this.cache);
67
+ this.newsletterManagement = new NewsletterManagementClient(this.http, this.cache);
65
68
  this.siteUsers = new SiteUsersClient(this.http, this.cache);
66
69
  this.bundles = new BundlesClient(this.http, this.cache);
67
70
  }
@@ -225,6 +225,269 @@ export interface NewsletterUnsubscribeResponse {
225
225
  status?: string;
226
226
  }
227
227
 
228
+ // Newsletter Management
229
+ export interface NewsletterManagementListMembership {
230
+ id: string;
231
+ list_name: string;
232
+ slug: string;
233
+ }
234
+
235
+ export interface NewsletterManagementSubscription {
236
+ id: string;
237
+ site_id: string;
238
+ site_name: string;
239
+ email: string;
240
+ name?: string | null;
241
+ status: 'pending' | 'confirmed' | 'unsubscribed' | 'bounced' | 'complained';
242
+ confirmation_token?: string | null;
243
+ unsubscribe_token: string;
244
+ double_opt_in: boolean;
245
+ confirmed_at?: string | null;
246
+ source?: string | null;
247
+ source_url?: string | null;
248
+ frequency: 'instant' | 'daily' | 'weekly' | 'monthly';
249
+ topics?: string[] | string | null;
250
+ language: string;
251
+ tags?: string[] | string | null;
252
+ custom_fields?: Record<string, any> | string | null;
253
+ notes?: string | null;
254
+ unsubscribed_at?: string | null;
255
+ unsubscribe_reason?: string | null;
256
+ created_at: string;
257
+ updated_at: string;
258
+ lists: NewsletterManagementListMembership[];
259
+ }
260
+
261
+ export interface NewsletterSubscriptionSyncRequest {
262
+ email: string;
263
+ name?: string | null;
264
+ status?: 'pending' | 'confirmed' | 'unsubscribed' | 'bounced' | 'complained';
265
+ list_ids?: string[];
266
+ frequency?: 'instant' | 'daily' | 'weekly' | 'monthly';
267
+ topics?: string[];
268
+ language?: string | null;
269
+ source?: string | null;
270
+ source_url?: string | null;
271
+ notes?: string | null;
272
+ tags?: string[];
273
+ metadata?: Record<string, any>;
274
+ resubscribe_override?: boolean;
275
+ }
276
+
277
+ export interface NewsletterSubscriptionSyncResponse {
278
+ applied: boolean;
279
+ code: 'CREATED' | 'UPDATED' | 'RESUBSCRIBED' | 'ALREADY_UNSUBSCRIBED';
280
+ skipped_unsubscribed: boolean;
281
+ resubscribed: boolean;
282
+ created: boolean;
283
+ updated: boolean;
284
+ subscription_id: string;
285
+ subscription: NewsletterManagementSubscription;
286
+ }
287
+
288
+ export type NewsletterSubscriptionsBulkAction =
289
+ | 'confirm'
290
+ | 'unsubscribe'
291
+ | 'delete'
292
+ | 'add_to_list'
293
+ | 'remove_from_list';
294
+
295
+ export interface NewsletterSubscriptionsBulkUpdateRequest {
296
+ ids: string[];
297
+ action: NewsletterSubscriptionsBulkAction;
298
+ list_id?: string;
299
+ resubscribe_override?: boolean;
300
+ }
301
+
302
+ export interface NewsletterSubscriptionsBulkOutcome {
303
+ id: string;
304
+ applied: boolean;
305
+ code: string;
306
+ error?: string;
307
+ skipped_unsubscribed?: boolean;
308
+ }
309
+
310
+ export interface NewsletterSubscriptionsBulkUpdateResponse {
311
+ succeeded: number;
312
+ failed: number;
313
+ skipped_unsubscribed: number;
314
+ outcomes: NewsletterSubscriptionsBulkOutcome[];
315
+ }
316
+
317
+ export interface NewsletterSubscriptionMembershipUpdateRequest {
318
+ mode: 'add' | 'remove' | 'replace';
319
+ list_ids: string[];
320
+ }
321
+
322
+ export interface NewsletterSubscriptionImportRowRequest {
323
+ email: string;
324
+ name?: string | null;
325
+ status?: 'pending' | 'confirmed' | 'unsubscribed' | 'bounced' | 'complained';
326
+ list_ids?: string[];
327
+ frequency?: 'instant' | 'daily' | 'weekly' | 'monthly';
328
+ topics?: string[];
329
+ language?: string | null;
330
+ source?: string | null;
331
+ source_url?: string | null;
332
+ notes?: string | null;
333
+ tags?: string[];
334
+ metadata?: Record<string, any>;
335
+ resubscribe_override?: boolean;
336
+ }
337
+
338
+ export interface NewsletterSubscriptionsImportRequest {
339
+ rows: NewsletterSubscriptionImportRowRequest[];
340
+ resubscribe_override?: boolean;
341
+ }
342
+
343
+ export interface NewsletterSubscriptionsImportRowResult {
344
+ index: number;
345
+ email: string;
346
+ applied: boolean;
347
+ code: string;
348
+ skipped_unsubscribed: boolean;
349
+ resubscribed: boolean;
350
+ subscription_id: string;
351
+ }
352
+
353
+ export interface NewsletterSubscriptionsImportResponse {
354
+ total: number;
355
+ processed: number;
356
+ applied: number;
357
+ created: number;
358
+ updated: number;
359
+ resubscribed: number;
360
+ skipped_unsubscribed: number;
361
+ rows: NewsletterSubscriptionsImportRowResult[];
362
+ }
363
+
364
+ export interface NewsletterManagementPagination {
365
+ page: number;
366
+ limit: number;
367
+ total: number;
368
+ pages: number;
369
+ }
370
+
371
+ export interface NewsletterManagementSubscriptionsListResponse {
372
+ items: NewsletterManagementSubscription[];
373
+ pagination: NewsletterManagementPagination;
374
+ }
375
+
376
+ export interface NewsletterManagementList extends NewsletterList {
377
+ site_id: string;
378
+ site_name: string;
379
+ description?: string;
380
+ is_public: boolean;
381
+ is_default: boolean;
382
+ double_opt_in: boolean;
383
+ welcome_email_enabled: boolean;
384
+ subscriber_count: number;
385
+ status: 'active' | 'archived';
386
+ created_at: string;
387
+ updated_at: string;
388
+ }
389
+
390
+ export interface NewsletterManagementSeries {
391
+ id: string;
392
+ site_id: string;
393
+ site_name: string;
394
+ series_name: string;
395
+ description?: string | null;
396
+ list_ids?: string | null;
397
+ from_name?: string | null;
398
+ from_email?: string | null;
399
+ reply_to_email?: string | null;
400
+ subject_prefix?: string | null;
401
+ cadence: 'manual' | 'daily' | 'weekly' | 'monthly';
402
+ timezone?: string | null;
403
+ send_time?: string | null;
404
+ day_of_week?: number | null;
405
+ day_of_month?: number | null;
406
+ status: 'active' | 'paused' | 'archived';
407
+ last_sent_at?: string | null;
408
+ next_send_at?: string | null;
409
+ tags?: string | null;
410
+ notes?: string | null;
411
+ created_at: string;
412
+ updated_at: string;
413
+ created_by?: string | null;
414
+ }
415
+
416
+ export interface NewsletterManagementCampaign {
417
+ id: string;
418
+ site_id: string;
419
+ site_name: string;
420
+ series_id?: string | null;
421
+ series_name?: string | null;
422
+ campaign_name: string;
423
+ slug?: string | null;
424
+ slug_prefix?: string | null;
425
+ subject: string;
426
+ markdown_content?: string | null;
427
+ template_id?: string | null;
428
+ list_ids?: string | null;
429
+ tags?: string | null;
430
+ notes?: string | null;
431
+ preview_text?: string | null;
432
+ from_name?: string | null;
433
+ from_email?: string | null;
434
+ reply_to_email?: string | null;
435
+ status: 'draft' | 'scheduled' | 'sending' | 'sent' | 'cancelled';
436
+ scheduled_at?: string | null;
437
+ sent_at?: string | null;
438
+ completed_at?: string | null;
439
+ total_recipients?: number | null;
440
+ sent_count?: number | null;
441
+ delivered_count?: number | null;
442
+ opened_count?: number | null;
443
+ clicked_count?: number | null;
444
+ unsubscribed_count?: number | null;
445
+ bounced_count?: number | null;
446
+ complained_count?: number | null;
447
+ created_at: string;
448
+ updated_at: string;
449
+ }
450
+
451
+ export interface NewsletterManagementCampaignListResponse {
452
+ items: NewsletterManagementCampaign[];
453
+ pagination: NewsletterManagementPagination;
454
+ }
455
+
456
+ export interface NewsletterCampaignTestSendRequest {
457
+ to: string | string[];
458
+ subject?: string | null;
459
+ }
460
+
461
+ export interface NewsletterCampaignTestSendResponse {
462
+ sent: number;
463
+ recipients: string[];
464
+ campaign_id: string;
465
+ }
466
+
467
+ export interface NewsletterManagementStatsResponse {
468
+ total: number;
469
+ byStatus: Record<string, number>;
470
+ recentActivity: Array<{
471
+ date: string;
472
+ count: number;
473
+ }>;
474
+ }
475
+
476
+ export interface NewsletterExportCreateRequest {
477
+ format?: 'csv' | 'json' | 'xlsx';
478
+ status?: 'pending' | 'confirmed' | 'unsubscribed' | 'bounced' | 'complained';
479
+ list_id?: string;
480
+ search?: string | null;
481
+ }
482
+
483
+ export interface NewsletterExportCreateResponse {
484
+ exportId: string;
485
+ downloadUrl: string;
486
+ expiresAt: string;
487
+ format: 'csv' | 'json';
488
+ rowCount: number;
489
+ }
490
+
228
491
  // Content Management
229
492
  export type ContentStatus = 'draft' | 'publish' | 'private' | 'trash';
230
493
  export type ContentType = 'post' | 'page' | 'block';
@@ -320,6 +583,49 @@ export interface MediaItem {
320
583
  site_name: string;
321
584
  }
322
585
 
586
+ export interface ProductSkuMediaItem {
587
+ id?: string;
588
+ media_id: string;
589
+ file_name?: string;
590
+ fileName?: string;
591
+ link?: string;
592
+ url?: string;
593
+ content_type?: string;
594
+ contentType?: string;
595
+ width?: number;
596
+ height?: number;
597
+ filesize?: number;
598
+ r2_key?: string;
599
+ site_name?: string;
600
+ }
601
+
602
+ export interface ProductSkuOption {
603
+ name: string;
604
+ key: string;
605
+ value: string;
606
+ label: string;
607
+ value_id: number;
608
+ }
609
+
610
+ export interface ProductSku {
611
+ sku_id: number;
612
+ sku?: string | null;
613
+ combination_key: string;
614
+ media_id?: string | null;
615
+ media?: ProductSkuMediaItem | null;
616
+ options?: ProductSkuOption[];
617
+ unit_amount?: number;
618
+ currency?: string;
619
+ quantity_available?: number | null;
620
+ price?: number;
621
+ sale_price?: number;
622
+ stock_quantity?: number;
623
+ value_ids: number[];
624
+ created_at?: string;
625
+ updated_at?: string;
626
+ [key: string]: any;
627
+ }
628
+
323
629
  export interface Product {
324
630
  id: number | string;
325
631
  name?: string;
@@ -333,6 +639,7 @@ export interface Product {
333
639
  slug_prefix?: string;
334
640
  image?: string;
335
641
  media?: MediaItem[] | MediaItem[][];
642
+ skus?: ProductSku[];
336
643
  isActive?: boolean;
337
644
  organizationId?: number;
338
645
  createdAt?: string;
@@ -362,6 +669,21 @@ export interface CreateProductRequest {
362
669
  isActive?: boolean;
363
670
  }
364
671
 
672
+ export interface CreateProductSkuRequest {
673
+ sku?: string | null;
674
+ media_id?: string | null;
675
+ unit_amount?: number;
676
+ currency?: string;
677
+ quantity_available?: number | null;
678
+ price?: number | null;
679
+ stock_quantity?: number | null;
680
+ sale_price?: number | null;
681
+ published?: boolean;
682
+ gateway_price_id_test?: string | null;
683
+ gateway_price_id_live?: string | null;
684
+ value_ids: number[];
685
+ }
686
+
365
687
  export interface ProductQueryParams extends PaginationParams {
366
688
  organizationId?: number;
367
689
  isActive?: boolean;