perspectapi-ts-sdk 6.5.9 → 7.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/README.md +46 -1011
- package/dist/chunk-K3T2AFYA.mjs +1393 -0
- package/dist/index-CWvUyMt3.d.mts +2224 -0
- package/dist/index-CWvUyMt3.d.ts +2224 -0
- package/dist/index.d.mts +130 -2221
- package/dist/index.d.ts +130 -2221
- package/dist/index.js +8 -2
- package/dist/index.mjs +13 -1364
- package/dist/v2/index.d.mts +1 -0
- package/dist/v2/index.d.ts +1 -0
- package/dist/v2/index.js +1419 -0
- package/dist/v2/index.mjs +40 -0
- package/docs/README.md +15 -0
- package/docs/v1-deprecated/README.md +9 -0
- package/docs/v1-deprecated/examples/README.md +324 -0
- package/docs/v1-deprecated/examples/basic-usage.ts +258 -0
- package/docs/v1-deprecated/examples/cloudflare-worker.ts +274 -0
- package/docs/v1-deprecated/examples/content-query-with-slug-prefix.ts +237 -0
- package/docs/v1-deprecated/examples/image-transforms.ts +200 -0
- package/docs/v1-deprecated/examples/site-user-checkout.ts +186 -0
- package/docs/v1-deprecated/examples/slug-prefix-examples.ts +491 -0
- package/docs/v1-deprecated/legacy-docs/caching.md +667 -0
- package/docs/v1-deprecated/legacy-docs/contact.md +1396 -0
- package/docs/v1-deprecated/legacy-docs/csrf-protection.md +664 -0
- package/docs/v1-deprecated/legacy-docs/image-transforms.md +523 -0
- package/docs/v1-deprecated/legacy-docs/loaders.md +304 -0
- package/docs/v1-deprecated/legacy-docs/newsletter.md +811 -0
- package/docs/v1-deprecated/legacy-docs/site-users.md +817 -0
- package/docs/v1-deprecated/legacy-notes/CHANGELOG-CHECKOUT.md +143 -0
- package/docs/v1-deprecated/legacy-notes/CSRF-CHECKOUT.md +271 -0
- package/docs/v1-deprecated/legacy-notes/IMAGE_TRANSFORMS_PORT.md +298 -0
- package/docs/v1-deprecated/sdk-readme.md +1076 -0
- package/examples/README.md +19 -0
- package/examples/basic-v2.ts +37 -0
- package/llms.txt +25 -0
- package/package.json +18 -7
- package/src/client/api-keys-client.ts +4 -0
- package/src/client/auth-client.ts +4 -0
- package/src/client/base-client.ts +7 -0
- package/src/client/bundles-client.ts +4 -0
- package/src/client/categories-client.ts +4 -0
- package/src/client/checkout-client.ts +4 -0
- package/src/client/contact-client.ts +4 -0
- package/src/client/content-client.ts +4 -0
- package/src/client/newsletter-client.ts +4 -0
- package/src/client/newsletter-management-client.ts +4 -0
- package/src/client/organizations-client.ts +4 -0
- package/src/client/products-client.ts +4 -0
- package/src/client/site-users-client.ts +10 -1
- package/src/client/sites-client.ts +4 -0
- package/src/client/webhooks-client.ts +4 -0
- package/src/deprecation.ts +2 -1
- package/src/index.ts +2 -1
- package/src/loaders.ts +59 -0
- package/src/perspect-api-client.ts +2 -2
- package/src/v2/client/orders-client.ts +6 -1
- package/src/v2/types.ts +3 -0
package/dist/v2/index.js
ADDED
|
@@ -0,0 +1,1419 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/v2/index.ts
|
|
21
|
+
var v2_exports = {};
|
|
22
|
+
__export(v2_exports, {
|
|
23
|
+
ApiKeysV2Client: () => ApiKeysV2Client,
|
|
24
|
+
BaseV2Client: () => BaseV2Client,
|
|
25
|
+
CategoriesV2Client: () => CategoriesV2Client,
|
|
26
|
+
CollectionsV2Client: () => CollectionsV2Client,
|
|
27
|
+
ContactsV2Client: () => ContactsV2Client,
|
|
28
|
+
ContentV2Client: () => ContentV2Client,
|
|
29
|
+
CreditsV2Client: () => CreditsV2Client,
|
|
30
|
+
NewsletterV2Client: () => NewsletterV2Client,
|
|
31
|
+
OrdersV2Client: () => OrdersV2Client,
|
|
32
|
+
OrganizationsV2Client: () => OrganizationsV2Client,
|
|
33
|
+
PerspectApiV2Client: () => PerspectApiV2Client,
|
|
34
|
+
PerspectV2Error: () => PerspectV2Error,
|
|
35
|
+
ProductsV2Client: () => ProductsV2Client,
|
|
36
|
+
SiteUsersV2Client: () => SiteUsersV2Client,
|
|
37
|
+
SitesV2Client: () => SitesV2Client,
|
|
38
|
+
SubscriptionsV2Client: () => SubscriptionsV2Client,
|
|
39
|
+
WebhooksV2Client: () => WebhooksV2Client,
|
|
40
|
+
createPerspectApiV2Client: () => createPerspectApiV2Client
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(v2_exports);
|
|
43
|
+
|
|
44
|
+
// src/types/index.ts
|
|
45
|
+
var PerspectApiError = class extends Error {
|
|
46
|
+
code;
|
|
47
|
+
status;
|
|
48
|
+
details;
|
|
49
|
+
constructor({ message, code, status, details }) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = "PerspectApiError";
|
|
52
|
+
this.code = code;
|
|
53
|
+
this.status = status;
|
|
54
|
+
this.details = details;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/utils/http-client.ts
|
|
59
|
+
var HttpClient = class {
|
|
60
|
+
baseUrl;
|
|
61
|
+
defaultHeaders;
|
|
62
|
+
timeout;
|
|
63
|
+
retries;
|
|
64
|
+
constructor(config) {
|
|
65
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
66
|
+
this.timeout = config.timeout || 3e4;
|
|
67
|
+
this.retries = config.retries || 3;
|
|
68
|
+
this.defaultHeaders = {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
"User-Agent": "perspectapi-ts-sdk/1.0.0",
|
|
71
|
+
...config.headers
|
|
72
|
+
};
|
|
73
|
+
if (config.apiKey) {
|
|
74
|
+
this.defaultHeaders["X-API-Key"] = config.apiKey;
|
|
75
|
+
}
|
|
76
|
+
if (config.jwt) {
|
|
77
|
+
this.defaultHeaders["Authorization"] = `Bearer ${config.jwt}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Update authentication token
|
|
82
|
+
*/
|
|
83
|
+
setAuth(jwt) {
|
|
84
|
+
this.defaultHeaders["Authorization"] = `Bearer ${jwt}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Update API key
|
|
88
|
+
*/
|
|
89
|
+
setApiKey(apiKey) {
|
|
90
|
+
this.defaultHeaders["X-API-Key"] = apiKey;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Whether this client currently has a site-user/admin bearer token attached.
|
|
94
|
+
* Bearer-scoped GETs must not share cache entries across callers.
|
|
95
|
+
*/
|
|
96
|
+
hasBearerAuth() {
|
|
97
|
+
return Boolean(this.defaultHeaders["Authorization"]);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Remove authentication
|
|
101
|
+
*/
|
|
102
|
+
clearAuth() {
|
|
103
|
+
delete this.defaultHeaders["Authorization"];
|
|
104
|
+
delete this.defaultHeaders["X-API-Key"];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Make HTTP request with retry logic
|
|
108
|
+
*/
|
|
109
|
+
async request(endpoint, options = {}) {
|
|
110
|
+
const url = this.buildUrl(endpoint, options.params);
|
|
111
|
+
const requestOptions = this.buildRequestOptions(options);
|
|
112
|
+
console.log(`[HTTP Client] ====== Request Details ======`);
|
|
113
|
+
console.log(`[HTTP Client] Method: ${options.method || "GET"}`);
|
|
114
|
+
console.log(`[HTTP Client] Base URL: ${this.baseUrl}`);
|
|
115
|
+
console.log(`[HTTP Client] Endpoint: ${endpoint}`);
|
|
116
|
+
console.log(`[HTTP Client] Full URL: ${url}`);
|
|
117
|
+
if (options.params) {
|
|
118
|
+
console.log(`[HTTP Client] Query params:`, JSON.stringify(options.params, null, 2));
|
|
119
|
+
if (options.params.slug_prefix) {
|
|
120
|
+
console.log(`[HTTP Client] \u26A0\uFE0F slug_prefix detected: "${options.params.slug_prefix}"`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const safeHeaders = { ...requestOptions.headers };
|
|
124
|
+
if (safeHeaders["Authorization"]) {
|
|
125
|
+
safeHeaders["Authorization"] = "Bearer [REDACTED]";
|
|
126
|
+
}
|
|
127
|
+
if (safeHeaders["X-API-Key"]) {
|
|
128
|
+
safeHeaders["X-API-Key"] = "[REDACTED]";
|
|
129
|
+
}
|
|
130
|
+
console.log(`[HTTP Client] Headers:`, JSON.stringify(safeHeaders, null, 2));
|
|
131
|
+
let lastError;
|
|
132
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
133
|
+
try {
|
|
134
|
+
const response = await this.fetchWithTimeout(url, requestOptions);
|
|
135
|
+
return await this.handleResponse(response);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
lastError = error;
|
|
138
|
+
if (error && typeof error === "object" && "status" in error && typeof error.status === "number" && error.status < 500) {
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
if (attempt === this.retries) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
await this.delay(Math.pow(2, attempt) * 1e3);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
throw lastError;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* GET request
|
|
151
|
+
*/
|
|
152
|
+
async get(endpoint, params) {
|
|
153
|
+
return this.request(endpoint, { method: "GET", params });
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* POST request
|
|
157
|
+
*/
|
|
158
|
+
async post(endpoint, body, options) {
|
|
159
|
+
return this.request(endpoint, { method: "POST", body, ...options });
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* PUT request
|
|
163
|
+
*/
|
|
164
|
+
async put(endpoint, body, options) {
|
|
165
|
+
return this.request(endpoint, { method: "PUT", body, ...options });
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* DELETE request
|
|
169
|
+
*/
|
|
170
|
+
async delete(endpoint, options) {
|
|
171
|
+
return this.request(endpoint, { method: "DELETE", ...options });
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* PATCH request
|
|
175
|
+
*/
|
|
176
|
+
async patch(endpoint, body, options) {
|
|
177
|
+
return this.request(endpoint, { method: "PATCH", body, ...options });
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Build full URL with query parameters
|
|
181
|
+
*/
|
|
182
|
+
buildUrl(endpoint, params) {
|
|
183
|
+
const url = `${this.baseUrl}${endpoint.startsWith("/") ? "" : "/"}${endpoint}`;
|
|
184
|
+
console.log(`[HTTP Client - URL Builder] Base URL: ${this.baseUrl}`);
|
|
185
|
+
console.log(`[HTTP Client - URL Builder] Endpoint: ${endpoint}`);
|
|
186
|
+
console.log(`[HTTP Client - URL Builder] Combined URL (before params): ${url}`);
|
|
187
|
+
if (!params || Object.keys(params).length === 0) {
|
|
188
|
+
console.log(`[HTTP Client - URL Builder] No params, returning: ${url}`);
|
|
189
|
+
return url;
|
|
190
|
+
}
|
|
191
|
+
console.log(`[HTTP Client - URL Builder] Processing params:`, params);
|
|
192
|
+
const searchParams = new URLSearchParams();
|
|
193
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
194
|
+
if (value !== void 0 && value !== null) {
|
|
195
|
+
console.log(`[HTTP Client - URL Builder] Adding param: ${key}=${value}`);
|
|
196
|
+
searchParams.append(key, String(value));
|
|
197
|
+
} else {
|
|
198
|
+
console.log(`[HTTP Client - URL Builder] Skipping null/undefined param: ${key}`);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
const finalUrl = `${url}?${searchParams.toString()}`;
|
|
202
|
+
console.log(`[HTTP Client - URL Builder] Final URL: ${finalUrl}`);
|
|
203
|
+
return finalUrl;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Build request options
|
|
207
|
+
*/
|
|
208
|
+
buildRequestOptions(options) {
|
|
209
|
+
const headers = {
|
|
210
|
+
...this.defaultHeaders,
|
|
211
|
+
...options.headers
|
|
212
|
+
};
|
|
213
|
+
if (options.csrfToken) {
|
|
214
|
+
headers["X-CSRF-Token"] = options.csrfToken;
|
|
215
|
+
}
|
|
216
|
+
const requestOptions = {
|
|
217
|
+
method: options.method || "GET",
|
|
218
|
+
headers
|
|
219
|
+
};
|
|
220
|
+
if (options.body && options.method !== "GET") {
|
|
221
|
+
if (typeof options.body === "string") {
|
|
222
|
+
requestOptions.body = options.body;
|
|
223
|
+
} else {
|
|
224
|
+
requestOptions.body = JSON.stringify(options.body);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return requestOptions;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Fetch with timeout support
|
|
231
|
+
*/
|
|
232
|
+
async fetchWithTimeout(url, options) {
|
|
233
|
+
const controller = new AbortController();
|
|
234
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
235
|
+
try {
|
|
236
|
+
const response = await fetch(url, {
|
|
237
|
+
...options,
|
|
238
|
+
signal: controller.signal
|
|
239
|
+
});
|
|
240
|
+
return response;
|
|
241
|
+
} finally {
|
|
242
|
+
clearTimeout(timeoutId);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Handle response and errors
|
|
247
|
+
*/
|
|
248
|
+
async handleResponse(response) {
|
|
249
|
+
const contentType = response.headers.get("content-type");
|
|
250
|
+
const isJson = contentType?.includes("application/json");
|
|
251
|
+
console.log(`[HTTP Client - Response] Status: ${response.status} ${response.statusText}`);
|
|
252
|
+
console.log(`[HTTP Client - Response] Content-Type: ${contentType}`);
|
|
253
|
+
let data;
|
|
254
|
+
try {
|
|
255
|
+
data = isJson ? await response.json() : await response.text();
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error(`[HTTP Client - Response] Failed to parse response:`, error);
|
|
258
|
+
data = null;
|
|
259
|
+
}
|
|
260
|
+
const dataStr = JSON.stringify(data);
|
|
261
|
+
if (dataStr && dataStr.length > 1e3) {
|
|
262
|
+
console.log(`[HTTP Client - Response] Data (truncated):`, dataStr.substring(0, 1e3) + "...");
|
|
263
|
+
} else {
|
|
264
|
+
console.log(`[HTTP Client - Response] Data:`, data);
|
|
265
|
+
}
|
|
266
|
+
if (!response.ok) {
|
|
267
|
+
console.error(`[HTTP Client - Response] Error response received`);
|
|
268
|
+
const error = new PerspectApiError({
|
|
269
|
+
message: data?.error || data?.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
270
|
+
status: response.status,
|
|
271
|
+
code: data?.code,
|
|
272
|
+
details: data
|
|
273
|
+
});
|
|
274
|
+
console.error(`[HTTP Client - Response] Throwing error:`, error);
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
if (isJson && typeof data === "object") {
|
|
278
|
+
if ("data" in data || "message" in data || "error" in data) {
|
|
279
|
+
const apiResponse = data;
|
|
280
|
+
console.log(`[HTTP Client - Response] Returning API response with success=${apiResponse.success}, data length=${Array.isArray(apiResponse.data) ? apiResponse.data.length : "N/A"}`);
|
|
281
|
+
return apiResponse;
|
|
282
|
+
}
|
|
283
|
+
console.log(`[HTTP Client - Response] Wrapping response in data property`);
|
|
284
|
+
return { data, success: true };
|
|
285
|
+
}
|
|
286
|
+
console.log(`[HTTP Client - Response] Returning text response`);
|
|
287
|
+
return { data, success: true };
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Delay utility for retries
|
|
291
|
+
*/
|
|
292
|
+
delay(ms) {
|
|
293
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// src/cache/noop-adapter.ts
|
|
298
|
+
var NoopCacheAdapter = class {
|
|
299
|
+
async get() {
|
|
300
|
+
return void 0;
|
|
301
|
+
}
|
|
302
|
+
async set() {
|
|
303
|
+
}
|
|
304
|
+
async delete() {
|
|
305
|
+
}
|
|
306
|
+
async deleteMany() {
|
|
307
|
+
}
|
|
308
|
+
async clear() {
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// src/cache/cache-manager.ts
|
|
313
|
+
var TAG_PREFIX = "__tag__";
|
|
314
|
+
var CacheManager = class {
|
|
315
|
+
adapter;
|
|
316
|
+
defaultTtlSeconds;
|
|
317
|
+
keyPrefix;
|
|
318
|
+
enabled;
|
|
319
|
+
constructor(config) {
|
|
320
|
+
const defaultOptions = {
|
|
321
|
+
defaultTtlSeconds: 300,
|
|
322
|
+
keyPrefix: "perspectapi"
|
|
323
|
+
};
|
|
324
|
+
const mergedConfig = {
|
|
325
|
+
...defaultOptions,
|
|
326
|
+
...config
|
|
327
|
+
};
|
|
328
|
+
if (config && config.enabled !== false && config.adapter) {
|
|
329
|
+
this.enabled = true;
|
|
330
|
+
this.adapter = config.adapter;
|
|
331
|
+
} else {
|
|
332
|
+
this.enabled = false;
|
|
333
|
+
this.adapter = new NoopCacheAdapter();
|
|
334
|
+
}
|
|
335
|
+
this.defaultTtlSeconds = mergedConfig.defaultTtlSeconds ?? 300;
|
|
336
|
+
this.keyPrefix = mergedConfig.keyPrefix ?? "perspectapi";
|
|
337
|
+
}
|
|
338
|
+
isEnabled() {
|
|
339
|
+
return this.enabled;
|
|
340
|
+
}
|
|
341
|
+
getKeyPrefix() {
|
|
342
|
+
return this.keyPrefix;
|
|
343
|
+
}
|
|
344
|
+
buildKey(parts) {
|
|
345
|
+
const normalized = parts.flatMap((part) => this.normalizeKeyPart(part)).filter((part) => part !== void 0 && part !== null && part !== "");
|
|
346
|
+
return normalized.join(":");
|
|
347
|
+
}
|
|
348
|
+
async getOrSet(key, resolveValue, policy) {
|
|
349
|
+
if (!this.enabled || policy?.skipCache) {
|
|
350
|
+
console.log("[Cache] Cache disabled or skipped", { key, enabled: this.enabled, skipCache: policy?.skipCache });
|
|
351
|
+
return resolveValue();
|
|
352
|
+
}
|
|
353
|
+
const namespacedKey = this.namespacedKey(key);
|
|
354
|
+
const cachedRaw = await this.adapter.get(namespacedKey);
|
|
355
|
+
if (cachedRaw) {
|
|
356
|
+
const entry = this.deserialize(cachedRaw);
|
|
357
|
+
if (!entry.expiresAt || entry.expiresAt > Date.now()) {
|
|
358
|
+
console.log("[Cache] \u2713 HIT", { key, tags: entry.tags });
|
|
359
|
+
return entry.value;
|
|
360
|
+
}
|
|
361
|
+
console.log("[Cache] \u2717 EXPIRED", { key, expiresAt: new Date(entry.expiresAt) });
|
|
362
|
+
await this.adapter.delete(namespacedKey);
|
|
363
|
+
if (entry.tags?.length) {
|
|
364
|
+
await this.removeKeyFromTags(namespacedKey, entry.tags);
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
console.log("[Cache] \u2717 MISS", { key });
|
|
368
|
+
}
|
|
369
|
+
const value = await resolveValue();
|
|
370
|
+
await this.set(key, value, policy);
|
|
371
|
+
return value;
|
|
372
|
+
}
|
|
373
|
+
async set(key, value, options) {
|
|
374
|
+
if (!this.enabled) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const namespacedKey = this.namespacedKey(key);
|
|
378
|
+
const ttlSeconds = options?.ttlSeconds ?? this.defaultTtlSeconds;
|
|
379
|
+
const entry = {
|
|
380
|
+
value,
|
|
381
|
+
expiresAt: ttlSeconds > 0 ? Date.now() + ttlSeconds * 1e3 : void 0,
|
|
382
|
+
tags: options?.tags,
|
|
383
|
+
metadata: options?.metadata
|
|
384
|
+
};
|
|
385
|
+
console.log("[Cache] SET", { key, ttlSeconds, tags: options?.tags });
|
|
386
|
+
await this.adapter.set(namespacedKey, this.serialize(entry), {
|
|
387
|
+
ttlSeconds: ttlSeconds > 0 ? ttlSeconds : void 0
|
|
388
|
+
});
|
|
389
|
+
if (options?.tags?.length) {
|
|
390
|
+
await this.registerKeyTags(namespacedKey, options.tags);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async delete(key) {
|
|
394
|
+
if (!this.enabled) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const namespacedKey = this.namespacedKey(key);
|
|
398
|
+
await this.adapter.delete(namespacedKey);
|
|
399
|
+
}
|
|
400
|
+
async invalidate(options) {
|
|
401
|
+
if (!this.enabled) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
let totalInvalidated = 0;
|
|
405
|
+
if (options.keys?.length) {
|
|
406
|
+
const namespacedKeys = options.keys.map((key) => this.namespacedKey(key));
|
|
407
|
+
console.log("[Cache] INVALIDATE by keys", { count: options.keys.length, keys: options.keys });
|
|
408
|
+
if (this.adapter.deleteMany) {
|
|
409
|
+
await this.adapter.deleteMany(namespacedKeys);
|
|
410
|
+
} else {
|
|
411
|
+
await Promise.all(namespacedKeys.map((key) => this.adapter.delete(key)));
|
|
412
|
+
}
|
|
413
|
+
totalInvalidated += options.keys.length;
|
|
414
|
+
}
|
|
415
|
+
if (options.tags?.length) {
|
|
416
|
+
console.log("[Cache] INVALIDATE by tags", { tags: options.tags });
|
|
417
|
+
await Promise.all(
|
|
418
|
+
options.tags.map(async (tag) => {
|
|
419
|
+
const tagKey = this.tagKey(tag);
|
|
420
|
+
const payload = await this.adapter.get(tagKey);
|
|
421
|
+
if (!payload) {
|
|
422
|
+
console.log("[Cache] No entries for tag", { tag });
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const keys = this.deserializeTagSet(payload);
|
|
426
|
+
if (keys.length) {
|
|
427
|
+
console.log("[Cache] Invalidating entries for tag", { tag, count: keys.length });
|
|
428
|
+
if (this.adapter.deleteMany) {
|
|
429
|
+
await this.adapter.deleteMany(keys);
|
|
430
|
+
} else {
|
|
431
|
+
await Promise.all(keys.map((key) => this.adapter.delete(key)));
|
|
432
|
+
}
|
|
433
|
+
totalInvalidated += keys.length;
|
|
434
|
+
}
|
|
435
|
+
await this.adapter.delete(tagKey);
|
|
436
|
+
})
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
console.log("[Cache] \u2713 INVALIDATED", { totalEntries: totalInvalidated, keys: options.keys?.length || 0, tags: options.tags?.length || 0 });
|
|
440
|
+
}
|
|
441
|
+
namespacedKey(key) {
|
|
442
|
+
return `${this.keyPrefix}:${key}`;
|
|
443
|
+
}
|
|
444
|
+
tagKey(tag) {
|
|
445
|
+
return this.namespacedKey(`${TAG_PREFIX}:${tag}`);
|
|
446
|
+
}
|
|
447
|
+
serialize(entry) {
|
|
448
|
+
return JSON.stringify(entry);
|
|
449
|
+
}
|
|
450
|
+
deserialize(payload) {
|
|
451
|
+
try {
|
|
452
|
+
return JSON.parse(payload);
|
|
453
|
+
} catch {
|
|
454
|
+
return { value: payload };
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
deserializeTagSet(payload) {
|
|
458
|
+
try {
|
|
459
|
+
const parsed = JSON.parse(payload);
|
|
460
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
461
|
+
} catch {
|
|
462
|
+
return [];
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
async registerKeyTags(namespacedKey, tags) {
|
|
466
|
+
await Promise.all(
|
|
467
|
+
tags.map(async (tag) => {
|
|
468
|
+
const tagKey = this.tagKey(tag);
|
|
469
|
+
const existingPayload = await this.adapter.get(tagKey);
|
|
470
|
+
const keys = existingPayload ? this.deserializeTagSet(existingPayload) : [];
|
|
471
|
+
if (!keys.includes(namespacedKey)) {
|
|
472
|
+
keys.push(namespacedKey);
|
|
473
|
+
await this.adapter.set(tagKey, JSON.stringify(keys));
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
async removeKeyFromTags(namespacedKey, tags) {
|
|
479
|
+
await Promise.all(
|
|
480
|
+
tags.map(async (tag) => {
|
|
481
|
+
const tagKey = this.tagKey(tag);
|
|
482
|
+
const existingPayload = await this.adapter.get(tagKey);
|
|
483
|
+
if (!existingPayload) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const keys = this.deserializeTagSet(existingPayload);
|
|
487
|
+
const updated = keys.filter((key) => key !== namespacedKey);
|
|
488
|
+
if (updated.length === 0) {
|
|
489
|
+
await this.adapter.delete(tagKey);
|
|
490
|
+
} else if (updated.length !== keys.length) {
|
|
491
|
+
await this.adapter.set(tagKey, JSON.stringify(updated));
|
|
492
|
+
}
|
|
493
|
+
})
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
normalizeKeyPart(part) {
|
|
497
|
+
if (part === void 0 || part === null || part === "") {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
if (Array.isArray(part)) {
|
|
501
|
+
return part.flatMap((item) => this.normalizeKeyPart(item));
|
|
502
|
+
}
|
|
503
|
+
if (typeof part === "object") {
|
|
504
|
+
return [this.normalizeObject(part)];
|
|
505
|
+
}
|
|
506
|
+
return [String(part)];
|
|
507
|
+
}
|
|
508
|
+
normalizeObject(input) {
|
|
509
|
+
const sortedKeys = Object.keys(input).sort();
|
|
510
|
+
const normalized = {};
|
|
511
|
+
for (const key of sortedKeys) {
|
|
512
|
+
const value = input[key];
|
|
513
|
+
if (value === void 0) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
517
|
+
normalized[key] = JSON.parse(this.normalizeObject(value));
|
|
518
|
+
} else if (Array.isArray(value)) {
|
|
519
|
+
normalized[key] = value.map(
|
|
520
|
+
(item) => typeof item === "object" && item !== null ? JSON.parse(this.normalizeObject(item)) : item
|
|
521
|
+
);
|
|
522
|
+
} else {
|
|
523
|
+
normalized[key] = value;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
return JSON.stringify(normalized);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
// src/v2/client/base-v2-client.ts
|
|
531
|
+
var PerspectV2Error = class extends Error {
|
|
532
|
+
type;
|
|
533
|
+
code;
|
|
534
|
+
param;
|
|
535
|
+
status;
|
|
536
|
+
constructor(error, status) {
|
|
537
|
+
super(error.message);
|
|
538
|
+
this.name = "PerspectV2Error";
|
|
539
|
+
this.type = error.type;
|
|
540
|
+
this.code = error.code;
|
|
541
|
+
this.param = error.param;
|
|
542
|
+
this.status = status;
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
var BaseV2Client = class {
|
|
546
|
+
http;
|
|
547
|
+
basePath;
|
|
548
|
+
cache;
|
|
549
|
+
constructor(http, basePath, cache) {
|
|
550
|
+
this.http = http;
|
|
551
|
+
this.basePath = basePath;
|
|
552
|
+
this.cache = cache && cache.isEnabled() ? cache : void 0;
|
|
553
|
+
}
|
|
554
|
+
buildPath(endpoint) {
|
|
555
|
+
const clean = endpoint.replace(/^\//, "");
|
|
556
|
+
return clean ? `${this.basePath}/${clean}` : this.basePath;
|
|
557
|
+
}
|
|
558
|
+
sitePath(siteName, resource, suffix = "") {
|
|
559
|
+
const encoded = encodeURIComponent(siteName.trim());
|
|
560
|
+
const cleanSuffix = suffix.replace(/^\//, "");
|
|
561
|
+
const end = cleanSuffix ? `/${cleanSuffix}` : "";
|
|
562
|
+
return `/sites/${encoded}/${resource}${end}`;
|
|
563
|
+
}
|
|
564
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
565
|
+
toParams(params) {
|
|
566
|
+
if (!params) return void 0;
|
|
567
|
+
const out = {};
|
|
568
|
+
for (const [k, v] of Object.entries(params)) {
|
|
569
|
+
if (v !== void 0 && v !== null) out[k] = String(v);
|
|
570
|
+
}
|
|
571
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Extract v2 payload from HttpClient response.
|
|
575
|
+
*
|
|
576
|
+
* The shared HttpClient wraps responses in a v1-style { success, data } envelope.
|
|
577
|
+
* v2 API responses don't have a `success` field — the HttpClient already throws
|
|
578
|
+
* on HTTP errors, so if we reach this point the request succeeded.
|
|
579
|
+
*
|
|
580
|
+
* The HttpClient may return the v2 payload nested under `data` (when the response
|
|
581
|
+
* JSON contains a `data` key, which v2 list responses do) or as a direct wrap.
|
|
582
|
+
* We unwrap accordingly.
|
|
583
|
+
*/
|
|
584
|
+
extractData(response) {
|
|
585
|
+
if ("object" in response && typeof response.object === "string") {
|
|
586
|
+
const payload2 = response;
|
|
587
|
+
if (payload2.error && typeof payload2.error === "object" && "type" in payload2.error) {
|
|
588
|
+
throw this.toError(response);
|
|
589
|
+
}
|
|
590
|
+
return response;
|
|
591
|
+
}
|
|
592
|
+
const payload = response.data;
|
|
593
|
+
if (payload && typeof payload === "object" && "error" in payload) {
|
|
594
|
+
const errObj = payload.error;
|
|
595
|
+
if (errObj && typeof errObj === "object" && "type" in errObj) {
|
|
596
|
+
throw this.toError(response);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return payload;
|
|
600
|
+
}
|
|
601
|
+
/** GET a single resource, with optional caching. */
|
|
602
|
+
async getOne(path, params, cachePolicy) {
|
|
603
|
+
const fetcher = async () => {
|
|
604
|
+
const response = await this.http.get(path, this.toParams(params));
|
|
605
|
+
return this.extractData(response);
|
|
606
|
+
};
|
|
607
|
+
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
608
|
+
}
|
|
609
|
+
/** GET a list of resources with cursor pagination, with optional caching. */
|
|
610
|
+
async getList(path, params, cachePolicy) {
|
|
611
|
+
const fetcher = async () => {
|
|
612
|
+
const response = await this.http.get(path, this.toParams(params));
|
|
613
|
+
return this.extractData(response);
|
|
614
|
+
};
|
|
615
|
+
return this.fetchWithCache(path, params, cachePolicy, fetcher);
|
|
616
|
+
}
|
|
617
|
+
/** POST to create a resource. */
|
|
618
|
+
async post(path, body) {
|
|
619
|
+
const response = await this.http.post(path, body);
|
|
620
|
+
return this.extractData(response);
|
|
621
|
+
}
|
|
622
|
+
/** PATCH to update a resource. */
|
|
623
|
+
async patchOne(path, body) {
|
|
624
|
+
const response = await this.http.patch(path, body);
|
|
625
|
+
return this.extractData(response);
|
|
626
|
+
}
|
|
627
|
+
/** PUT to upsert a resource. */
|
|
628
|
+
async putOne(path, body) {
|
|
629
|
+
const response = await this.http.put(path, body);
|
|
630
|
+
return this.extractData(response);
|
|
631
|
+
}
|
|
632
|
+
/** DELETE a resource. */
|
|
633
|
+
async deleteOne(path) {
|
|
634
|
+
const response = await this.http.delete(path);
|
|
635
|
+
return this.extractData(response);
|
|
636
|
+
}
|
|
637
|
+
/** Fetch with optional cache. Bypasses cache for writes or when no cache is configured. */
|
|
638
|
+
async fetchWithCache(path, params, policy, fetcher) {
|
|
639
|
+
const hasBearerAuth = typeof this.http.hasBearerAuth === "function" && this.http.hasBearerAuth();
|
|
640
|
+
if (!this.cache || policy?.skipCache || hasBearerAuth) {
|
|
641
|
+
return fetcher();
|
|
642
|
+
}
|
|
643
|
+
const key = this.buildCacheKey(path, params);
|
|
644
|
+
return this.cache.getOrSet(key, fetcher, policy);
|
|
645
|
+
}
|
|
646
|
+
/** Invalidate cache entries by keys or tags. */
|
|
647
|
+
async invalidateCache(options) {
|
|
648
|
+
if (!this.cache) return;
|
|
649
|
+
await this.cache.invalidate(options);
|
|
650
|
+
}
|
|
651
|
+
buildCacheKey(path, params) {
|
|
652
|
+
const parts = [path];
|
|
653
|
+
if (params && Object.keys(params).length > 0) {
|
|
654
|
+
const sorted = {};
|
|
655
|
+
for (const key of Object.keys(params).sort()) {
|
|
656
|
+
sorted[key] = params[key];
|
|
657
|
+
}
|
|
658
|
+
parts.push(sorted);
|
|
659
|
+
}
|
|
660
|
+
if (this.cache) {
|
|
661
|
+
return this.cache.buildKey(parts);
|
|
662
|
+
}
|
|
663
|
+
return parts.map((p) => typeof p === "string" ? p : JSON.stringify(p)).join(":");
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Auto-paginating async generator.
|
|
667
|
+
* Yields every item across all pages.
|
|
668
|
+
*
|
|
669
|
+
* Usage:
|
|
670
|
+
* for await (const item of client.listAutoPaginate(path, params)) { ... }
|
|
671
|
+
*/
|
|
672
|
+
async *listAutoPaginate(path, params) {
|
|
673
|
+
let startingAfter;
|
|
674
|
+
let hasMore = true;
|
|
675
|
+
while (hasMore) {
|
|
676
|
+
const queryParams = { ...params };
|
|
677
|
+
if (startingAfter) queryParams.starting_after = startingAfter;
|
|
678
|
+
const page = await this.getList(path, queryParams);
|
|
679
|
+
for (const item of page.data) {
|
|
680
|
+
yield item;
|
|
681
|
+
}
|
|
682
|
+
hasMore = page.has_more;
|
|
683
|
+
if (page.data.length > 0) {
|
|
684
|
+
startingAfter = page.data[page.data.length - 1].id;
|
|
685
|
+
} else {
|
|
686
|
+
hasMore = false;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
toError(response) {
|
|
691
|
+
const data = response.data;
|
|
692
|
+
const errorObj = data?.error ?? response.error;
|
|
693
|
+
if (errorObj && typeof errorObj === "object" && "type" in errorObj) {
|
|
694
|
+
return new PerspectV2Error(errorObj, 400);
|
|
695
|
+
}
|
|
696
|
+
return new PerspectV2Error(
|
|
697
|
+
{ type: "api_error", code: "unknown", message: response.message ?? "Unknown error" },
|
|
698
|
+
500
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
// src/v2/client/content-client.ts
|
|
704
|
+
var ContentV2Client = class extends BaseV2Client {
|
|
705
|
+
async list(siteName, params, cachePolicy) {
|
|
706
|
+
return this.getList(
|
|
707
|
+
this.sitePath(siteName, "content"),
|
|
708
|
+
params,
|
|
709
|
+
this.withContentTags(siteName, cachePolicy, {
|
|
710
|
+
category: params?.category,
|
|
711
|
+
slugPrefix: params?.slug_prefix,
|
|
712
|
+
type: params?.type
|
|
713
|
+
})
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
async *listAutoPaginated(siteName, params, cachePolicy) {
|
|
717
|
+
let startingAfter;
|
|
718
|
+
let hasMore = true;
|
|
719
|
+
while (hasMore) {
|
|
720
|
+
const queryParams = { ...params ?? {} };
|
|
721
|
+
if (startingAfter) {
|
|
722
|
+
queryParams.starting_after = startingAfter;
|
|
723
|
+
}
|
|
724
|
+
const page = await this.list(siteName, queryParams, cachePolicy);
|
|
725
|
+
for (const item of page.data) {
|
|
726
|
+
yield item;
|
|
727
|
+
}
|
|
728
|
+
hasMore = page.has_more;
|
|
729
|
+
if (page.data.length > 0) {
|
|
730
|
+
startingAfter = page.data[page.data.length - 1].id;
|
|
731
|
+
} else {
|
|
732
|
+
hasMore = false;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async get(siteName, idOrSlug, cachePolicy) {
|
|
737
|
+
const isContentId = this.isContentId(idOrSlug);
|
|
738
|
+
return this.getOne(
|
|
739
|
+
this.sitePath(siteName, "content", idOrSlug),
|
|
740
|
+
void 0,
|
|
741
|
+
this.withContentTags(siteName, cachePolicy, {
|
|
742
|
+
id: isContentId ? idOrSlug : void 0,
|
|
743
|
+
slug: isContentId ? void 0 : idOrSlug,
|
|
744
|
+
slugPrefix: isContentId ? void 0 : this.extractSlugPrefix(idOrSlug)
|
|
745
|
+
})
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
async create(siteName, data) {
|
|
749
|
+
return this.post(this.sitePath(siteName, "content"), data);
|
|
750
|
+
}
|
|
751
|
+
async update(siteName, id, data) {
|
|
752
|
+
return this.patchOne(this.sitePath(siteName, "content", id), data);
|
|
753
|
+
}
|
|
754
|
+
async del(siteName, id) {
|
|
755
|
+
return this.deleteOne(this.sitePath(siteName, "content", id));
|
|
756
|
+
}
|
|
757
|
+
async publish(siteName, id) {
|
|
758
|
+
return this.post(this.sitePath(siteName, "content", `${id}/publish`));
|
|
759
|
+
}
|
|
760
|
+
async unpublish(siteName, id) {
|
|
761
|
+
return this.post(this.sitePath(siteName, "content", `${id}/unpublish`));
|
|
762
|
+
}
|
|
763
|
+
withContentTags(siteName, cachePolicy, options) {
|
|
764
|
+
const tags = new Set(cachePolicy?.tags ?? []);
|
|
765
|
+
for (const tag of this.buildContentTags(siteName, options)) {
|
|
766
|
+
tags.add(tag);
|
|
767
|
+
}
|
|
768
|
+
return {
|
|
769
|
+
...cachePolicy,
|
|
770
|
+
tags: Array.from(tags)
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
buildContentTags(siteName, options) {
|
|
774
|
+
const tags = /* @__PURE__ */ new Set(["content", `content:site:${siteName}`]);
|
|
775
|
+
const normalizedPrefix = this.normalizeTagPart(options.slugPrefix);
|
|
776
|
+
const normalizedCategory = this.normalizeTagPart(options.category);
|
|
777
|
+
const normalizedType = this.normalizeTagPart(options.type);
|
|
778
|
+
if (options.slug) {
|
|
779
|
+
tags.add(`content:slug:${siteName}:${options.slug}`);
|
|
780
|
+
}
|
|
781
|
+
if (options.id) {
|
|
782
|
+
tags.add(`content:id:${options.id}`);
|
|
783
|
+
}
|
|
784
|
+
if (normalizedPrefix) {
|
|
785
|
+
tags.add(`content:prefix:${normalizedPrefix}`);
|
|
786
|
+
}
|
|
787
|
+
if (normalizedType) {
|
|
788
|
+
tags.add(`content:${normalizedType}`);
|
|
789
|
+
}
|
|
790
|
+
if (normalizedCategory) {
|
|
791
|
+
tags.add("content:category");
|
|
792
|
+
tags.add(`content:category:${siteName}:${normalizedCategory}`);
|
|
793
|
+
}
|
|
794
|
+
return Array.from(tags);
|
|
795
|
+
}
|
|
796
|
+
normalizeTagPart(value) {
|
|
797
|
+
if (typeof value !== "string") {
|
|
798
|
+
return void 0;
|
|
799
|
+
}
|
|
800
|
+
const normalized = value.trim().toLowerCase();
|
|
801
|
+
return normalized === "" ? void 0 : normalized;
|
|
802
|
+
}
|
|
803
|
+
extractSlugPrefix(slug) {
|
|
804
|
+
const slashIndex = slug.indexOf("/");
|
|
805
|
+
if (slashIndex > 0) {
|
|
806
|
+
return slug.slice(0, slashIndex);
|
|
807
|
+
}
|
|
808
|
+
return void 0;
|
|
809
|
+
}
|
|
810
|
+
isContentId(idOrSlug) {
|
|
811
|
+
return /^cnt_/i.test(idOrSlug);
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
// src/v2/client/products-client.ts
|
|
816
|
+
var ProductsV2Client = class extends BaseV2Client {
|
|
817
|
+
async list(siteName, params, cachePolicy) {
|
|
818
|
+
return this.getList(this.sitePath(siteName, "products"), params, cachePolicy);
|
|
819
|
+
}
|
|
820
|
+
async *listAutoPaginated(siteName, params) {
|
|
821
|
+
yield* this.listAutoPaginate(this.sitePath(siteName, "products"), params);
|
|
822
|
+
}
|
|
823
|
+
async get(siteName, idOrSlug, cachePolicy) {
|
|
824
|
+
return this.getOne(this.sitePath(siteName, "products", idOrSlug), void 0, cachePolicy);
|
|
825
|
+
}
|
|
826
|
+
async create(siteName, data) {
|
|
827
|
+
return this.post(this.sitePath(siteName, "products"), data);
|
|
828
|
+
}
|
|
829
|
+
async update(siteName, id, data) {
|
|
830
|
+
return this.patchOne(this.sitePath(siteName, "products", id), data);
|
|
831
|
+
}
|
|
832
|
+
async del(siteName, id) {
|
|
833
|
+
return this.deleteOne(this.sitePath(siteName, "products", id));
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/v2/client/categories-client.ts
|
|
838
|
+
var CategoriesV2Client = class extends BaseV2Client {
|
|
839
|
+
async list(siteName, params, cachePolicy) {
|
|
840
|
+
return this.getList(this.sitePath(siteName, "categories"), params, cachePolicy);
|
|
841
|
+
}
|
|
842
|
+
async get(siteName, id, cachePolicy) {
|
|
843
|
+
return this.getOne(this.sitePath(siteName, "categories", id), void 0, cachePolicy);
|
|
844
|
+
}
|
|
845
|
+
async create(siteName, data) {
|
|
846
|
+
return this.post(this.sitePath(siteName, "categories"), data);
|
|
847
|
+
}
|
|
848
|
+
async update(siteName, id, data) {
|
|
849
|
+
return this.patchOne(this.sitePath(siteName, "categories", id), data);
|
|
850
|
+
}
|
|
851
|
+
async del(siteName, id) {
|
|
852
|
+
return this.deleteOne(this.sitePath(siteName, "categories", id));
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
// src/v2/client/collections-client.ts
|
|
857
|
+
var CollectionsV2Client = class extends BaseV2Client {
|
|
858
|
+
async list(siteName, params) {
|
|
859
|
+
return this.getList(this.sitePath(siteName, "collections"), params, {
|
|
860
|
+
tags: [`collections:${siteName}`]
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
async *listAutoPaginated(siteName, params) {
|
|
864
|
+
yield* this.listAutoPaginate(this.sitePath(siteName, "collections"), params);
|
|
865
|
+
}
|
|
866
|
+
async getCurrent(siteName) {
|
|
867
|
+
const result = await this.getOne(
|
|
868
|
+
this.sitePath(siteName, "collections", "current")
|
|
869
|
+
);
|
|
870
|
+
return result ?? null;
|
|
871
|
+
}
|
|
872
|
+
async get(siteName, id) {
|
|
873
|
+
return this.getOne(this.sitePath(siteName, "collections", id));
|
|
874
|
+
}
|
|
875
|
+
async create(siteName, data) {
|
|
876
|
+
const result = await this.post(this.sitePath(siteName, "collections"), data);
|
|
877
|
+
await this.invalidateCache({ tags: [`collections:${siteName}`] });
|
|
878
|
+
return result;
|
|
879
|
+
}
|
|
880
|
+
async update(siteName, id, data) {
|
|
881
|
+
const result = await this.patchOne(this.sitePath(siteName, "collections", id), data);
|
|
882
|
+
await this.invalidateCache({
|
|
883
|
+
tags: [`collections:${siteName}`],
|
|
884
|
+
keys: [this.sitePath(siteName, "collections", id)]
|
|
885
|
+
});
|
|
886
|
+
return result;
|
|
887
|
+
}
|
|
888
|
+
async del(siteName, id) {
|
|
889
|
+
const result = await this.deleteOne(this.sitePath(siteName, "collections", id));
|
|
890
|
+
await this.invalidateCache({
|
|
891
|
+
tags: [`collections:${siteName}`],
|
|
892
|
+
keys: [this.sitePath(siteName, "collections", id)]
|
|
893
|
+
});
|
|
894
|
+
return result;
|
|
895
|
+
}
|
|
896
|
+
// --- Items ---
|
|
897
|
+
async listItems(siteName, collectionId) {
|
|
898
|
+
return this.getList(
|
|
899
|
+
this.sitePath(siteName, "collections", `${collectionId}/items`)
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
async addItem(siteName, collectionId, data) {
|
|
903
|
+
const result = await this.post(
|
|
904
|
+
this.sitePath(siteName, "collections", `${collectionId}/items`),
|
|
905
|
+
data
|
|
906
|
+
);
|
|
907
|
+
await this.invalidateCache({
|
|
908
|
+
keys: [this.sitePath(siteName, "collections", `${collectionId}/items`)]
|
|
909
|
+
});
|
|
910
|
+
return result;
|
|
911
|
+
}
|
|
912
|
+
async removeItem(siteName, collectionId, itemId) {
|
|
913
|
+
const result = await this.deleteOne(
|
|
914
|
+
this.sitePath(siteName, "collections", `${collectionId}/items/${itemId}`)
|
|
915
|
+
);
|
|
916
|
+
await this.invalidateCache({
|
|
917
|
+
keys: [this.sitePath(siteName, "collections", `${collectionId}/items`)]
|
|
918
|
+
});
|
|
919
|
+
return result;
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
|
|
923
|
+
// src/v2/client/orders-client.ts
|
|
924
|
+
var OrdersV2Client = class extends BaseV2Client {
|
|
925
|
+
async list(siteName, params, cachePolicy) {
|
|
926
|
+
return this.getList(this.sitePath(siteName, "orders"), params, cachePolicy);
|
|
927
|
+
}
|
|
928
|
+
async *listAutoPaginated(siteName, params) {
|
|
929
|
+
yield* this.listAutoPaginate(this.sitePath(siteName, "orders"), params);
|
|
930
|
+
}
|
|
931
|
+
async get(siteName, id, cachePolicy) {
|
|
932
|
+
return this.getOne(this.sitePath(siteName, "orders", id), void 0, cachePolicy);
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Create a checkout session via Stripe. Returns the session ID and a
|
|
936
|
+
* `checkout_url` that the client should redirect to (or open in a new tab).
|
|
937
|
+
*
|
|
938
|
+
* This replaces the v1 `checkout.createCheckoutSession()` + `getCsrfToken()`
|
|
939
|
+
* dance — v2 is API-key-only and requires no CSRF token.
|
|
940
|
+
*/
|
|
941
|
+
async create(siteName, data) {
|
|
942
|
+
return this.post(
|
|
943
|
+
this.sitePath(siteName, "orders"),
|
|
944
|
+
data
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Update fulfillment status, tracking number, and/or notes on an order.
|
|
949
|
+
*
|
|
950
|
+
* Set `notify_customer: true` when moving the order into a terminal
|
|
951
|
+
* fulfillment state to send the customer fulfillment email.
|
|
952
|
+
*/
|
|
953
|
+
async updateFulfillment(siteName, id, data) {
|
|
954
|
+
return this.patchOne(
|
|
955
|
+
this.sitePath(siteName, "orders", `${id}/fulfillment`),
|
|
956
|
+
data
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
// src/v2/client/site-users-client.ts
|
|
962
|
+
function bypassAuthenticatedCache(policy) {
|
|
963
|
+
return { ...policy, skipCache: true };
|
|
964
|
+
}
|
|
965
|
+
var SiteUsersV2Client = class extends BaseV2Client {
|
|
966
|
+
// --- OTP Auth (public, API-key-scoped) ---
|
|
967
|
+
async requestOtp(siteName, data) {
|
|
968
|
+
return this.post(this.sitePath(siteName, "users", "request-otp"), data);
|
|
969
|
+
}
|
|
970
|
+
async verifyOtp(siteName, data) {
|
|
971
|
+
return this.post(this.sitePath(siteName, "users", "verify-otp"), data);
|
|
972
|
+
}
|
|
973
|
+
// --- Admin (API key) ---
|
|
974
|
+
async list(siteName, params) {
|
|
975
|
+
return this.getList(this.sitePath(siteName, "users"), params);
|
|
976
|
+
}
|
|
977
|
+
async *listAutoPaginated(siteName, params) {
|
|
978
|
+
yield* this.listAutoPaginate(this.sitePath(siteName, "users"), params);
|
|
979
|
+
}
|
|
980
|
+
async get(siteName, id) {
|
|
981
|
+
return this.getOne(this.sitePath(siteName, "users", id));
|
|
982
|
+
}
|
|
983
|
+
async getProfileForUser(siteName, id, cachePolicy) {
|
|
984
|
+
return this.getOne(
|
|
985
|
+
this.sitePath(siteName, "users", `${id}/profile`),
|
|
986
|
+
void 0,
|
|
987
|
+
cachePolicy
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
async update(siteName, id, data) {
|
|
991
|
+
return this.patchOne(this.sitePath(siteName, "users", id), data);
|
|
992
|
+
}
|
|
993
|
+
// --- Authenticated "me" endpoints (site-user JWT) ---
|
|
994
|
+
/**
|
|
995
|
+
* Load the currently-authenticated site user's canonical record plus their
|
|
996
|
+
* profile KV map. Requires `client.setAuth(jwt)` to have been called with
|
|
997
|
+
* the token returned from `verifyOtp`.
|
|
998
|
+
*/
|
|
999
|
+
async getMe(siteName, cachePolicy) {
|
|
1000
|
+
return this.getOne(
|
|
1001
|
+
this.sitePath(siteName, "users", "me"),
|
|
1002
|
+
void 0,
|
|
1003
|
+
bypassAuthenticatedCache(cachePolicy)
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
/** Update the authenticated user's own fields. */
|
|
1007
|
+
async updateMe(siteName, data) {
|
|
1008
|
+
return this.patchOne(
|
|
1009
|
+
this.sitePath(siteName, "users", "me"),
|
|
1010
|
+
data
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
/** Fetch the profile KV map as a dedicated `site_user_profile` envelope. */
|
|
1014
|
+
async getProfile(siteName, cachePolicy) {
|
|
1015
|
+
return this.getOne(
|
|
1016
|
+
this.sitePath(siteName, "users", "me/profile"),
|
|
1017
|
+
void 0,
|
|
1018
|
+
bypassAuthenticatedCache(cachePolicy)
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Set a single profile key. The value is persisted verbatim — callers wanting
|
|
1023
|
+
* structured data should JSON-stringify their value first.
|
|
1024
|
+
*/
|
|
1025
|
+
async setProfileValue(siteName, key, value) {
|
|
1026
|
+
const encoded = encodeURIComponent(key);
|
|
1027
|
+
return this.putOne(
|
|
1028
|
+
this.sitePath(siteName, "users", `me/profile/${encoded}`),
|
|
1029
|
+
{ value }
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
/** Delete a single profile key. */
|
|
1033
|
+
async deleteProfileValue(siteName, key) {
|
|
1034
|
+
const encoded = encodeURIComponent(key);
|
|
1035
|
+
return this.deleteOne(
|
|
1036
|
+
this.sitePath(siteName, "users", `me/profile/${encoded}`)
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
// src/v2/client/newsletter-client.ts
|
|
1042
|
+
var NewsletterV2Client = class extends BaseV2Client {
|
|
1043
|
+
// --- Subscribe / Unsubscribe ---
|
|
1044
|
+
async subscribe(siteName, data) {
|
|
1045
|
+
return this.post(
|
|
1046
|
+
this.sitePath(siteName, "newsletter", "subscribe"),
|
|
1047
|
+
data
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
async confirm(siteName, token) {
|
|
1051
|
+
return this.getOne(
|
|
1052
|
+
this.sitePath(siteName, "newsletter", `confirm/${token}`)
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
async unsubscribe(siteName, data) {
|
|
1056
|
+
return this.post(
|
|
1057
|
+
this.sitePath(siteName, "newsletter", "unsubscribe"),
|
|
1058
|
+
data
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
async trackOpen(siteName, token) {
|
|
1062
|
+
return this.post(
|
|
1063
|
+
this.sitePath(siteName, "newsletter", `track/open/${encodeURIComponent(token)}`)
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
async trackClick(siteName, token, url) {
|
|
1067
|
+
return this.post(
|
|
1068
|
+
this.sitePath(siteName, "newsletter", `track/click/${encodeURIComponent(token)}`),
|
|
1069
|
+
{ url }
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
// --- Subscriptions (admin) ---
|
|
1073
|
+
async listSubscriptions(siteName, params, cachePolicy) {
|
|
1074
|
+
return this.getList(
|
|
1075
|
+
this.sitePath(siteName, "newsletter", "subscriptions"),
|
|
1076
|
+
params,
|
|
1077
|
+
cachePolicy
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
async getSubscription(siteName, id, cachePolicy) {
|
|
1081
|
+
return this.getOne(
|
|
1082
|
+
this.sitePath(siteName, "newsletter", `subscriptions/${id}`),
|
|
1083
|
+
void 0,
|
|
1084
|
+
cachePolicy
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
// --- Lists ---
|
|
1088
|
+
async listLists(siteName, cachePolicy) {
|
|
1089
|
+
return this.getList(
|
|
1090
|
+
this.sitePath(siteName, "newsletter", "lists"),
|
|
1091
|
+
void 0,
|
|
1092
|
+
cachePolicy
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
// --- Campaigns ---
|
|
1096
|
+
async listCampaigns(siteName, params, cachePolicy) {
|
|
1097
|
+
return this.getList(
|
|
1098
|
+
this.sitePath(siteName, "newsletter", "campaigns"),
|
|
1099
|
+
params,
|
|
1100
|
+
cachePolicy
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
async getCampaign(siteName, idOrSlug, cachePolicy) {
|
|
1104
|
+
return this.getOne(
|
|
1105
|
+
this.sitePath(siteName, "newsletter", `campaigns/${idOrSlug}`),
|
|
1106
|
+
void 0,
|
|
1107
|
+
cachePolicy
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
// --- Admin writes: Lists CRUD ---
|
|
1111
|
+
async createList(siteName, data) {
|
|
1112
|
+
return this.post(
|
|
1113
|
+
this.sitePath(siteName, "newsletter", "lists"),
|
|
1114
|
+
data
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
async updateList(siteName, id, data) {
|
|
1118
|
+
return this.patchOne(
|
|
1119
|
+
this.sitePath(siteName, "newsletter", `lists/${id}`),
|
|
1120
|
+
data
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
async deleteList(siteName, id) {
|
|
1124
|
+
return this.deleteOne(
|
|
1125
|
+
this.sitePath(siteName, "newsletter", `lists/${id}`)
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
// --- Admin writes: Subscription sync / membership / import ---
|
|
1129
|
+
/**
|
|
1130
|
+
* Upsert a subscription by email and (optionally) replace its list
|
|
1131
|
+
* memberships. Returns a `newsletter_sync_result` envelope with the
|
|
1132
|
+
* outcome (created / updated / resubscribed / already-unsubscribed).
|
|
1133
|
+
*/
|
|
1134
|
+
async syncSubscription(siteName, data) {
|
|
1135
|
+
return this.post(
|
|
1136
|
+
this.sitePath(siteName, "newsletter", "subscriptions/sync"),
|
|
1137
|
+
data
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Add/remove/replace the list memberships for an existing subscription.
|
|
1142
|
+
* Returns the refreshed subscription record.
|
|
1143
|
+
*/
|
|
1144
|
+
async updateSubscriptionListMembership(siteName, subscriptionId, data) {
|
|
1145
|
+
return this.post(
|
|
1146
|
+
this.sitePath(
|
|
1147
|
+
siteName,
|
|
1148
|
+
"newsletter",
|
|
1149
|
+
`subscriptions/${subscriptionId}/list-membership`
|
|
1150
|
+
),
|
|
1151
|
+
data
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Bulk import subscriptions. Each row is upserted via the same sync
|
|
1156
|
+
* path; `refreshListCounts` is deferred until after all rows are
|
|
1157
|
+
* processed on the server.
|
|
1158
|
+
*/
|
|
1159
|
+
async importSubscriptions(siteName, data) {
|
|
1160
|
+
return this.post(
|
|
1161
|
+
this.sitePath(siteName, "newsletter", "subscriptions/import"),
|
|
1162
|
+
data
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
// src/v2/client/contacts-client.ts
|
|
1168
|
+
var ContactsV2Client = class extends BaseV2Client {
|
|
1169
|
+
async submit(siteName, data) {
|
|
1170
|
+
return this.post(this.sitePath(siteName, "contacts"), data);
|
|
1171
|
+
}
|
|
1172
|
+
async list(siteName, params) {
|
|
1173
|
+
return this.getList(this.sitePath(siteName, "contacts"), params);
|
|
1174
|
+
}
|
|
1175
|
+
async get(siteName, id) {
|
|
1176
|
+
return this.getOne(this.sitePath(siteName, "contacts", id));
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
// src/v2/client/organizations-client.ts
|
|
1181
|
+
var OrganizationsV2Client = class extends BaseV2Client {
|
|
1182
|
+
async list() {
|
|
1183
|
+
return this.getList("/organizations");
|
|
1184
|
+
}
|
|
1185
|
+
async get(id) {
|
|
1186
|
+
return this.getOne(`/organizations/${id}`);
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
// src/v2/client/sites-client.ts
|
|
1191
|
+
var SitesV2Client = class extends BaseV2Client {
|
|
1192
|
+
async list(params) {
|
|
1193
|
+
return this.getList("/sites", params);
|
|
1194
|
+
}
|
|
1195
|
+
async get(name) {
|
|
1196
|
+
return this.getOne(`/sites/${encodeURIComponent(name)}`);
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
|
|
1200
|
+
// src/v2/client/api-keys-client.ts
|
|
1201
|
+
var ApiKeysV2Client = class extends BaseV2Client {
|
|
1202
|
+
async list(params) {
|
|
1203
|
+
return this.getList("/api-keys", params);
|
|
1204
|
+
}
|
|
1205
|
+
async get(id) {
|
|
1206
|
+
return this.getOne(`/api-keys/${id}`);
|
|
1207
|
+
}
|
|
1208
|
+
async del(id) {
|
|
1209
|
+
return this.deleteOne(`/api-keys/${id}`);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
|
|
1213
|
+
// src/v2/client/webhooks-client.ts
|
|
1214
|
+
var WebhooksV2Client = class extends BaseV2Client {
|
|
1215
|
+
async list(siteName, params) {
|
|
1216
|
+
return this.getList(this.sitePath(siteName, "webhooks"), params);
|
|
1217
|
+
}
|
|
1218
|
+
async get(siteName, id) {
|
|
1219
|
+
return this.getOne(this.sitePath(siteName, "webhooks", id));
|
|
1220
|
+
}
|
|
1221
|
+
async create(siteName, data) {
|
|
1222
|
+
return this.post(this.sitePath(siteName, "webhooks"), data);
|
|
1223
|
+
}
|
|
1224
|
+
async update(siteName, id, data) {
|
|
1225
|
+
return this.patchOne(this.sitePath(siteName, "webhooks", id), data);
|
|
1226
|
+
}
|
|
1227
|
+
async del(siteName, id) {
|
|
1228
|
+
return this.deleteOne(this.sitePath(siteName, "webhooks", id));
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
// src/v2/client/subscriptions-client.ts
|
|
1233
|
+
var SubscriptionsV2Client = class extends BaseV2Client {
|
|
1234
|
+
// --- Authenticated "me" endpoints (site-user JWT) ---
|
|
1235
|
+
/** List all subscriptions for the authenticated user. */
|
|
1236
|
+
async listMySubscriptions(siteName, cachePolicy) {
|
|
1237
|
+
return this.getList(
|
|
1238
|
+
this.sitePath(siteName, "users", "me/subscriptions"),
|
|
1239
|
+
void 0,
|
|
1240
|
+
{ ...cachePolicy, skipCache: true }
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
/** Pause a subscription. */
|
|
1244
|
+
async pauseSubscription(siteName, subId, params) {
|
|
1245
|
+
return this.post(
|
|
1246
|
+
this.sitePath(siteName, "users", `me/subscriptions/${subId}/pause`),
|
|
1247
|
+
params ?? {}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
/** Resume a paused subscription. */
|
|
1251
|
+
async resumeSubscription(siteName, subId) {
|
|
1252
|
+
return this.post(
|
|
1253
|
+
this.sitePath(siteName, "users", `me/subscriptions/${subId}/resume`)
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
/** Cancel a subscription. */
|
|
1257
|
+
async cancelSubscription(siteName, subId, params) {
|
|
1258
|
+
return this.post(
|
|
1259
|
+
this.sitePath(siteName, "users", `me/subscriptions/${subId}/cancel`),
|
|
1260
|
+
params ?? {}
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
/** Change the plan (price) of a subscription. */
|
|
1264
|
+
async changeSubscriptionPlan(siteName, subId, params) {
|
|
1265
|
+
return this.post(
|
|
1266
|
+
this.sitePath(siteName, "users", `me/subscriptions/${subId}/change-plan`),
|
|
1267
|
+
params
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
// --- Admin endpoints (API key) ---
|
|
1271
|
+
/** List subscriptions for a specific user (admin). */
|
|
1272
|
+
async listUserSubscriptions(siteName, userId, cachePolicy) {
|
|
1273
|
+
return this.getList(
|
|
1274
|
+
this.sitePath(siteName, "users", `${userId}/subscriptions`),
|
|
1275
|
+
void 0,
|
|
1276
|
+
cachePolicy
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
/** Pause a user's subscription (admin). */
|
|
1280
|
+
async pauseUserSubscription(siteName, userId, subId, params) {
|
|
1281
|
+
return this.post(
|
|
1282
|
+
this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/pause`),
|
|
1283
|
+
params ?? {}
|
|
1284
|
+
);
|
|
1285
|
+
}
|
|
1286
|
+
/** Resume a user's paused subscription (admin). */
|
|
1287
|
+
async resumeUserSubscription(siteName, userId, subId) {
|
|
1288
|
+
return this.post(
|
|
1289
|
+
this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/resume`)
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
/** Cancel a user's subscription (admin). */
|
|
1293
|
+
async cancelUserSubscription(siteName, userId, subId, params) {
|
|
1294
|
+
return this.post(
|
|
1295
|
+
this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/cancel`),
|
|
1296
|
+
params ?? {}
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
/** Charge a user's subscription once (admin). */
|
|
1300
|
+
async chargeUserSubscription(siteName, userId, subId, params) {
|
|
1301
|
+
return this.post(
|
|
1302
|
+
this.sitePath(siteName, "users", `${userId}/subscriptions/${subId}/charges`),
|
|
1303
|
+
params
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
|
|
1308
|
+
// src/v2/client/credits-client.ts
|
|
1309
|
+
var CreditsV2Client = class extends BaseV2Client {
|
|
1310
|
+
// --- Authenticated "me" endpoints (site-user JWT) ---
|
|
1311
|
+
/** Get the current credit balance for the authenticated user. */
|
|
1312
|
+
async getMyBalance(siteName, cachePolicy) {
|
|
1313
|
+
return this.getOne(
|
|
1314
|
+
this.sitePath(siteName, "users", "me/credits/balance"),
|
|
1315
|
+
void 0,
|
|
1316
|
+
{ ...cachePolicy, skipCache: true }
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
/** Get credit balance and transaction history for the authenticated user. */
|
|
1320
|
+
async getMyCredits(siteName, cachePolicy) {
|
|
1321
|
+
return this.getOne(
|
|
1322
|
+
this.sitePath(siteName, "users", "me/credits"),
|
|
1323
|
+
void 0,
|
|
1324
|
+
{ ...cachePolicy, skipCache: true }
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
// --- Admin endpoints (API key) ---
|
|
1328
|
+
/** Get the credit balance for a specific user (admin). */
|
|
1329
|
+
async getUserBalance(siteName, userId) {
|
|
1330
|
+
return this.getOne(
|
|
1331
|
+
this.sitePath(siteName, "users", `${userId}/credits/balance`)
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
/** Grant credit to a specific user (admin). */
|
|
1335
|
+
async grantCredit(siteName, userId, data) {
|
|
1336
|
+
return this.post(
|
|
1337
|
+
this.sitePath(siteName, "users", `${userId}/credits/grant`),
|
|
1338
|
+
data
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
|
|
1343
|
+
// src/v2/index.ts
|
|
1344
|
+
var PerspectApiV2Client = class {
|
|
1345
|
+
http;
|
|
1346
|
+
cache;
|
|
1347
|
+
content;
|
|
1348
|
+
products;
|
|
1349
|
+
categories;
|
|
1350
|
+
collections;
|
|
1351
|
+
orders;
|
|
1352
|
+
siteUsers;
|
|
1353
|
+
newsletter;
|
|
1354
|
+
contacts;
|
|
1355
|
+
organizations;
|
|
1356
|
+
sites;
|
|
1357
|
+
apiKeys;
|
|
1358
|
+
webhooks;
|
|
1359
|
+
subscriptions;
|
|
1360
|
+
credits;
|
|
1361
|
+
constructor(config) {
|
|
1362
|
+
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
1363
|
+
const v2BaseUrl = baseUrl.endsWith("/api/v2") ? baseUrl : `${baseUrl}/api/v2`;
|
|
1364
|
+
this.http = new HttpClient({ ...config, baseUrl: v2BaseUrl });
|
|
1365
|
+
this.cache = new CacheManager(config.cache);
|
|
1366
|
+
const basePath = "";
|
|
1367
|
+
const cache = this.cache;
|
|
1368
|
+
this.content = new ContentV2Client(this.http, basePath, cache);
|
|
1369
|
+
this.products = new ProductsV2Client(this.http, basePath, cache);
|
|
1370
|
+
this.categories = new CategoriesV2Client(this.http, basePath, cache);
|
|
1371
|
+
this.collections = new CollectionsV2Client(this.http, basePath, cache);
|
|
1372
|
+
this.orders = new OrdersV2Client(this.http, basePath, cache);
|
|
1373
|
+
this.siteUsers = new SiteUsersV2Client(this.http, basePath, cache);
|
|
1374
|
+
this.newsletter = new NewsletterV2Client(this.http, basePath, cache);
|
|
1375
|
+
this.contacts = new ContactsV2Client(this.http, basePath, cache);
|
|
1376
|
+
this.organizations = new OrganizationsV2Client(this.http, basePath, cache);
|
|
1377
|
+
this.sites = new SitesV2Client(this.http, basePath, cache);
|
|
1378
|
+
this.apiKeys = new ApiKeysV2Client(this.http, basePath, cache);
|
|
1379
|
+
this.webhooks = new WebhooksV2Client(this.http, basePath, cache);
|
|
1380
|
+
this.subscriptions = new SubscriptionsV2Client(this.http, basePath, cache);
|
|
1381
|
+
this.credits = new CreditsV2Client(this.http, basePath, cache);
|
|
1382
|
+
}
|
|
1383
|
+
/** Update the JWT token for authenticated requests. */
|
|
1384
|
+
setAuth(jwt) {
|
|
1385
|
+
this.http.setAuth(jwt);
|
|
1386
|
+
}
|
|
1387
|
+
/** Update the API key. */
|
|
1388
|
+
setApiKey(apiKey) {
|
|
1389
|
+
this.http.setApiKey(apiKey);
|
|
1390
|
+
}
|
|
1391
|
+
/** Clear authentication. */
|
|
1392
|
+
clearAuth() {
|
|
1393
|
+
this.http.clearAuth();
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
function createPerspectApiV2Client(config) {
|
|
1397
|
+
return new PerspectApiV2Client(config);
|
|
1398
|
+
}
|
|
1399
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1400
|
+
0 && (module.exports = {
|
|
1401
|
+
ApiKeysV2Client,
|
|
1402
|
+
BaseV2Client,
|
|
1403
|
+
CategoriesV2Client,
|
|
1404
|
+
CollectionsV2Client,
|
|
1405
|
+
ContactsV2Client,
|
|
1406
|
+
ContentV2Client,
|
|
1407
|
+
CreditsV2Client,
|
|
1408
|
+
NewsletterV2Client,
|
|
1409
|
+
OrdersV2Client,
|
|
1410
|
+
OrganizationsV2Client,
|
|
1411
|
+
PerspectApiV2Client,
|
|
1412
|
+
PerspectV2Error,
|
|
1413
|
+
ProductsV2Client,
|
|
1414
|
+
SiteUsersV2Client,
|
|
1415
|
+
SitesV2Client,
|
|
1416
|
+
SubscriptionsV2Client,
|
|
1417
|
+
WebhooksV2Client,
|
|
1418
|
+
createPerspectApiV2Client
|
|
1419
|
+
});
|