perspectapi-ts-sdk 5.0.2 → 5.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.
- package/dist/index.d.mts +72 -21
- package/dist/index.d.ts +72 -21
- package/dist/index.js +135 -47
- package/dist/index.mjs +134 -47
- package/package.json +1 -1
- package/src/cache/cloudflare-kv-adapter.ts +58 -0
- package/src/index.ts +1 -0
- package/src/v2/client/base-v2-client.ts +55 -9
- package/src/v2/client/categories-client.ts +5 -4
- package/src/v2/client/content-client.ts +5 -4
- package/src/v2/client/newsletter-client.ts +35 -4
- package/src/v2/client/orders-client.ts +5 -4
- package/src/v2/client/products-client.ts +5 -4
- package/src/v2/index.ts +22 -13
- package/src/v2/types.ts +4 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* v2 Base Client — cursor pagination, expand support, typed errors.
|
|
2
|
+
* v2 Base Client — cursor pagination, expand support, caching, typed errors.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { HttpClient } from '../../utils/http-client';
|
|
6
|
+
import type { CacheManager } from '../../cache/cache-manager';
|
|
7
|
+
import type { CachePolicy, CacheInvalidateOptions } from '../../cache/types';
|
|
6
8
|
import type { V2List, V2Error, V2Deleted } from '../types';
|
|
7
9
|
|
|
8
10
|
export class PerspectV2Error extends Error {
|
|
@@ -24,10 +26,12 @@ export class PerspectV2Error extends Error {
|
|
|
24
26
|
export abstract class BaseV2Client {
|
|
25
27
|
protected http: HttpClient;
|
|
26
28
|
protected basePath: string;
|
|
29
|
+
protected cache?: CacheManager;
|
|
27
30
|
|
|
28
|
-
constructor(http: HttpClient, basePath: string) {
|
|
31
|
+
constructor(http: HttpClient, basePath: string, cache?: CacheManager) {
|
|
29
32
|
this.http = http;
|
|
30
33
|
this.basePath = basePath;
|
|
34
|
+
this.cache = cache && cache.isEnabled() ? cache : undefined;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
protected buildPath(endpoint: string): string {
|
|
@@ -77,19 +81,26 @@ export abstract class BaseV2Client {
|
|
|
77
81
|
return payload as T;
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
/** GET a single resource. */
|
|
81
|
-
protected async getOne<T>(path: string, params?: object): Promise<T> {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
+
/** GET a single resource, with optional caching. */
|
|
85
|
+
protected async getOne<T>(path: string, params?: object, cachePolicy?: CachePolicy): Promise<T> {
|
|
86
|
+
const fetcher = async () => {
|
|
87
|
+
const response = await this.http.get<T>(path, this.toParams(params));
|
|
88
|
+
return this.extractData<T>(response);
|
|
89
|
+
};
|
|
90
|
+
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
84
91
|
}
|
|
85
92
|
|
|
86
|
-
/** GET a list of resources with cursor pagination. */
|
|
93
|
+
/** GET a list of resources with cursor pagination, with optional caching. */
|
|
87
94
|
protected async getList<T>(
|
|
88
95
|
path: string,
|
|
89
96
|
params?: object,
|
|
97
|
+
cachePolicy?: CachePolicy,
|
|
90
98
|
): Promise<V2List<T>> {
|
|
91
|
-
const
|
|
92
|
-
|
|
99
|
+
const fetcher = async () => {
|
|
100
|
+
const response = await this.http.get<V2List<T>>(path, this.toParams(params));
|
|
101
|
+
return this.extractData<V2List<T>>(response);
|
|
102
|
+
};
|
|
103
|
+
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
/** POST to create a resource. */
|
|
@@ -110,6 +121,41 @@ export abstract class BaseV2Client {
|
|
|
110
121
|
return this.extractData<V2Deleted>(response);
|
|
111
122
|
}
|
|
112
123
|
|
|
124
|
+
/** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
|
|
125
|
+
private async fetchWithCache<T>(
|
|
126
|
+
path: string,
|
|
127
|
+
params: object | undefined,
|
|
128
|
+
policy: CachePolicy | undefined,
|
|
129
|
+
fetcher: () => Promise<T>,
|
|
130
|
+
): Promise<T> {
|
|
131
|
+
if (!this.cache || policy?.skipCache) {
|
|
132
|
+
return fetcher();
|
|
133
|
+
}
|
|
134
|
+
const key = this.buildCacheKey(path, params);
|
|
135
|
+
return this.cache.getOrSet<T>(key, fetcher, policy);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Invalidate cache entries by keys or tags. */
|
|
139
|
+
protected async invalidateCache(options: CacheInvalidateOptions): Promise<void> {
|
|
140
|
+
if (!this.cache) return;
|
|
141
|
+
await this.cache.invalidate(options);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private buildCacheKey(path: string, params?: object): string {
|
|
145
|
+
const parts: Array<string | Record<string, unknown>> = [path];
|
|
146
|
+
if (params && Object.keys(params).length > 0) {
|
|
147
|
+
const sorted: Record<string, unknown> = {};
|
|
148
|
+
for (const key of Object.keys(params).sort()) {
|
|
149
|
+
sorted[key] = (params as Record<string, unknown>)[key];
|
|
150
|
+
}
|
|
151
|
+
parts.push(sorted);
|
|
152
|
+
}
|
|
153
|
+
if (this.cache) {
|
|
154
|
+
return this.cache.buildKey(parts);
|
|
155
|
+
}
|
|
156
|
+
return parts.map(p => typeof p === 'string' ? p : JSON.stringify(p)).join(':');
|
|
157
|
+
}
|
|
158
|
+
|
|
113
159
|
/**
|
|
114
160
|
* Auto-paginating async generator.
|
|
115
161
|
* Yields every item across all pages.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { BaseV2Client } from './base-v2-client';
|
|
6
|
+
import type { CachePolicy } from '../../cache/types';
|
|
6
7
|
import type {
|
|
7
8
|
V2Category, V2CategoryCreateParams, V2CategoryUpdateParams,
|
|
8
9
|
V2PaginationParams, V2List, V2Deleted,
|
|
@@ -10,12 +11,12 @@ import type {
|
|
|
10
11
|
|
|
11
12
|
export class CategoriesV2Client extends BaseV2Client {
|
|
12
13
|
|
|
13
|
-
async list(siteName: string, params?: V2PaginationParams & { type?: string }): Promise<V2List<V2Category>> {
|
|
14
|
-
return this.getList<V2Category>(this.sitePath(siteName, 'categories'), params);
|
|
14
|
+
async list(siteName: string, params?: V2PaginationParams & { type?: string }, cachePolicy?: CachePolicy): Promise<V2List<V2Category>> {
|
|
15
|
+
return this.getList<V2Category>(this.sitePath(siteName, 'categories'), params, cachePolicy);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
async get(siteName: string, id: string): Promise<V2Category> {
|
|
18
|
-
return this.getOne<V2Category>(this.sitePath(siteName, 'categories', id));
|
|
18
|
+
async get(siteName: string, id: string, cachePolicy?: CachePolicy): Promise<V2Category> {
|
|
19
|
+
return this.getOne<V2Category>(this.sitePath(siteName, 'categories', id), undefined, cachePolicy);
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
async create(siteName: string, data: V2CategoryCreateParams): Promise<V2Category> {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { BaseV2Client } from './base-v2-client';
|
|
6
|
+
import type { CachePolicy } from '../../cache/types';
|
|
6
7
|
import type {
|
|
7
8
|
V2Content, V2ContentCreateParams, V2ContentUpdateParams,
|
|
8
9
|
V2ContentListParams, V2List, V2Deleted,
|
|
@@ -10,16 +11,16 @@ import type {
|
|
|
10
11
|
|
|
11
12
|
export class ContentV2Client extends BaseV2Client {
|
|
12
13
|
|
|
13
|
-
async list(siteName: string, params?: V2ContentListParams): Promise<V2List<V2Content>> {
|
|
14
|
-
return this.getList<V2Content>(this.sitePath(siteName, 'content'), params);
|
|
14
|
+
async list(siteName: string, params?: V2ContentListParams, cachePolicy?: CachePolicy): Promise<V2List<V2Content>> {
|
|
15
|
+
return this.getList<V2Content>(this.sitePath(siteName, 'content'), params, cachePolicy);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
async *listAutoPaginated(siteName: string, params?: Omit<V2ContentListParams, 'starting_after' | 'ending_before'>) {
|
|
18
19
|
yield* this.listAutoPaginate<V2Content>(this.sitePath(siteName, 'content'), params);
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
async get(siteName: string, idOrSlug: string): Promise<V2Content> {
|
|
22
|
-
return this.getOne<V2Content>(this.sitePath(siteName, 'content', idOrSlug));
|
|
22
|
+
async get(siteName: string, idOrSlug: string, cachePolicy?: CachePolicy): Promise<V2Content> {
|
|
23
|
+
return this.getOne<V2Content>(this.sitePath(siteName, 'content', idOrSlug), undefined, cachePolicy);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
async create(siteName: string, data: V2ContentCreateParams): Promise<V2Content> {
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { BaseV2Client } from './base-v2-client';
|
|
6
|
+
import type { CachePolicy } from '../../cache/types';
|
|
6
7
|
import type {
|
|
7
8
|
V2NewsletterSubscription, V2NewsletterList, V2NewsletterCampaign,
|
|
8
|
-
V2PaginationParams, V2List,
|
|
9
|
+
V2PaginationParams, V2List, V2NewsletterTrackingResponse,
|
|
9
10
|
} from '../types';
|
|
10
11
|
|
|
11
12
|
export class NewsletterV2Client extends BaseV2Client {
|
|
@@ -48,29 +49,55 @@ export class NewsletterV2Client extends BaseV2Client {
|
|
|
48
49
|
);
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
async trackOpen(
|
|
53
|
+
siteName: string,
|
|
54
|
+
token: string,
|
|
55
|
+
): Promise<V2NewsletterTrackingResponse> {
|
|
56
|
+
return this.post<V2NewsletterTrackingResponse>(
|
|
57
|
+
this.sitePath(siteName, 'newsletter', `track/open/${encodeURIComponent(token)}`),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async trackClick(
|
|
62
|
+
siteName: string,
|
|
63
|
+
token: string,
|
|
64
|
+
url: string,
|
|
65
|
+
): Promise<V2NewsletterTrackingResponse> {
|
|
66
|
+
return this.post<V2NewsletterTrackingResponse>(
|
|
67
|
+
this.sitePath(siteName, 'newsletter', `track/click/${encodeURIComponent(token)}`),
|
|
68
|
+
{ url },
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
51
72
|
// --- Subscriptions (admin) ---
|
|
52
73
|
|
|
53
74
|
async listSubscriptions(
|
|
54
75
|
siteName: string,
|
|
55
76
|
params?: V2PaginationParams & { status?: string },
|
|
77
|
+
cachePolicy?: CachePolicy,
|
|
56
78
|
): Promise<V2List<V2NewsletterSubscription>> {
|
|
57
79
|
return this.getList<V2NewsletterSubscription>(
|
|
58
80
|
this.sitePath(siteName, 'newsletter', 'subscriptions'),
|
|
59
81
|
params,
|
|
82
|
+
cachePolicy,
|
|
60
83
|
);
|
|
61
84
|
}
|
|
62
85
|
|
|
63
|
-
async getSubscription(siteName: string, id: string): Promise<V2NewsletterSubscription> {
|
|
86
|
+
async getSubscription(siteName: string, id: string, cachePolicy?: CachePolicy): Promise<V2NewsletterSubscription> {
|
|
64
87
|
return this.getOne<V2NewsletterSubscription>(
|
|
65
88
|
this.sitePath(siteName, 'newsletter', `subscriptions/${id}`),
|
|
89
|
+
undefined,
|
|
90
|
+
cachePolicy,
|
|
66
91
|
);
|
|
67
92
|
}
|
|
68
93
|
|
|
69
94
|
// --- Lists ---
|
|
70
95
|
|
|
71
|
-
async listLists(siteName: string): Promise<V2List<V2NewsletterList>> {
|
|
96
|
+
async listLists(siteName: string, cachePolicy?: CachePolicy): Promise<V2List<V2NewsletterList>> {
|
|
72
97
|
return this.getList<V2NewsletterList>(
|
|
73
98
|
this.sitePath(siteName, 'newsletter', 'lists'),
|
|
99
|
+
undefined,
|
|
100
|
+
cachePolicy,
|
|
74
101
|
);
|
|
75
102
|
}
|
|
76
103
|
|
|
@@ -79,16 +106,20 @@ export class NewsletterV2Client extends BaseV2Client {
|
|
|
79
106
|
async listCampaigns(
|
|
80
107
|
siteName: string,
|
|
81
108
|
params?: V2PaginationParams & { status?: string },
|
|
109
|
+
cachePolicy?: CachePolicy,
|
|
82
110
|
): Promise<V2List<V2NewsletterCampaign>> {
|
|
83
111
|
return this.getList<V2NewsletterCampaign>(
|
|
84
112
|
this.sitePath(siteName, 'newsletter', 'campaigns'),
|
|
85
113
|
params,
|
|
114
|
+
cachePolicy,
|
|
86
115
|
);
|
|
87
116
|
}
|
|
88
117
|
|
|
89
|
-
async getCampaign(siteName: string, idOrSlug: string): Promise<V2NewsletterCampaign> {
|
|
118
|
+
async getCampaign(siteName: string, idOrSlug: string, cachePolicy?: CachePolicy): Promise<V2NewsletterCampaign> {
|
|
90
119
|
return this.getOne<V2NewsletterCampaign>(
|
|
91
120
|
this.sitePath(siteName, 'newsletter', `campaigns/${idOrSlug}`),
|
|
121
|
+
undefined,
|
|
122
|
+
cachePolicy,
|
|
92
123
|
);
|
|
93
124
|
}
|
|
94
125
|
}
|
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { BaseV2Client } from './base-v2-client';
|
|
6
|
+
import type { CachePolicy } from '../../cache/types';
|
|
6
7
|
import type { V2Order, V2OrderListParams, V2List } from '../types';
|
|
7
8
|
|
|
8
9
|
export class OrdersV2Client extends BaseV2Client {
|
|
9
10
|
|
|
10
|
-
async list(siteName: string, params?: V2OrderListParams): Promise<V2List<V2Order>> {
|
|
11
|
-
return this.getList<V2Order>(this.sitePath(siteName, 'orders'), params);
|
|
11
|
+
async list(siteName: string, params?: V2OrderListParams, cachePolicy?: CachePolicy): Promise<V2List<V2Order>> {
|
|
12
|
+
return this.getList<V2Order>(this.sitePath(siteName, 'orders'), params, cachePolicy);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
async *listAutoPaginated(siteName: string, params?: Omit<V2OrderListParams, 'starting_after' | 'ending_before'>) {
|
|
15
16
|
yield* this.listAutoPaginate<V2Order>(this.sitePath(siteName, 'orders'), params);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
async get(siteName: string, id: string): Promise<V2Order> {
|
|
19
|
-
return this.getOne<V2Order>(this.sitePath(siteName, 'orders', id));
|
|
19
|
+
async get(siteName: string, id: string, cachePolicy?: CachePolicy): Promise<V2Order> {
|
|
20
|
+
return this.getOne<V2Order>(this.sitePath(siteName, 'orders', id), undefined, cachePolicy);
|
|
20
21
|
}
|
|
21
22
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { BaseV2Client } from './base-v2-client';
|
|
6
|
+
import type { CachePolicy } from '../../cache/types';
|
|
6
7
|
import type {
|
|
7
8
|
V2Product, V2ProductCreateParams, V2ProductUpdateParams,
|
|
8
9
|
V2ProductListParams, V2List, V2Deleted,
|
|
@@ -10,16 +11,16 @@ import type {
|
|
|
10
11
|
|
|
11
12
|
export class ProductsV2Client extends BaseV2Client {
|
|
12
13
|
|
|
13
|
-
async list(siteName: string, params?: V2ProductListParams): Promise<V2List<V2Product>> {
|
|
14
|
-
return this.getList<V2Product>(this.sitePath(siteName, 'products'), params);
|
|
14
|
+
async list(siteName: string, params?: V2ProductListParams, cachePolicy?: CachePolicy): Promise<V2List<V2Product>> {
|
|
15
|
+
return this.getList<V2Product>(this.sitePath(siteName, 'products'), params, cachePolicy);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
async *listAutoPaginated(siteName: string, params?: Omit<V2ProductListParams, 'starting_after' | 'ending_before'>) {
|
|
18
19
|
yield* this.listAutoPaginate<V2Product>(this.sitePath(siteName, 'products'), params);
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
async get(siteName: string, idOrSlug: string): Promise<V2Product> {
|
|
22
|
-
return this.getOne<V2Product>(this.sitePath(siteName, 'products', idOrSlug));
|
|
22
|
+
async get(siteName: string, idOrSlug: string, cachePolicy?: CachePolicy): Promise<V2Product> {
|
|
23
|
+
return this.getOne<V2Product>(this.sitePath(siteName, 'products', idOrSlug), undefined, cachePolicy);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
async create(siteName: string, data: V2ProductCreateParams): Promise<V2Product> {
|
package/src/v2/index.ts
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { HttpClient } from '../utils/http-client';
|
|
14
|
+
import { CacheManager } from '../cache/cache-manager';
|
|
14
15
|
import type { PerspectApiConfig } from '../types';
|
|
16
|
+
import type { CacheConfig } from '../cache/types';
|
|
15
17
|
|
|
16
18
|
import { ContentV2Client } from './client/content-client';
|
|
17
19
|
import { ProductsV2Client } from './client/products-client';
|
|
@@ -26,8 +28,13 @@ import { SitesV2Client } from './client/sites-client';
|
|
|
26
28
|
import { ApiKeysV2Client } from './client/api-keys-client';
|
|
27
29
|
import { WebhooksV2Client } from './client/webhooks-client';
|
|
28
30
|
|
|
31
|
+
export interface PerspectApiV2Config extends PerspectApiConfig {
|
|
32
|
+
cache?: CacheConfig;
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
export class PerspectApiV2Client {
|
|
30
36
|
private http: HttpClient;
|
|
37
|
+
readonly cache: CacheManager;
|
|
31
38
|
|
|
32
39
|
readonly content: ContentV2Client;
|
|
33
40
|
readonly products: ProductsV2Client;
|
|
@@ -42,7 +49,7 @@ export class PerspectApiV2Client {
|
|
|
42
49
|
readonly apiKeys: ApiKeysV2Client;
|
|
43
50
|
readonly webhooks: WebhooksV2Client;
|
|
44
51
|
|
|
45
|
-
constructor(config:
|
|
52
|
+
constructor(config: PerspectApiV2Config) {
|
|
46
53
|
// Ensure base URL points to /api/v2
|
|
47
54
|
const baseUrl = config.baseUrl.replace(/\/+$/, '');
|
|
48
55
|
const v2BaseUrl = baseUrl.endsWith('/api/v2')
|
|
@@ -50,20 +57,22 @@ export class PerspectApiV2Client {
|
|
|
50
57
|
: `${baseUrl}/api/v2`;
|
|
51
58
|
|
|
52
59
|
this.http = new HttpClient({ ...config, baseUrl: v2BaseUrl });
|
|
60
|
+
this.cache = new CacheManager(config.cache);
|
|
53
61
|
|
|
54
62
|
const basePath = '';
|
|
55
|
-
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this.
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
66
|
-
this.
|
|
63
|
+
const cache = this.cache;
|
|
64
|
+
this.content = new ContentV2Client(this.http, basePath, cache);
|
|
65
|
+
this.products = new ProductsV2Client(this.http, basePath, cache);
|
|
66
|
+
this.categories = new CategoriesV2Client(this.http, basePath, cache);
|
|
67
|
+
this.collections = new CollectionsV2Client(this.http, basePath, cache);
|
|
68
|
+
this.orders = new OrdersV2Client(this.http, basePath, cache);
|
|
69
|
+
this.siteUsers = new SiteUsersV2Client(this.http, basePath, cache);
|
|
70
|
+
this.newsletter = new NewsletterV2Client(this.http, basePath, cache);
|
|
71
|
+
this.contacts = new ContactsV2Client(this.http, basePath, cache);
|
|
72
|
+
this.organizations = new OrganizationsV2Client(this.http, basePath, cache);
|
|
73
|
+
this.sites = new SitesV2Client(this.http, basePath, cache);
|
|
74
|
+
this.apiKeys = new ApiKeysV2Client(this.http, basePath, cache);
|
|
75
|
+
this.webhooks = new WebhooksV2Client(this.http, basePath, cache);
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
/** Update the JWT token for authenticated requests. */
|
package/src/v2/types.ts
CHANGED
|
@@ -311,6 +311,10 @@ export interface V2NewsletterCampaign extends V2Object {
|
|
|
311
311
|
updated_at: string | null;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
export interface V2NewsletterTrackingResponse {
|
|
315
|
+
success: boolean;
|
|
316
|
+
}
|
|
317
|
+
|
|
314
318
|
// --- Contact ---
|
|
315
319
|
|
|
316
320
|
export interface V2ContactSubmission extends V2Object {
|