perspectapi-ts-sdk 5.4.5 → 6.0.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 +235 -2
- package/dist/index.d.ts +235 -2
- package/dist/index.js +207 -12
- package/dist/index.mjs +207 -12
- package/package.json +1 -1
- package/src/cache/cache-manager.ts +2 -8
- package/src/index.ts +1 -0
- package/src/v2/client/base-v2-client.ts +6 -0
- package/src/v2/client/content-client.ts +125 -4
- package/src/v2/client/newsletter-client.ts +85 -1
- package/src/v2/client/orders-client.ts +27 -1
- package/src/v2/client/site-users-client.ts +76 -3
- package/src/v2/types.ts +192 -0
|
@@ -12,15 +12,57 @@ import type {
|
|
|
12
12
|
export class ContentV2Client extends BaseV2Client {
|
|
13
13
|
|
|
14
14
|
async list(siteName: string, params?: V2ContentListParams, cachePolicy?: CachePolicy): Promise<V2List<V2Content>> {
|
|
15
|
-
return this.getList<V2Content>(
|
|
15
|
+
return this.getList<V2Content>(
|
|
16
|
+
this.sitePath(siteName, 'content'),
|
|
17
|
+
params,
|
|
18
|
+
this.withContentTags(siteName, cachePolicy, {
|
|
19
|
+
category: params?.category,
|
|
20
|
+
slugPrefix: params?.slug_prefix,
|
|
21
|
+
type: params?.type,
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
16
24
|
}
|
|
17
25
|
|
|
18
|
-
async *listAutoPaginated(
|
|
19
|
-
|
|
26
|
+
async *listAutoPaginated(
|
|
27
|
+
siteName: string,
|
|
28
|
+
params?: Omit<V2ContentListParams, 'starting_after' | 'ending_before'>,
|
|
29
|
+
cachePolicy?: CachePolicy,
|
|
30
|
+
) {
|
|
31
|
+
let startingAfter: string | undefined;
|
|
32
|
+
let hasMore = true;
|
|
33
|
+
|
|
34
|
+
while (hasMore) {
|
|
35
|
+
const queryParams: V2ContentListParams = { ...(params ?? {}) };
|
|
36
|
+
if (startingAfter) {
|
|
37
|
+
queryParams.starting_after = startingAfter;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const page = await this.list(siteName, queryParams, cachePolicy);
|
|
41
|
+
for (const item of page.data) {
|
|
42
|
+
yield item;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
hasMore = page.has_more;
|
|
46
|
+
if (page.data.length > 0) {
|
|
47
|
+
startingAfter = page.data[page.data.length - 1].id;
|
|
48
|
+
} else {
|
|
49
|
+
hasMore = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
20
52
|
}
|
|
21
53
|
|
|
22
54
|
async get(siteName: string, idOrSlug: string, cachePolicy?: CachePolicy): Promise<V2Content> {
|
|
23
|
-
|
|
55
|
+
const isContentId = this.isContentId(idOrSlug);
|
|
56
|
+
|
|
57
|
+
return this.getOne<V2Content>(
|
|
58
|
+
this.sitePath(siteName, 'content', idOrSlug),
|
|
59
|
+
undefined,
|
|
60
|
+
this.withContentTags(siteName, cachePolicy, {
|
|
61
|
+
id: isContentId ? idOrSlug : undefined,
|
|
62
|
+
slug: isContentId ? undefined : idOrSlug,
|
|
63
|
+
slugPrefix: isContentId ? undefined : this.extractSlugPrefix(idOrSlug),
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
24
66
|
}
|
|
25
67
|
|
|
26
68
|
async create(siteName: string, data: V2ContentCreateParams): Promise<V2Content> {
|
|
@@ -42,4 +84,83 @@ export class ContentV2Client extends BaseV2Client {
|
|
|
42
84
|
async unpublish(siteName: string, id: string): Promise<V2Content> {
|
|
43
85
|
return this.post<V2Content>(this.sitePath(siteName, 'content', `${id}/unpublish`));
|
|
44
86
|
}
|
|
87
|
+
|
|
88
|
+
private withContentTags(
|
|
89
|
+
siteName: string,
|
|
90
|
+
cachePolicy: CachePolicy | undefined,
|
|
91
|
+
options: {
|
|
92
|
+
category?: string | null;
|
|
93
|
+
id?: string;
|
|
94
|
+
slug?: string;
|
|
95
|
+
slugPrefix?: string | null;
|
|
96
|
+
type?: string | null;
|
|
97
|
+
},
|
|
98
|
+
): CachePolicy {
|
|
99
|
+
const tags = new Set<string>(cachePolicy?.tags ?? []);
|
|
100
|
+
|
|
101
|
+
for (const tag of this.buildContentTags(siteName, options)) {
|
|
102
|
+
tags.add(tag);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
...cachePolicy,
|
|
107
|
+
tags: Array.from(tags),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private buildContentTags(
|
|
112
|
+
siteName: string,
|
|
113
|
+
options: {
|
|
114
|
+
category?: string | null;
|
|
115
|
+
id?: string;
|
|
116
|
+
slug?: string;
|
|
117
|
+
slugPrefix?: string | null;
|
|
118
|
+
type?: string | null;
|
|
119
|
+
},
|
|
120
|
+
): string[] {
|
|
121
|
+
const tags = new Set<string>(['content', `content:site:${siteName}`]);
|
|
122
|
+
const normalizedPrefix = this.normalizeTagPart(options.slugPrefix);
|
|
123
|
+
const normalizedCategory = this.normalizeTagPart(options.category);
|
|
124
|
+
const normalizedType = this.normalizeTagPart(options.type);
|
|
125
|
+
|
|
126
|
+
if (options.slug) {
|
|
127
|
+
tags.add(`content:slug:${siteName}:${options.slug}`);
|
|
128
|
+
}
|
|
129
|
+
if (options.id) {
|
|
130
|
+
tags.add(`content:id:${options.id}`);
|
|
131
|
+
}
|
|
132
|
+
if (normalizedPrefix) {
|
|
133
|
+
tags.add(`content:prefix:${normalizedPrefix}`);
|
|
134
|
+
}
|
|
135
|
+
if (normalizedType) {
|
|
136
|
+
tags.add(`content:${normalizedType}`);
|
|
137
|
+
}
|
|
138
|
+
if (normalizedCategory) {
|
|
139
|
+
tags.add('content:category');
|
|
140
|
+
tags.add(`content:category:${siteName}:${normalizedCategory}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return Array.from(tags);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private normalizeTagPart(value?: string | null): string | undefined {
|
|
147
|
+
if (typeof value !== 'string') {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const normalized = value.trim().toLowerCase();
|
|
152
|
+
return normalized === '' ? undefined : normalized;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private extractSlugPrefix(slug: string): string | undefined {
|
|
156
|
+
const slashIndex = slug.indexOf('/');
|
|
157
|
+
if (slashIndex > 0) {
|
|
158
|
+
return slug.slice(0, slashIndex);
|
|
159
|
+
}
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private isContentId(idOrSlug: string): boolean {
|
|
164
|
+
return /^cnt_/i.test(idOrSlug);
|
|
165
|
+
}
|
|
45
166
|
}
|
|
@@ -6,7 +6,11 @@ import { BaseV2Client } from './base-v2-client';
|
|
|
6
6
|
import type { CachePolicy } from '../../cache/types';
|
|
7
7
|
import type {
|
|
8
8
|
V2NewsletterSubscription, V2NewsletterList, V2NewsletterCampaign,
|
|
9
|
-
V2PaginationParams, V2List, V2NewsletterTrackingResponse,
|
|
9
|
+
V2PaginationParams, V2List, V2Deleted, V2NewsletterTrackingResponse,
|
|
10
|
+
V2NewsletterListCreateParams, V2NewsletterListUpdateParams,
|
|
11
|
+
V2NewsletterSyncInput, V2NewsletterSyncResult,
|
|
12
|
+
V2NewsletterSubscriptionListMembershipUpdate,
|
|
13
|
+
V2NewsletterImportRequest, V2NewsletterImportResult,
|
|
10
14
|
} from '../types';
|
|
11
15
|
|
|
12
16
|
export class NewsletterV2Client extends BaseV2Client {
|
|
@@ -122,4 +126,84 @@ export class NewsletterV2Client extends BaseV2Client {
|
|
|
122
126
|
cachePolicy,
|
|
123
127
|
);
|
|
124
128
|
}
|
|
129
|
+
|
|
130
|
+
// --- Admin writes: Lists CRUD ---
|
|
131
|
+
|
|
132
|
+
async createList(
|
|
133
|
+
siteName: string,
|
|
134
|
+
data: V2NewsletterListCreateParams,
|
|
135
|
+
): Promise<V2NewsletterList> {
|
|
136
|
+
return this.post<V2NewsletterList>(
|
|
137
|
+
this.sitePath(siteName, 'newsletter', 'lists'),
|
|
138
|
+
data,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async updateList(
|
|
143
|
+
siteName: string,
|
|
144
|
+
id: string,
|
|
145
|
+
data: V2NewsletterListUpdateParams,
|
|
146
|
+
): Promise<V2NewsletterList> {
|
|
147
|
+
return this.patchOne<V2NewsletterList>(
|
|
148
|
+
this.sitePath(siteName, 'newsletter', `lists/${id}`),
|
|
149
|
+
data,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async deleteList(siteName: string, id: string): Promise<V2Deleted> {
|
|
154
|
+
return this.deleteOne(
|
|
155
|
+
this.sitePath(siteName, 'newsletter', `lists/${id}`),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// --- Admin writes: Subscription sync / membership / import ---
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Upsert a subscription by email and (optionally) replace its list
|
|
163
|
+
* memberships. Returns a `newsletter_sync_result` envelope with the
|
|
164
|
+
* outcome (created / updated / resubscribed / already-unsubscribed).
|
|
165
|
+
*/
|
|
166
|
+
async syncSubscription(
|
|
167
|
+
siteName: string,
|
|
168
|
+
data: V2NewsletterSyncInput,
|
|
169
|
+
): Promise<V2NewsletterSyncResult> {
|
|
170
|
+
return this.post<V2NewsletterSyncResult>(
|
|
171
|
+
this.sitePath(siteName, 'newsletter', 'subscriptions/sync'),
|
|
172
|
+
data,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Add/remove/replace the list memberships for an existing subscription.
|
|
178
|
+
* Returns the refreshed subscription record.
|
|
179
|
+
*/
|
|
180
|
+
async updateSubscriptionListMembership(
|
|
181
|
+
siteName: string,
|
|
182
|
+
subscriptionId: string,
|
|
183
|
+
data: V2NewsletterSubscriptionListMembershipUpdate,
|
|
184
|
+
): Promise<V2NewsletterSubscription> {
|
|
185
|
+
return this.post<V2NewsletterSubscription>(
|
|
186
|
+
this.sitePath(
|
|
187
|
+
siteName,
|
|
188
|
+
'newsletter',
|
|
189
|
+
`subscriptions/${subscriptionId}/list-membership`,
|
|
190
|
+
),
|
|
191
|
+
data,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Bulk import subscriptions. Each row is upserted via the same sync
|
|
197
|
+
* path; `refreshListCounts` is deferred until after all rows are
|
|
198
|
+
* processed on the server.
|
|
199
|
+
*/
|
|
200
|
+
async importSubscriptions(
|
|
201
|
+
siteName: string,
|
|
202
|
+
data: V2NewsletterImportRequest,
|
|
203
|
+
): Promise<V2NewsletterImportResult> {
|
|
204
|
+
return this.post<V2NewsletterImportResult>(
|
|
205
|
+
this.sitePath(siteName, 'newsletter', 'subscriptions/import'),
|
|
206
|
+
data,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
125
209
|
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* v2 Orders Client (checkout sessions)
|
|
3
|
+
*
|
|
4
|
+
* `create()` initiates a Stripe checkout session and returns the checkout URL.
|
|
5
|
+
* No CSRF token is needed — v2 uses API-key auth only.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import { BaseV2Client } from './base-v2-client';
|
|
6
9
|
import type { CachePolicy } from '../../cache/types';
|
|
7
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
V2Order,
|
|
12
|
+
V2OrderListParams,
|
|
13
|
+
V2OrderCreateParams,
|
|
14
|
+
V2OrderCreateResult,
|
|
15
|
+
V2List,
|
|
16
|
+
} from '../types';
|
|
8
17
|
|
|
9
18
|
export class OrdersV2Client extends BaseV2Client {
|
|
10
19
|
|
|
@@ -19,4 +28,21 @@ export class OrdersV2Client extends BaseV2Client {
|
|
|
19
28
|
async get(siteName: string, id: string, cachePolicy?: CachePolicy): Promise<V2Order> {
|
|
20
29
|
return this.getOne<V2Order>(this.sitePath(siteName, 'orders', id), undefined, cachePolicy);
|
|
21
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a checkout session via Stripe. Returns the session ID and a
|
|
34
|
+
* `checkout_url` that the client should redirect to (or open in a new tab).
|
|
35
|
+
*
|
|
36
|
+
* This replaces the v1 `checkout.createCheckoutSession()` + `getCsrfToken()`
|
|
37
|
+
* dance — v2 is API-key-only and requires no CSRF token.
|
|
38
|
+
*/
|
|
39
|
+
async create(
|
|
40
|
+
siteName: string,
|
|
41
|
+
data: V2OrderCreateParams,
|
|
42
|
+
): Promise<V2OrderCreateResult> {
|
|
43
|
+
return this.post<V2OrderCreateResult>(
|
|
44
|
+
this.sitePath(siteName, 'orders'),
|
|
45
|
+
data,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
22
48
|
}
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* v2 Site Users Client
|
|
3
|
+
*
|
|
4
|
+
* Two classes of endpoints:
|
|
5
|
+
* - Admin paths (list/get/update/OTP flows) require an API key. Use the
|
|
6
|
+
* usual `setApiKey(...)` on the main `PerspectApiV2Client` before calling.
|
|
7
|
+
* - `/me*` paths require a site-user JWT (minted by `verifyOtp`). Call
|
|
8
|
+
* `setAuth(jwt)` on the main client before calling these.
|
|
3
9
|
*/
|
|
4
10
|
|
|
5
11
|
import { BaseV2Client } from './base-v2-client';
|
|
6
|
-
import type {
|
|
12
|
+
import type {
|
|
13
|
+
V2SiteUser,
|
|
14
|
+
V2SiteUserUpdateParams,
|
|
15
|
+
V2SiteUserMeUpdateParams,
|
|
16
|
+
V2SiteUserListParams,
|
|
17
|
+
V2SiteUserWithProfile,
|
|
18
|
+
V2SiteUserProfile,
|
|
19
|
+
V2List,
|
|
20
|
+
V2Deleted,
|
|
21
|
+
} from '../types';
|
|
7
22
|
|
|
8
23
|
export interface V2OtpRequestResponse {
|
|
9
24
|
object: 'otp_request';
|
|
@@ -17,7 +32,7 @@ export interface V2OtpVerifyResponse extends V2SiteUser {
|
|
|
17
32
|
|
|
18
33
|
export class SiteUsersV2Client extends BaseV2Client {
|
|
19
34
|
|
|
20
|
-
// --- OTP Auth ---
|
|
35
|
+
// --- OTP Auth (public, API-key-scoped) ---
|
|
21
36
|
|
|
22
37
|
async requestOtp(
|
|
23
38
|
siteName: string,
|
|
@@ -33,7 +48,7 @@ export class SiteUsersV2Client extends BaseV2Client {
|
|
|
33
48
|
return this.post<V2OtpVerifyResponse>(this.sitePath(siteName, 'users', 'verify-otp'), data);
|
|
34
49
|
}
|
|
35
50
|
|
|
36
|
-
// --- Admin ---
|
|
51
|
+
// --- Admin (API key) ---
|
|
37
52
|
|
|
38
53
|
async list(siteName: string, params?: V2SiteUserListParams): Promise<V2List<V2SiteUser>> {
|
|
39
54
|
return this.getList<V2SiteUser>(this.sitePath(siteName, 'users'), params);
|
|
@@ -50,4 +65,62 @@ export class SiteUsersV2Client extends BaseV2Client {
|
|
|
50
65
|
async update(siteName: string, id: string, data: V2SiteUserUpdateParams): Promise<V2SiteUser> {
|
|
51
66
|
return this.patchOne<V2SiteUser>(this.sitePath(siteName, 'users', id), data);
|
|
52
67
|
}
|
|
68
|
+
|
|
69
|
+
// --- Authenticated "me" endpoints (site-user JWT) ---
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Load the currently-authenticated site user's canonical record plus their
|
|
73
|
+
* profile KV map. Requires `client.setAuth(jwt)` to have been called with
|
|
74
|
+
* the token returned from `verifyOtp`.
|
|
75
|
+
*/
|
|
76
|
+
async getMe(siteName: string): Promise<V2SiteUserWithProfile> {
|
|
77
|
+
return this.getOne<V2SiteUserWithProfile>(
|
|
78
|
+
this.sitePath(siteName, 'users', 'me'),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Update the authenticated user's own fields. */
|
|
83
|
+
async updateMe(
|
|
84
|
+
siteName: string,
|
|
85
|
+
data: V2SiteUserMeUpdateParams,
|
|
86
|
+
): Promise<V2SiteUser> {
|
|
87
|
+
return this.patchOne<V2SiteUser>(
|
|
88
|
+
this.sitePath(siteName, 'users', 'me'),
|
|
89
|
+
data,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Fetch the profile KV map as a dedicated `site_user_profile` envelope. */
|
|
94
|
+
async getProfile(siteName: string): Promise<V2SiteUserProfile> {
|
|
95
|
+
return this.getOne<V2SiteUserProfile>(
|
|
96
|
+
this.sitePath(siteName, 'users', 'me/profile'),
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Set a single profile key. The value is persisted verbatim — callers wanting
|
|
102
|
+
* structured data should JSON-stringify their value first.
|
|
103
|
+
*/
|
|
104
|
+
async setProfileValue(
|
|
105
|
+
siteName: string,
|
|
106
|
+
key: string,
|
|
107
|
+
value: string,
|
|
108
|
+
): Promise<V2SiteUserProfile> {
|
|
109
|
+
const encoded = encodeURIComponent(key);
|
|
110
|
+
return this.putOne<V2SiteUserProfile>(
|
|
111
|
+
this.sitePath(siteName, 'users', `me/profile/${encoded}`),
|
|
112
|
+
{ value },
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Delete a single profile key. */
|
|
117
|
+
async deleteProfileValue(
|
|
118
|
+
siteName: string,
|
|
119
|
+
key: string,
|
|
120
|
+
): Promise<V2Deleted> {
|
|
121
|
+
const encoded = encodeURIComponent(key);
|
|
122
|
+
return this.deleteOne(
|
|
123
|
+
this.sitePath(siteName, 'users', `me/profile/${encoded}`),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
53
126
|
}
|
package/src/v2/types.ts
CHANGED
|
@@ -250,6 +250,90 @@ export interface V2OrderListParams extends V2PaginationParams {
|
|
|
250
250
|
date_to?: string;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
// --- Order create (checkout session creation) ---
|
|
254
|
+
|
|
255
|
+
export interface V2OrderLineItemPriceData {
|
|
256
|
+
currency: string;
|
|
257
|
+
product_data: {
|
|
258
|
+
name: string;
|
|
259
|
+
description?: string;
|
|
260
|
+
images?: string[];
|
|
261
|
+
};
|
|
262
|
+
unit_amount: number;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export interface V2OrderLineItem {
|
|
266
|
+
sku_id?: number;
|
|
267
|
+
product_id?: number;
|
|
268
|
+
price_data?: V2OrderLineItemPriceData;
|
|
269
|
+
price?: string;
|
|
270
|
+
quantity: number;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface V2OrderAddress {
|
|
274
|
+
line1?: string;
|
|
275
|
+
line2?: string;
|
|
276
|
+
city?: string;
|
|
277
|
+
state?: string;
|
|
278
|
+
postal_code?: string;
|
|
279
|
+
country?: string;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export interface V2OrderTaxRequest {
|
|
283
|
+
strategy?: string;
|
|
284
|
+
customer_identifier?: string;
|
|
285
|
+
customer_profile_id?: string;
|
|
286
|
+
customer_display_name?: string;
|
|
287
|
+
allow_exemption?: boolean;
|
|
288
|
+
save_profile?: boolean;
|
|
289
|
+
customer_exemption?: {
|
|
290
|
+
status?: "none" | "exempt" | "reverse_charge";
|
|
291
|
+
reason?: string;
|
|
292
|
+
tax_id?: string;
|
|
293
|
+
tax_id_type?: string;
|
|
294
|
+
certificate_url?: string;
|
|
295
|
+
metadata?: Record<string, unknown>;
|
|
296
|
+
expires_at?: string;
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export interface V2OrderCreateParams {
|
|
301
|
+
line_items: V2OrderLineItem[];
|
|
302
|
+
success_url: string;
|
|
303
|
+
cancel_url: string;
|
|
304
|
+
customer_email?: string;
|
|
305
|
+
site_user_id?: string;
|
|
306
|
+
mode?: "payment" | "subscription";
|
|
307
|
+
metadata?: Record<string, string | number | boolean>;
|
|
308
|
+
tax?: V2OrderTaxRequest;
|
|
309
|
+
shipping_amount?: number;
|
|
310
|
+
shipping_address?: V2OrderAddress;
|
|
311
|
+
billing_address?: V2OrderAddress;
|
|
312
|
+
currency?: string;
|
|
313
|
+
referral_code?: string;
|
|
314
|
+
referrer_site_user_id?: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export interface V2OrderCreateResult extends V2Object {
|
|
318
|
+
object: "checkout_session";
|
|
319
|
+
checkout_url: string | null;
|
|
320
|
+
payment_status: string | null;
|
|
321
|
+
tax: {
|
|
322
|
+
amount: number;
|
|
323
|
+
currency: string;
|
|
324
|
+
strategy: string;
|
|
325
|
+
exemption_applied: boolean;
|
|
326
|
+
exemption_status: string;
|
|
327
|
+
breakdown: Array<{
|
|
328
|
+
jurisdiction?: string;
|
|
329
|
+
rate_percent: number;
|
|
330
|
+
tax_amount: number;
|
|
331
|
+
taxable_amount: number;
|
|
332
|
+
source: string;
|
|
333
|
+
}>;
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
253
337
|
// --- Site Users ---
|
|
254
338
|
|
|
255
339
|
export interface V2SiteUser extends V2Object {
|
|
@@ -275,11 +359,41 @@ export interface V2SiteUserUpdateParams {
|
|
|
275
359
|
metadata?: Record<string, unknown>;
|
|
276
360
|
}
|
|
277
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Patch shape for the authenticated `/me` endpoint. Unlike the admin update,
|
|
364
|
+
* end users cannot change their own `status`.
|
|
365
|
+
*/
|
|
366
|
+
export interface V2SiteUserMeUpdateParams {
|
|
367
|
+
first_name?: string;
|
|
368
|
+
last_name?: string;
|
|
369
|
+
avatar_url?: string;
|
|
370
|
+
metadata?: Record<string, unknown>;
|
|
371
|
+
}
|
|
372
|
+
|
|
278
373
|
export interface V2SiteUserListParams extends V2PaginationParams {
|
|
279
374
|
status?: "active" | "suspended" | "pending_verification";
|
|
280
375
|
email?: string;
|
|
281
376
|
}
|
|
282
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Response shape of `GET /sites/{siteName}/users/me`. Extends V2SiteUser with
|
|
380
|
+
* a `profile` side-channel populated from the `site_user_profiles` KV table.
|
|
381
|
+
*/
|
|
382
|
+
export interface V2SiteUserWithProfile extends V2SiteUser {
|
|
383
|
+
profile: Record<string, unknown>;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Standalone profile envelope returned by
|
|
388
|
+
* `GET|PUT /sites/{siteName}/users/me/profile[/:key]`. Each `data` entry is a
|
|
389
|
+
* parsed value (arbitrary JSON).
|
|
390
|
+
*/
|
|
391
|
+
export interface V2SiteUserProfile {
|
|
392
|
+
object: "site_user_profile";
|
|
393
|
+
site_user_id: string;
|
|
394
|
+
data: Record<string, unknown>;
|
|
395
|
+
}
|
|
396
|
+
|
|
283
397
|
// --- Newsletter ---
|
|
284
398
|
|
|
285
399
|
export interface V2NewsletterSubscription extends V2Object {
|
|
@@ -332,6 +446,84 @@ export interface V2NewsletterTrackingResponse {
|
|
|
332
446
|
success: boolean;
|
|
333
447
|
}
|
|
334
448
|
|
|
449
|
+
// --- Newsletter admin writes ---
|
|
450
|
+
|
|
451
|
+
export interface V2NewsletterListCreateParams {
|
|
452
|
+
list_name: string;
|
|
453
|
+
slug: string;
|
|
454
|
+
description?: string | null;
|
|
455
|
+
is_public?: boolean;
|
|
456
|
+
is_default?: boolean;
|
|
457
|
+
welcome_email_enabled?: boolean;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export interface V2NewsletterListUpdateParams {
|
|
461
|
+
list_name?: string;
|
|
462
|
+
slug?: string;
|
|
463
|
+
description?: string | null;
|
|
464
|
+
is_public?: boolean;
|
|
465
|
+
is_default?: boolean;
|
|
466
|
+
welcome_email_enabled?: boolean;
|
|
467
|
+
status?: "active" | "archived";
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export interface V2NewsletterSyncInput {
|
|
471
|
+
email: string;
|
|
472
|
+
name?: string | null;
|
|
473
|
+
status?: "pending" | "confirmed" | "unsubscribed" | "bounced" | "complained";
|
|
474
|
+
list_ids?: string[];
|
|
475
|
+
frequency?: "instant" | "daily" | "weekly" | "monthly";
|
|
476
|
+
topics?: string[];
|
|
477
|
+
language?: string | null;
|
|
478
|
+
source?: string | null;
|
|
479
|
+
source_url?: string | null;
|
|
480
|
+
notes?: string | null;
|
|
481
|
+
tags?: string[];
|
|
482
|
+
metadata?: Record<string, unknown>;
|
|
483
|
+
resubscribe_override?: boolean;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export interface V2NewsletterSyncResult {
|
|
487
|
+
object: "newsletter_sync_result";
|
|
488
|
+
applied: boolean;
|
|
489
|
+
code: "CREATED" | "UPDATED" | "RESUBSCRIBED" | "ALREADY_UNSUBSCRIBED";
|
|
490
|
+
skipped_unsubscribed: boolean;
|
|
491
|
+
resubscribed: boolean;
|
|
492
|
+
created: boolean;
|
|
493
|
+
updated: boolean;
|
|
494
|
+
subscription: Record<string, unknown>;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export interface V2NewsletterSubscriptionListMembershipUpdate {
|
|
498
|
+
mode: "add" | "remove" | "replace";
|
|
499
|
+
list_ids: string[];
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export interface V2NewsletterImportRequest {
|
|
503
|
+
rows: V2NewsletterSyncInput[];
|
|
504
|
+
resubscribe_override?: boolean;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export interface V2NewsletterImportResult {
|
|
508
|
+
object: "newsletter_import_result";
|
|
509
|
+
total: number;
|
|
510
|
+
processed: number;
|
|
511
|
+
applied: number;
|
|
512
|
+
created: number;
|
|
513
|
+
updated: number;
|
|
514
|
+
resubscribed: number;
|
|
515
|
+
skipped_unsubscribed: number;
|
|
516
|
+
rows: Array<{
|
|
517
|
+
index: number;
|
|
518
|
+
email: string;
|
|
519
|
+
applied: boolean;
|
|
520
|
+
code: V2NewsletterSyncResult["code"];
|
|
521
|
+
skipped_unsubscribed: boolean;
|
|
522
|
+
resubscribed: boolean;
|
|
523
|
+
subscription_id: string;
|
|
524
|
+
}>;
|
|
525
|
+
}
|
|
526
|
+
|
|
335
527
|
// --- Contact ---
|
|
336
528
|
|
|
337
529
|
export interface V2ContactSubmission extends V2Object {
|