@01.software/sdk 0.29.0 → 0.30.1
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 +273 -73
- package/dist/analytics/react.cjs +4 -1
- package/dist/analytics/react.cjs.map +1 -1
- package/dist/analytics/react.js +4 -1
- package/dist/analytics/react.js.map +1 -1
- package/dist/analytics.cjs +4 -1
- package/dist/analytics.cjs.map +1 -1
- package/dist/analytics.js +4 -1
- package/dist/analytics.js.map +1 -1
- package/dist/client.cjs +1476 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +28 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.js +1453 -0
- package/dist/client.js.map +1 -0
- package/dist/collection-client-B9d9kr1d.d.ts +218 -0
- package/dist/collection-client-QPbwimkU.d.cts +218 -0
- package/dist/{const-DAjQYNuM.d.ts → const-B75IFDRi.d.ts} +2 -4
- package/dist/{const-Dsixdi6z.d.cts → const-VZuk2tWc.d.cts} +2 -4
- package/dist/index-B2WbhEgT.d.cts +106 -0
- package/dist/index-B2WbhEgT.d.ts +106 -0
- package/dist/index.cjs +784 -1530
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -115
- package/dist/index.d.ts +11 -115
- package/dist/index.js +784 -1548
- package/dist/index.js.map +1 -1
- package/dist/metadata.cjs +91 -0
- package/dist/metadata.cjs.map +1 -0
- package/dist/metadata.d.cts +58 -0
- package/dist/metadata.d.ts +58 -0
- package/dist/metadata.js +68 -0
- package/dist/metadata.js.map +1 -0
- package/dist/{payload-types-Ci-ZA7aM.d.cts → payload-types-DPjO_IbQ.d.cts} +9 -3
- package/dist/{payload-types-Ci-ZA7aM.d.ts → payload-types-DPjO_IbQ.d.ts} +9 -3
- package/dist/query.cjs +1791 -0
- package/dist/query.cjs.map +1 -0
- package/dist/query.d.cts +244 -0
- package/dist/query.d.ts +244 -0
- package/dist/query.js +1786 -0
- package/dist/query.js.map +1 -0
- package/dist/realtime.cjs +4 -1
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js +4 -1
- package/dist/realtime.js.map +1 -1
- package/dist/{server-BINWywT8.d.cts → server-CrsPyqEc.d.cts} +14 -31
- package/dist/{server-BINWywT8.d.ts → server-CrsPyqEc.d.ts} +14 -31
- package/dist/server.cjs +299 -840
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +112 -7
- package/dist/server.d.ts +112 -7
- package/dist/server.js +299 -858
- package/dist/server.js.map +1 -1
- package/dist/{types-BWq_WlbB.d.ts → types-1fBLrYU7.d.ts} +1 -1
- package/dist/{types-zKjATmDK.d.cts → types-BwT0eeaz.d.cts} +1 -1
- package/dist/{server-Cv0Q4dPQ.d.ts → types-Dlb2mwpX.d.cts} +228 -741
- package/dist/{server-C0C8dtms.d.cts → types-DuSKPiY5.d.ts} +228 -741
- package/dist/ui/canvas/server.cjs +7 -6
- package/dist/ui/canvas/server.cjs.map +1 -1
- package/dist/ui/canvas/server.d.cts +1 -3
- package/dist/ui/canvas/server.d.ts +1 -3
- package/dist/ui/canvas/server.js +7 -6
- package/dist/ui/canvas/server.js.map +1 -1
- package/dist/ui/canvas.cjs +11 -10
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.d.cts +29 -6
- package/dist/ui/canvas.d.ts +29 -6
- package/dist/ui/canvas.js +11 -10
- package/dist/ui/canvas.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.d.cts +3 -3
- package/dist/webhook.d.ts +3 -3
- package/package.json +84 -15
package/dist/index.js
CHANGED
|
@@ -1,242 +1,3 @@
|
|
|
1
|
-
// src/utils/types.ts
|
|
2
|
-
var resolveRelation = (ref) => {
|
|
3
|
-
if (typeof ref === "string" || typeof ref === "number" || ref === null || ref === void 0)
|
|
4
|
-
return null;
|
|
5
|
-
return ref;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
// src/core/metadata/index.ts
|
|
9
|
-
function extractSeo(doc) {
|
|
10
|
-
const seo = doc.seo ?? {};
|
|
11
|
-
const og = seo.openGraph ?? {};
|
|
12
|
-
return {
|
|
13
|
-
title: seo.title ?? doc.title ?? null,
|
|
14
|
-
description: seo.description ?? null,
|
|
15
|
-
noIndex: seo.noIndex ?? null,
|
|
16
|
-
canonical: seo.canonical ?? null,
|
|
17
|
-
openGraph: {
|
|
18
|
-
title: og.title ?? null,
|
|
19
|
-
description: og.description ?? null,
|
|
20
|
-
image: og.image ?? null
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function generateMetadata(input, options) {
|
|
25
|
-
const title = input.title ?? void 0;
|
|
26
|
-
const description = input.description ?? void 0;
|
|
27
|
-
const ogTitle = input.openGraph?.title ?? title;
|
|
28
|
-
const ogDescription = input.openGraph?.description ?? description;
|
|
29
|
-
const image = resolveMetaImage(input.openGraph?.image);
|
|
30
|
-
return {
|
|
31
|
-
title,
|
|
32
|
-
description,
|
|
33
|
-
...input.noIndex && { robots: { index: false, follow: false } },
|
|
34
|
-
...input.canonical && { alternates: { canonical: input.canonical } },
|
|
35
|
-
openGraph: {
|
|
36
|
-
...ogTitle && { title: ogTitle },
|
|
37
|
-
...ogDescription && { description: ogDescription },
|
|
38
|
-
...options?.siteName && { siteName: options.siteName },
|
|
39
|
-
...image && { images: [image] }
|
|
40
|
-
},
|
|
41
|
-
twitter: {
|
|
42
|
-
card: image ? "summary_large_image" : "summary",
|
|
43
|
-
...ogTitle && { title: ogTitle },
|
|
44
|
-
...ogDescription && { description: ogDescription },
|
|
45
|
-
...image && { images: [image.url] }
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function resolveMetaImage(ref) {
|
|
50
|
-
const image = resolveRelation(ref);
|
|
51
|
-
if (!image) return null;
|
|
52
|
-
const sized = image.sizes?.["1536"];
|
|
53
|
-
const url = sized?.url || image.url;
|
|
54
|
-
if (!url) return null;
|
|
55
|
-
const width = sized?.url ? sized.width : image.width;
|
|
56
|
-
const height = sized?.url ? sized.height : image.height;
|
|
57
|
-
return {
|
|
58
|
-
url,
|
|
59
|
-
...width && { width },
|
|
60
|
-
...height && { height },
|
|
61
|
-
...image.alt && { alt: image.alt }
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// src/core/collection/query-builder.ts
|
|
66
|
-
var ReadOnlyCollectionQueryBuilder = class {
|
|
67
|
-
constructor(api, collection) {
|
|
68
|
-
this.api = api;
|
|
69
|
-
this.collection = collection;
|
|
70
|
-
}
|
|
71
|
-
async find(options) {
|
|
72
|
-
return this.api.requestFind(
|
|
73
|
-
`/api/${String(this.collection)}`,
|
|
74
|
-
options
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
async findById(id, options) {
|
|
78
|
-
return this.api.requestFindById(
|
|
79
|
-
`/api/${String(this.collection)}/${String(id)}`,
|
|
80
|
-
options
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
async count(options) {
|
|
84
|
-
return this.api.requestCount(
|
|
85
|
-
`/api/${String(this.collection)}/count`,
|
|
86
|
-
options
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
async findMetadata(options, metadataOptions) {
|
|
90
|
-
const { docs } = await this.find({ ...options, limit: 1, depth: 1 });
|
|
91
|
-
const doc = docs[0];
|
|
92
|
-
if (!doc) return null;
|
|
93
|
-
return generateMetadata(
|
|
94
|
-
extractSeo(doc),
|
|
95
|
-
metadataOptions
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
async findMetadataById(id, metadataOptions) {
|
|
99
|
-
const doc = await this.findById(id, { depth: 1 });
|
|
100
|
-
return generateMetadata(
|
|
101
|
-
extractSeo(doc),
|
|
102
|
-
metadataOptions
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
var CollectionQueryBuilder = class {
|
|
107
|
-
constructor(api, collection) {
|
|
108
|
-
this.api = api;
|
|
109
|
-
this.collection = collection;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Find documents (list query)
|
|
113
|
-
* GET /api/{collection}
|
|
114
|
-
* @returns Payload CMS find response with docs array and pagination
|
|
115
|
-
*/
|
|
116
|
-
async find(options) {
|
|
117
|
-
return this.api.requestFind(
|
|
118
|
-
`/api/${String(this.collection)}`,
|
|
119
|
-
options
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Find document by ID
|
|
124
|
-
* GET /api/{collection}/{id}
|
|
125
|
-
* @returns Document object directly (no wrapper)
|
|
126
|
-
*/
|
|
127
|
-
async findById(id, options) {
|
|
128
|
-
return this.api.requestFindById(
|
|
129
|
-
`/api/${String(this.collection)}/${String(id)}`,
|
|
130
|
-
options
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Create a new document
|
|
135
|
-
* POST /api/{collection}
|
|
136
|
-
* @returns Payload CMS mutation response with doc and message
|
|
137
|
-
*/
|
|
138
|
-
async create(data, options) {
|
|
139
|
-
const endpoint = `/api/${String(this.collection)}`;
|
|
140
|
-
if (options?.file) {
|
|
141
|
-
return this.api.requestCreateWithFile(
|
|
142
|
-
endpoint,
|
|
143
|
-
data,
|
|
144
|
-
options.file,
|
|
145
|
-
options.filename
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
return this.api.requestCreate(endpoint, data);
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Update a document by ID
|
|
152
|
-
* PATCH /api/{collection}/{id}
|
|
153
|
-
* @returns Payload CMS mutation response with doc and message
|
|
154
|
-
*/
|
|
155
|
-
async update(id, data, options) {
|
|
156
|
-
const endpoint = `/api/${String(this.collection)}/${String(id)}`;
|
|
157
|
-
if (options?.file) {
|
|
158
|
-
return this.api.requestUpdateWithFile(
|
|
159
|
-
endpoint,
|
|
160
|
-
data,
|
|
161
|
-
options.file,
|
|
162
|
-
options.filename
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
return this.api.requestUpdate(endpoint, data);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Count documents
|
|
169
|
-
* GET /api/{collection}/count
|
|
170
|
-
* @returns Count response with totalDocs
|
|
171
|
-
*/
|
|
172
|
-
async count(options) {
|
|
173
|
-
return this.api.requestCount(
|
|
174
|
-
`/api/${String(this.collection)}/count`,
|
|
175
|
-
options
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Find first matching document and return its Next.js Metadata.
|
|
180
|
-
* Applies depth: 1 (SEO image populate) and limit: 1 automatically.
|
|
181
|
-
* @returns Metadata or null if no document matches
|
|
182
|
-
*/
|
|
183
|
-
async findMetadata(options, metadataOptions) {
|
|
184
|
-
const { docs } = await this.find({ ...options, limit: 1, depth: 1 });
|
|
185
|
-
const doc = docs[0];
|
|
186
|
-
if (!doc) return null;
|
|
187
|
-
return generateMetadata(
|
|
188
|
-
extractSeo(doc),
|
|
189
|
-
metadataOptions
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Find document by ID and return its Next.js Metadata.
|
|
194
|
-
* Applies depth: 1 (SEO image populate) automatically.
|
|
195
|
-
* @returns Metadata (throws on 404)
|
|
196
|
-
*/
|
|
197
|
-
async findMetadataById(id, metadataOptions) {
|
|
198
|
-
const doc = await this.findById(id, { depth: 1 });
|
|
199
|
-
return generateMetadata(
|
|
200
|
-
extractSeo(doc),
|
|
201
|
-
metadataOptions
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Update multiple documents (bulk update)
|
|
206
|
-
* PATCH /api/{collection}
|
|
207
|
-
* @returns Payload CMS find response with updated docs
|
|
208
|
-
*/
|
|
209
|
-
async updateMany(where, data) {
|
|
210
|
-
return this.api.requestUpdateMany(
|
|
211
|
-
`/api/${String(this.collection)}`,
|
|
212
|
-
{ where, data }
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Delete a document by ID
|
|
217
|
-
* DELETE /api/{collection}/{id}
|
|
218
|
-
* @returns Deleted document object directly (no wrapper)
|
|
219
|
-
*/
|
|
220
|
-
async remove(id) {
|
|
221
|
-
return this.api.requestDelete(
|
|
222
|
-
`/api/${String(this.collection)}/${String(id)}`
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Delete multiple documents (bulk delete)
|
|
227
|
-
* DELETE /api/{collection}
|
|
228
|
-
* @returns Payload CMS find response with deleted docs
|
|
229
|
-
*/
|
|
230
|
-
async removeMany(where) {
|
|
231
|
-
return this.api.requestDeleteMany(
|
|
232
|
-
`/api/${String(this.collection)}`,
|
|
233
|
-
{ where }
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
var ServerCollectionQueryBuilder = class extends CollectionQueryBuilder {
|
|
238
|
-
};
|
|
239
|
-
|
|
240
1
|
// src/core/collection/http-client.ts
|
|
241
2
|
import { stringify } from "qs-esm";
|
|
242
3
|
|
|
@@ -430,7 +191,10 @@ function requirePublishableKeyForSecret(apiName, publishableKey, secretKey) {
|
|
|
430
191
|
}
|
|
431
192
|
|
|
432
193
|
// src/core/client/types.ts
|
|
433
|
-
function resolveApiUrl() {
|
|
194
|
+
function resolveApiUrl(apiUrl) {
|
|
195
|
+
if (apiUrl) {
|
|
196
|
+
return apiUrl.replace(/\/$/, "");
|
|
197
|
+
}
|
|
434
198
|
if (typeof process !== "undefined" && process.env) {
|
|
435
199
|
const envUrl = process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL;
|
|
436
200
|
if (envUrl) {
|
|
@@ -611,6 +375,7 @@ function createHttpStatusError(status, parsed, details, requestId) {
|
|
|
611
375
|
}
|
|
612
376
|
async function httpFetch(url, options) {
|
|
613
377
|
const {
|
|
378
|
+
apiUrl,
|
|
614
379
|
publishableKey,
|
|
615
380
|
secretKey,
|
|
616
381
|
customerToken,
|
|
@@ -620,7 +385,7 @@ async function httpFetch(url, options) {
|
|
|
620
385
|
onUnauthorized,
|
|
621
386
|
...requestInit
|
|
622
387
|
} = options || {};
|
|
623
|
-
const baseUrl = resolveApiUrl();
|
|
388
|
+
const baseUrl = resolveApiUrl(apiUrl);
|
|
624
389
|
const retryConfig = {
|
|
625
390
|
maxRetries: retry?.maxRetries ?? 3,
|
|
626
391
|
retryableStatuses: retry?.retryableStatuses ?? DEFAULT_RETRYABLE_STATUSES,
|
|
@@ -809,7 +574,7 @@ async function httpFetch(url, options) {
|
|
|
809
574
|
|
|
810
575
|
// src/core/collection/http-client.ts
|
|
811
576
|
var HttpClient = class {
|
|
812
|
-
constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId) {
|
|
577
|
+
constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId, apiUrl) {
|
|
813
578
|
this.publishableKey = requirePublishableKeyForSecret(
|
|
814
579
|
"CollectionClient",
|
|
815
580
|
publishableKey,
|
|
@@ -819,9 +584,11 @@ var HttpClient = class {
|
|
|
819
584
|
this.getCustomerToken = getCustomerToken;
|
|
820
585
|
this.onUnauthorized = onUnauthorized;
|
|
821
586
|
this.onRequestId = onRequestId;
|
|
587
|
+
this.apiUrl = apiUrl;
|
|
822
588
|
}
|
|
823
589
|
get defaultOptions() {
|
|
824
590
|
const opts = {
|
|
591
|
+
apiUrl: this.apiUrl,
|
|
825
592
|
publishableKey: this.publishableKey,
|
|
826
593
|
secretKey: this.secretKey
|
|
827
594
|
};
|
|
@@ -939,159 +706,113 @@ var HttpClient = class {
|
|
|
939
706
|
}
|
|
940
707
|
};
|
|
941
708
|
|
|
942
|
-
// src/
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
709
|
+
// src/utils/types.ts
|
|
710
|
+
var resolveRelation = (ref) => {
|
|
711
|
+
if (typeof ref === "string" || typeof ref === "number" || ref === null || ref === void 0)
|
|
712
|
+
return null;
|
|
713
|
+
return ref;
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
// src/core/metadata/index.ts
|
|
717
|
+
function extractSeo(doc) {
|
|
718
|
+
const seo = doc.seo ?? {};
|
|
719
|
+
const og = seo.openGraph ?? {};
|
|
720
|
+
return {
|
|
721
|
+
title: seo.title ?? doc.title ?? null,
|
|
722
|
+
description: seo.description ?? null,
|
|
723
|
+
noIndex: seo.noIndex ?? null,
|
|
724
|
+
canonical: seo.canonical ?? null,
|
|
725
|
+
openGraph: {
|
|
726
|
+
title: og.title ?? null,
|
|
727
|
+
description: og.description ?? null,
|
|
728
|
+
image: og.image ?? null
|
|
729
|
+
}
|
|
730
|
+
};
|
|
950
731
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
732
|
+
function generateMetadata(input, options) {
|
|
733
|
+
const title = input.title ?? void 0;
|
|
734
|
+
const description = input.description ?? void 0;
|
|
735
|
+
const ogTitle = input.openGraph?.title ?? title;
|
|
736
|
+
const ogDescription = input.openGraph?.description ?? description;
|
|
737
|
+
const image = resolveMetaImage(input.openGraph?.image);
|
|
738
|
+
return {
|
|
739
|
+
title,
|
|
740
|
+
description,
|
|
741
|
+
...input.noIndex && { robots: { index: false, follow: false } },
|
|
742
|
+
...input.canonical && { alternates: { canonical: input.canonical } },
|
|
743
|
+
openGraph: {
|
|
744
|
+
...ogTitle && { title: ogTitle },
|
|
745
|
+
...ogDescription && { description: ogDescription },
|
|
746
|
+
...options?.siteName && { siteName: options.siteName },
|
|
747
|
+
...image && { images: [image] }
|
|
748
|
+
},
|
|
749
|
+
twitter: {
|
|
750
|
+
card: image ? "summary_large_image" : "summary",
|
|
751
|
+
...ogTitle && { title: ogTitle },
|
|
752
|
+
...ogDescription && { description: ogDescription },
|
|
753
|
+
...image && { images: [image.url] }
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function resolveMetaImage(ref) {
|
|
758
|
+
const image = resolveRelation(ref);
|
|
759
|
+
if (!image) return null;
|
|
760
|
+
const sized = image.sizes?.["1536"];
|
|
761
|
+
const url = sized?.url || image.url;
|
|
762
|
+
if (!url) return null;
|
|
763
|
+
const width = sized?.url ? sized.width : image.width;
|
|
764
|
+
const height = sized?.url ? sized.height : image.height;
|
|
765
|
+
return {
|
|
766
|
+
url,
|
|
767
|
+
...width && { width },
|
|
768
|
+
...height && { height },
|
|
769
|
+
...image.alt && { alt: image.alt }
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/core/collection/query-builder.ts
|
|
774
|
+
var ReadOnlyCollectionQueryBuilder = class {
|
|
775
|
+
constructor(api, collection) {
|
|
776
|
+
this.api = api;
|
|
777
|
+
this.collection = collection;
|
|
954
778
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
* GET /api/{collection}
|
|
961
|
-
*/
|
|
962
|
-
async requestFind(endpoint, options) {
|
|
963
|
-
const url = this.buildUrl(endpoint, options);
|
|
964
|
-
const response = await this.fetchWithTracking(url, {
|
|
965
|
-
...this.defaultOptions,
|
|
966
|
-
method: "GET"
|
|
967
|
-
});
|
|
968
|
-
return this.parseFindResponse(response);
|
|
969
|
-
}
|
|
970
|
-
/**
|
|
971
|
-
* Find-like response from a custom endpoint
|
|
972
|
-
* POST /api/...custom-endpoint
|
|
973
|
-
*/
|
|
974
|
-
async requestFindEndpoint(endpoint, data) {
|
|
975
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
976
|
-
...this.defaultOptions,
|
|
977
|
-
method: "POST",
|
|
978
|
-
body: data ? JSON.stringify(data) : void 0
|
|
979
|
-
});
|
|
980
|
-
return this.parseFindResponse(response);
|
|
981
|
-
}
|
|
982
|
-
/**
|
|
983
|
-
* Find document by ID
|
|
984
|
-
* GET /api/{collection}/{id}
|
|
985
|
-
*/
|
|
986
|
-
async requestFindById(endpoint, options) {
|
|
987
|
-
const url = this.buildUrl(endpoint, options);
|
|
988
|
-
const response = await this.fetchWithTracking(url, {
|
|
989
|
-
...this.defaultOptions,
|
|
990
|
-
method: "GET"
|
|
991
|
-
});
|
|
992
|
-
return this.parseDocumentResponse(response);
|
|
993
|
-
}
|
|
994
|
-
/**
|
|
995
|
-
* Create document
|
|
996
|
-
* POST /api/{collection}
|
|
997
|
-
*/
|
|
998
|
-
async requestCreate(endpoint, data) {
|
|
999
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
1000
|
-
...this.defaultOptions,
|
|
1001
|
-
method: "POST",
|
|
1002
|
-
body: data ? JSON.stringify(data) : void 0
|
|
1003
|
-
});
|
|
1004
|
-
return this.parseMutationResponse(response);
|
|
1005
|
-
}
|
|
1006
|
-
/**
|
|
1007
|
-
* Update document
|
|
1008
|
-
* PATCH /api/{collection}/{id}
|
|
1009
|
-
*/
|
|
1010
|
-
async requestUpdate(endpoint, data) {
|
|
1011
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
1012
|
-
...this.defaultOptions,
|
|
1013
|
-
method: "PATCH",
|
|
1014
|
-
body: data ? JSON.stringify(data) : void 0
|
|
1015
|
-
});
|
|
1016
|
-
return this.parseMutationResponse(response);
|
|
1017
|
-
}
|
|
1018
|
-
/**
|
|
1019
|
-
* Count documents
|
|
1020
|
-
* GET /api/{collection}/count
|
|
1021
|
-
*/
|
|
1022
|
-
async requestCount(endpoint, options) {
|
|
1023
|
-
const url = this.buildUrl(endpoint, options);
|
|
1024
|
-
const response = await this.fetchWithTracking(url, {
|
|
1025
|
-
...this.defaultOptions,
|
|
1026
|
-
method: "GET"
|
|
1027
|
-
});
|
|
1028
|
-
return this.parseDocumentResponse(response);
|
|
1029
|
-
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Update multiple documents (bulk update)
|
|
1032
|
-
* PATCH /api/{collection}
|
|
1033
|
-
*/
|
|
1034
|
-
async requestUpdateMany(endpoint, data) {
|
|
1035
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
1036
|
-
...this.defaultOptions,
|
|
1037
|
-
method: "PATCH",
|
|
1038
|
-
body: JSON.stringify(data)
|
|
1039
|
-
});
|
|
1040
|
-
return this.parseFindResponse(response);
|
|
1041
|
-
}
|
|
1042
|
-
/**
|
|
1043
|
-
* Delete document
|
|
1044
|
-
* DELETE /api/{collection}/{id}
|
|
1045
|
-
*/
|
|
1046
|
-
async requestDelete(endpoint) {
|
|
1047
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
1048
|
-
...this.defaultOptions,
|
|
1049
|
-
method: "DELETE"
|
|
1050
|
-
});
|
|
1051
|
-
return this.parseDocumentResponse(response);
|
|
779
|
+
async find(options) {
|
|
780
|
+
return this.api.requestFind(
|
|
781
|
+
`/api/${String(this.collection)}`,
|
|
782
|
+
options
|
|
783
|
+
);
|
|
1052
784
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
1059
|
-
...this.defaultOptions,
|
|
1060
|
-
method: "DELETE",
|
|
1061
|
-
body: JSON.stringify(data)
|
|
1062
|
-
});
|
|
1063
|
-
return this.parseFindResponse(response);
|
|
785
|
+
async findById(id, options) {
|
|
786
|
+
return this.api.requestFindById(
|
|
787
|
+
`/api/${String(this.collection)}/${String(id)}`,
|
|
788
|
+
options
|
|
789
|
+
);
|
|
1064
790
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
const response = await this.fetchWithTracking(endpoint, {
|
|
1071
|
-
...this.defaultOptions,
|
|
1072
|
-
method: "POST",
|
|
1073
|
-
body: buildPayloadFormData(data, file, filename)
|
|
1074
|
-
});
|
|
1075
|
-
return this.parseMutationResponse(response);
|
|
791
|
+
async count(options) {
|
|
792
|
+
return this.api.requestCount(
|
|
793
|
+
`/api/${String(this.collection)}/count`,
|
|
794
|
+
options
|
|
795
|
+
);
|
|
1076
796
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
body: buildPayloadFormData(data, file, filename)
|
|
1086
|
-
});
|
|
1087
|
-
return this.parseMutationResponse(response);
|
|
797
|
+
async findMetadata(options, metadataOptions) {
|
|
798
|
+
const { docs } = await this.find({ ...options, limit: 1, depth: 1 });
|
|
799
|
+
const doc = docs[0];
|
|
800
|
+
if (!doc) return null;
|
|
801
|
+
return generateMetadata(
|
|
802
|
+
extractSeo(doc),
|
|
803
|
+
metadataOptions
|
|
804
|
+
);
|
|
1088
805
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
806
|
+
async findMetadataById(id, metadataOptions) {
|
|
807
|
+
const doc = await this.findById(id, { depth: 1 });
|
|
808
|
+
return generateMetadata(
|
|
809
|
+
extractSeo(doc),
|
|
810
|
+
metadataOptions
|
|
811
|
+
);
|
|
1093
812
|
}
|
|
1094
813
|
};
|
|
814
|
+
|
|
815
|
+
// src/core/collection/collection-client.ts
|
|
1095
816
|
var ReadOnlyCollectionClient = class extends HttpClient {
|
|
1096
817
|
from(collection) {
|
|
1097
818
|
return new ReadOnlyCollectionQueryBuilder(this, collection);
|
|
@@ -1122,126 +843,6 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
1122
843
|
}
|
|
1123
844
|
};
|
|
1124
845
|
|
|
1125
|
-
// src/core/collection/const.ts
|
|
1126
|
-
var INTERNAL_COLLECTIONS = [
|
|
1127
|
-
"users",
|
|
1128
|
-
"payload-kv",
|
|
1129
|
-
"payload-locked-documents",
|
|
1130
|
-
"payload-preferences",
|
|
1131
|
-
"payload-migrations",
|
|
1132
|
-
"payload-folders",
|
|
1133
|
-
"field-configs",
|
|
1134
|
-
"system-media",
|
|
1135
|
-
"track-assets",
|
|
1136
|
-
"audiences",
|
|
1137
|
-
"email-logs",
|
|
1138
|
-
"api-usage",
|
|
1139
|
-
"tenant-analytics-daily",
|
|
1140
|
-
"tenant-web-analytics-config",
|
|
1141
|
-
"analytics-event-schemas",
|
|
1142
|
-
"subscriptions",
|
|
1143
|
-
"billing-history",
|
|
1144
|
-
"inventory-reservations",
|
|
1145
|
-
"order-status-logs",
|
|
1146
|
-
"api-keys",
|
|
1147
|
-
"personal-access-tokens",
|
|
1148
|
-
"tenant-entitlements",
|
|
1149
|
-
"tenant-purge-jobs",
|
|
1150
|
-
"direct-upload-sessions",
|
|
1151
|
-
"webhook-events",
|
|
1152
|
-
"webhook-deliveries",
|
|
1153
|
-
"audit-logs",
|
|
1154
|
-
"plans",
|
|
1155
|
-
"webhooks",
|
|
1156
|
-
"event-registrations"
|
|
1157
|
-
];
|
|
1158
|
-
var COLLECTIONS = [
|
|
1159
|
-
"tenants",
|
|
1160
|
-
"tenant-metadata",
|
|
1161
|
-
"tenant-logos",
|
|
1162
|
-
"products",
|
|
1163
|
-
"product-variants",
|
|
1164
|
-
"product-options",
|
|
1165
|
-
"product-option-values",
|
|
1166
|
-
"product-categories",
|
|
1167
|
-
"product-tags",
|
|
1168
|
-
"product-collections",
|
|
1169
|
-
"brands",
|
|
1170
|
-
"brand-logos",
|
|
1171
|
-
"orders",
|
|
1172
|
-
"order-items",
|
|
1173
|
-
"returns",
|
|
1174
|
-
"return-items",
|
|
1175
|
-
"fulfillments",
|
|
1176
|
-
"fulfillment-items",
|
|
1177
|
-
"transactions",
|
|
1178
|
-
"customers",
|
|
1179
|
-
"customer-profiles",
|
|
1180
|
-
"customer-profile-lists",
|
|
1181
|
-
"customer-addresses",
|
|
1182
|
-
"carts",
|
|
1183
|
-
"cart-items",
|
|
1184
|
-
"discounts",
|
|
1185
|
-
"shipping-policies",
|
|
1186
|
-
"shipping-zones",
|
|
1187
|
-
"documents",
|
|
1188
|
-
"document-categories",
|
|
1189
|
-
"document-types",
|
|
1190
|
-
"articles",
|
|
1191
|
-
"article-authors",
|
|
1192
|
-
"article-categories",
|
|
1193
|
-
"article-tags",
|
|
1194
|
-
"playlists",
|
|
1195
|
-
"playlist-categories",
|
|
1196
|
-
"playlist-tags",
|
|
1197
|
-
"tracks",
|
|
1198
|
-
"track-categories",
|
|
1199
|
-
"track-tags",
|
|
1200
|
-
"galleries",
|
|
1201
|
-
"gallery-categories",
|
|
1202
|
-
"gallery-tags",
|
|
1203
|
-
"gallery-items",
|
|
1204
|
-
"links",
|
|
1205
|
-
"link-categories",
|
|
1206
|
-
"link-tags",
|
|
1207
|
-
"canvases",
|
|
1208
|
-
"canvas-node-types",
|
|
1209
|
-
"canvas-edge-types",
|
|
1210
|
-
"canvas-categories",
|
|
1211
|
-
"canvas-tags",
|
|
1212
|
-
"canvas-nodes",
|
|
1213
|
-
"canvas-edges",
|
|
1214
|
-
"videos",
|
|
1215
|
-
"video-categories",
|
|
1216
|
-
"video-tags",
|
|
1217
|
-
"live-streams",
|
|
1218
|
-
"images",
|
|
1219
|
-
"forms",
|
|
1220
|
-
"form-submissions",
|
|
1221
|
-
// Community
|
|
1222
|
-
"posts",
|
|
1223
|
-
"comments",
|
|
1224
|
-
"reactions",
|
|
1225
|
-
"reaction-types",
|
|
1226
|
-
"bookmarks",
|
|
1227
|
-
"post-categories",
|
|
1228
|
-
// Events
|
|
1229
|
-
"event-calendars",
|
|
1230
|
-
"events",
|
|
1231
|
-
"event-categories",
|
|
1232
|
-
"event-occurrences",
|
|
1233
|
-
"event-tags"
|
|
1234
|
-
];
|
|
1235
|
-
var SERVER_ONLY_COLLECTIONS = [
|
|
1236
|
-
"customer-groups",
|
|
1237
|
-
"reports",
|
|
1238
|
-
"community-bans"
|
|
1239
|
-
];
|
|
1240
|
-
var SERVER_COLLECTIONS = [
|
|
1241
|
-
...COLLECTIONS,
|
|
1242
|
-
...SERVER_ONLY_COLLECTIONS
|
|
1243
|
-
];
|
|
1244
|
-
|
|
1245
846
|
// src/core/api/parse-response.ts
|
|
1246
847
|
async function parseApiResponse(response, endpoint) {
|
|
1247
848
|
let data;
|
|
@@ -1297,6 +898,7 @@ var CommunityClient = class {
|
|
|
1297
898
|
options.secretKey
|
|
1298
899
|
);
|
|
1299
900
|
this.secretKey = options.secretKey;
|
|
901
|
+
this.apiUrl = options.apiUrl;
|
|
1300
902
|
this.customerToken = options.customerToken;
|
|
1301
903
|
this.onUnauthorized = options.onUnauthorized;
|
|
1302
904
|
this.onRequestId = options.onRequestId;
|
|
@@ -1311,6 +913,7 @@ var CommunityClient = class {
|
|
|
1311
913
|
try {
|
|
1312
914
|
const response = await httpFetch(endpoint, {
|
|
1313
915
|
method,
|
|
916
|
+
apiUrl: this.apiUrl,
|
|
1314
917
|
publishableKey: this.publishableKey,
|
|
1315
918
|
secretKey: this.secretKey,
|
|
1316
919
|
customerToken: token ?? void 0,
|
|
@@ -1459,67 +1062,20 @@ var CommunityClient = class {
|
|
|
1459
1062
|
}
|
|
1460
1063
|
};
|
|
1461
1064
|
|
|
1462
|
-
// src/core/
|
|
1463
|
-
var
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
apiName,
|
|
1470
|
-
options.publishableKey,
|
|
1471
|
-
options.secretKey
|
|
1472
|
-
);
|
|
1473
|
-
this.secretKey = options.secretKey;
|
|
1474
|
-
this.onRequestId = options.onRequestId;
|
|
1475
|
-
}
|
|
1476
|
-
async request(endpoint, body, options) {
|
|
1477
|
-
const method = options?.method ?? "POST";
|
|
1478
|
-
try {
|
|
1479
|
-
const response = await httpFetch(endpoint, {
|
|
1480
|
-
method,
|
|
1481
|
-
publishableKey: this.publishableKey,
|
|
1482
|
-
secretKey: this.secretKey,
|
|
1483
|
-
...body !== void 0 && { body: JSON.stringify(body) },
|
|
1484
|
-
...options?.headers && { headers: options.headers }
|
|
1485
|
-
});
|
|
1486
|
-
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1487
|
-
return parseApiResponse(response, endpoint);
|
|
1488
|
-
} catch (err) {
|
|
1489
|
-
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
1490
|
-
this.onRequestId?.(id);
|
|
1491
|
-
throw err;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
};
|
|
1495
|
-
|
|
1496
|
-
// src/core/community/moderation-api.ts
|
|
1497
|
-
var ModerationApi = class extends BaseApi {
|
|
1498
|
-
constructor(options) {
|
|
1499
|
-
super("ModerationApi", options);
|
|
1500
|
-
}
|
|
1501
|
-
banCustomer(params) {
|
|
1502
|
-
return this.request("/api/community-bans/ban", params);
|
|
1503
|
-
}
|
|
1504
|
-
unbanCustomer(params) {
|
|
1505
|
-
return this.request("/api/community-bans/unban", params);
|
|
1506
|
-
}
|
|
1507
|
-
};
|
|
1508
|
-
|
|
1509
|
-
// src/core/customer/customer-auth.ts
|
|
1510
|
-
var DEFAULT_TIMEOUT2 = 15e3;
|
|
1511
|
-
function safeGetItem(key) {
|
|
1512
|
-
try {
|
|
1513
|
-
return localStorage.getItem(key);
|
|
1514
|
-
} catch {
|
|
1515
|
-
return null;
|
|
1065
|
+
// src/core/customer/customer-auth.ts
|
|
1066
|
+
var DEFAULT_TIMEOUT2 = 15e3;
|
|
1067
|
+
function safeGetItem(key) {
|
|
1068
|
+
try {
|
|
1069
|
+
return localStorage.getItem(key);
|
|
1070
|
+
} catch {
|
|
1071
|
+
return null;
|
|
1516
1072
|
}
|
|
1517
1073
|
}
|
|
1518
1074
|
var CustomerAuth = class {
|
|
1519
|
-
constructor(publishableKey, options) {
|
|
1075
|
+
constructor(publishableKey, options, apiUrl) {
|
|
1520
1076
|
this.refreshPromise = null;
|
|
1521
1077
|
this.publishableKey = publishableKey;
|
|
1522
|
-
this.baseUrl = resolveApiUrl();
|
|
1078
|
+
this.baseUrl = resolveApiUrl(apiUrl);
|
|
1523
1079
|
const persist = options?.persist ?? true;
|
|
1524
1080
|
if (persist) {
|
|
1525
1081
|
const key = typeof persist === "string" ? persist : "customer-token";
|
|
@@ -1750,8 +1306,8 @@ var CustomerAuth = class {
|
|
|
1750
1306
|
|
|
1751
1307
|
// src/core/customer/customer-namespace.ts
|
|
1752
1308
|
var CustomerNamespace = class {
|
|
1753
|
-
constructor(publishableKey, options) {
|
|
1754
|
-
this.auth = new CustomerAuth(publishableKey, options);
|
|
1309
|
+
constructor(publishableKey, options, apiUrl) {
|
|
1310
|
+
this.auth = new CustomerAuth(publishableKey, options, apiUrl);
|
|
1755
1311
|
}
|
|
1756
1312
|
};
|
|
1757
1313
|
|
|
@@ -1769,6 +1325,7 @@ var CartApi = class {
|
|
|
1769
1325
|
options.secretKey
|
|
1770
1326
|
);
|
|
1771
1327
|
this.secretKey = options.secretKey;
|
|
1328
|
+
this.apiUrl = options.apiUrl;
|
|
1772
1329
|
this.customerToken = options.customerToken;
|
|
1773
1330
|
this.onUnauthorized = options.onUnauthorized;
|
|
1774
1331
|
this.onRequestId = options.onRequestId;
|
|
@@ -1778,6 +1335,7 @@ var CartApi = class {
|
|
|
1778
1335
|
try {
|
|
1779
1336
|
const response = await httpFetch(endpoint, {
|
|
1780
1337
|
method,
|
|
1338
|
+
apiUrl: this.apiUrl,
|
|
1781
1339
|
publishableKey: this.publishableKey,
|
|
1782
1340
|
secretKey: this.secretKey,
|
|
1783
1341
|
customerToken: token ?? void 0,
|
|
@@ -1828,6 +1386,7 @@ var CommerceClient = class {
|
|
|
1828
1386
|
constructor(options) {
|
|
1829
1387
|
const cartApi = new CartApi({
|
|
1830
1388
|
publishableKey: options.publishableKey,
|
|
1389
|
+
apiUrl: options.apiUrl,
|
|
1831
1390
|
customerToken: options.customerToken,
|
|
1832
1391
|
onUnauthorized: options.onUnauthorized,
|
|
1833
1392
|
onRequestId: options.onRequestId
|
|
@@ -1837,6 +1396,7 @@ var CommerceClient = class {
|
|
|
1837
1396
|
try {
|
|
1838
1397
|
const response = await httpFetch(endpoint, {
|
|
1839
1398
|
method: "POST",
|
|
1399
|
+
apiUrl: options.apiUrl,
|
|
1840
1400
|
publishableKey: options.publishableKey,
|
|
1841
1401
|
customerToken: token ?? void 0,
|
|
1842
1402
|
...token && options.onUnauthorized && { onUnauthorized: options.onUnauthorized },
|
|
@@ -1884,68 +1444,105 @@ var CommerceClient = class {
|
|
|
1884
1444
|
}
|
|
1885
1445
|
};
|
|
1886
1446
|
|
|
1887
|
-
// src/core/
|
|
1888
|
-
var
|
|
1447
|
+
// src/core/client/client.ts
|
|
1448
|
+
var Client = class {
|
|
1889
1449
|
constructor(options) {
|
|
1890
|
-
|
|
1450
|
+
this.lastRequestId = null;
|
|
1451
|
+
const publishableKey = options.publishableKey;
|
|
1452
|
+
if (!publishableKey) {
|
|
1453
|
+
throw createConfigError("publishableKey is required.");
|
|
1454
|
+
}
|
|
1455
|
+
this.config = { ...options, publishableKey };
|
|
1456
|
+
const metadata = {
|
|
1457
|
+
timestamp: Date.now(),
|
|
1458
|
+
userAgent: typeof window !== "undefined" ? window.navigator?.userAgent : "Node.js"
|
|
1459
|
+
};
|
|
1460
|
+
this.state = { metadata };
|
|
1461
|
+
this.customer = new CustomerNamespace(
|
|
1462
|
+
this.config.publishableKey,
|
|
1463
|
+
options.customer,
|
|
1464
|
+
this.config.apiUrl
|
|
1465
|
+
);
|
|
1466
|
+
const onUnauthorized = async () => {
|
|
1467
|
+
try {
|
|
1468
|
+
const result = await this.customer.auth.refreshToken();
|
|
1469
|
+
return result.token ?? null;
|
|
1470
|
+
} catch {
|
|
1471
|
+
return null;
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
const onRequestId = (id) => {
|
|
1475
|
+
this.lastRequestId = id;
|
|
1476
|
+
};
|
|
1477
|
+
this.commerce = new CommerceClient({
|
|
1478
|
+
publishableKey: this.config.publishableKey,
|
|
1479
|
+
apiUrl: this.config.apiUrl,
|
|
1480
|
+
customerToken: () => this.customer.auth.getToken(),
|
|
1481
|
+
onUnauthorized,
|
|
1482
|
+
onRequestId,
|
|
1483
|
+
customerAuth: this.customer.auth
|
|
1484
|
+
});
|
|
1485
|
+
this.community = new CommunityClient({
|
|
1486
|
+
publishableKey: this.config.publishableKey,
|
|
1487
|
+
apiUrl: this.config.apiUrl,
|
|
1488
|
+
customerToken: () => this.customer.auth.getToken(),
|
|
1489
|
+
onUnauthorized,
|
|
1490
|
+
onRequestId
|
|
1491
|
+
});
|
|
1492
|
+
this.collections = new ReadOnlyCollectionClient(
|
|
1493
|
+
this.config.publishableKey,
|
|
1494
|
+
void 0,
|
|
1495
|
+
() => this.customer.auth.getToken(),
|
|
1496
|
+
onUnauthorized,
|
|
1497
|
+
onRequestId,
|
|
1498
|
+
this.config.apiUrl
|
|
1499
|
+
);
|
|
1891
1500
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
* Results reflect available stock at the moment of the call and are not guaranteed
|
|
1895
|
-
* to remain available by the time an order is placed.
|
|
1896
|
-
*/
|
|
1897
|
-
stockCheck(params) {
|
|
1898
|
-
return this.request("/api/products/stock-check", params);
|
|
1501
|
+
getState() {
|
|
1502
|
+
return { ...this.state };
|
|
1899
1503
|
}
|
|
1900
|
-
|
|
1901
|
-
return this.
|
|
1902
|
-
|
|
1903
|
-
|
|
1504
|
+
getConfig() {
|
|
1505
|
+
return { ...this.config };
|
|
1506
|
+
}
|
|
1507
|
+
};
|
|
1508
|
+
function createClient(options) {
|
|
1509
|
+
return new Client(options);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// src/core/api/base-api.ts
|
|
1513
|
+
var BaseApi = class {
|
|
1514
|
+
constructor(apiName, options) {
|
|
1515
|
+
if (!options.secretKey) {
|
|
1516
|
+
throw createConfigError(`secretKey is required for ${apiName}.`);
|
|
1517
|
+
}
|
|
1518
|
+
this.publishableKey = requirePublishableKeyForSecret(
|
|
1519
|
+
apiName,
|
|
1520
|
+
options.publishableKey,
|
|
1521
|
+
options.secretKey
|
|
1904
1522
|
);
|
|
1523
|
+
this.secretKey = options.secretKey;
|
|
1524
|
+
this.apiUrl = options.apiUrl;
|
|
1525
|
+
this.onRequestId = options.onRequestId;
|
|
1905
1526
|
}
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
* Returns `null` on 404 regardless of reason (`not_found` / `not_published` /
|
|
1909
|
-
* `tenant_mismatch` / `feature_disabled`). For the reason behind a null,
|
|
1910
|
-
* inspect `client.lastRequestId` against backend logs.
|
|
1911
|
-
*/
|
|
1912
|
-
async detail(params) {
|
|
1527
|
+
async request(endpoint, body, options) {
|
|
1528
|
+
const method = options?.method ?? "POST";
|
|
1913
1529
|
try {
|
|
1914
|
-
|
|
1530
|
+
const response = await httpFetch(endpoint, {
|
|
1531
|
+
method,
|
|
1532
|
+
apiUrl: this.apiUrl,
|
|
1533
|
+
publishableKey: this.publishableKey,
|
|
1534
|
+
secretKey: this.secretKey,
|
|
1535
|
+
...body !== void 0 && { body: JSON.stringify(body) },
|
|
1536
|
+
...options?.headers && { headers: options.headers }
|
|
1537
|
+
});
|
|
1538
|
+
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1539
|
+
return parseApiResponse(response, endpoint);
|
|
1915
1540
|
} catch (err) {
|
|
1916
|
-
|
|
1541
|
+
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
1542
|
+
this.onRequestId?.(id);
|
|
1917
1543
|
throw err;
|
|
1918
1544
|
}
|
|
1919
1545
|
}
|
|
1920
|
-
/**
|
|
1921
|
-
* Atomically create or update a product together with its options,
|
|
1922
|
-
* option-values, and variants in a single transaction. Mirrors Shopify's
|
|
1923
|
-
* `productSet` shape and is the canonical write path for the MCP
|
|
1924
|
-
* `product-upsert` tool.
|
|
1925
|
-
*/
|
|
1926
|
-
upsert(params) {
|
|
1927
|
-
return this.request("/api/products/upsert", params);
|
|
1928
|
-
}
|
|
1929
|
-
};
|
|
1930
|
-
|
|
1931
|
-
// src/core/api/discount-api.ts
|
|
1932
|
-
var DiscountApi = class extends BaseApi {
|
|
1933
|
-
constructor(options) {
|
|
1934
|
-
super("DiscountApi", options);
|
|
1935
|
-
}
|
|
1936
|
-
validate(params) {
|
|
1937
|
-
return this.request("/api/discounts/validate", params);
|
|
1938
|
-
}
|
|
1939
|
-
};
|
|
1940
|
-
|
|
1941
|
-
// src/core/api/shipping-api.ts
|
|
1942
|
-
var ShippingApi = class extends BaseApi {
|
|
1943
|
-
constructor(options) {
|
|
1944
|
-
super("ShippingApi", options);
|
|
1945
|
-
}
|
|
1946
|
-
calculate(params) {
|
|
1947
|
-
return this.request("/api/shipping-policies/calculate", params);
|
|
1948
|
-
}
|
|
1949
1546
|
};
|
|
1950
1547
|
|
|
1951
1548
|
// src/core/api/order-api.ts
|
|
@@ -1998,770 +1595,307 @@ var OrderApi = class extends BaseApi {
|
|
|
1998
1595
|
}
|
|
1999
1596
|
};
|
|
2000
1597
|
|
|
2001
|
-
// src/core/
|
|
2002
|
-
var
|
|
1598
|
+
// src/core/api/discount-api.ts
|
|
1599
|
+
var DiscountApi = class extends BaseApi {
|
|
2003
1600
|
constructor(options) {
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
);
|
|
2009
|
-
const serverOptions = {
|
|
2010
|
-
publishableKey,
|
|
2011
|
-
secretKey: options.secretKey,
|
|
2012
|
-
onRequestId: options.onRequestId
|
|
2013
|
-
};
|
|
2014
|
-
const productApi = new ProductApi(serverOptions);
|
|
2015
|
-
const cartApi = new CartApi(serverOptions);
|
|
2016
|
-
const discountApi = new DiscountApi(serverOptions);
|
|
2017
|
-
const shippingApi = new ShippingApi(serverOptions);
|
|
2018
|
-
const orderApi = new OrderApi(serverOptions);
|
|
2019
|
-
this.product = {
|
|
2020
|
-
stockCheck: productApi.stockCheck.bind(productApi),
|
|
2021
|
-
listingGroups: productApi.listingGroups.bind(productApi),
|
|
2022
|
-
detail: productApi.detail.bind(productApi),
|
|
2023
|
-
upsert: productApi.upsert.bind(productApi)
|
|
2024
|
-
};
|
|
2025
|
-
this.cart = {
|
|
2026
|
-
get: cartApi.getCart.bind(cartApi),
|
|
2027
|
-
addItem: cartApi.addItem.bind(cartApi),
|
|
2028
|
-
updateItem: cartApi.updateItem.bind(cartApi),
|
|
2029
|
-
removeItem: cartApi.removeItem.bind(cartApi),
|
|
2030
|
-
applyDiscount: cartApi.applyDiscount.bind(cartApi),
|
|
2031
|
-
removeDiscount: cartApi.removeDiscount.bind(cartApi),
|
|
2032
|
-
clear: cartApi.clearCart.bind(cartApi)
|
|
2033
|
-
};
|
|
2034
|
-
this.orders = {
|
|
2035
|
-
checkout: orderApi.checkout.bind(orderApi),
|
|
2036
|
-
create: orderApi.createOrder.bind(orderApi),
|
|
2037
|
-
update: orderApi.updateOrder.bind(orderApi),
|
|
2038
|
-
updateTransaction: orderApi.updateTransaction.bind(orderApi),
|
|
2039
|
-
confirmPayment: orderApi.confirmPayment.bind(orderApi),
|
|
2040
|
-
createFulfillment: orderApi.createFulfillment.bind(orderApi),
|
|
2041
|
-
updateFulfillment: orderApi.updateFulfillment.bind(orderApi),
|
|
2042
|
-
bulkImportFulfillments: orderApi.bulkImportFulfillments.bind(orderApi),
|
|
2043
|
-
createReturn: orderApi.createReturn.bind(orderApi),
|
|
2044
|
-
updateReturn: orderApi.updateReturn.bind(orderApi),
|
|
2045
|
-
returnWithRefund: orderApi.returnWithRefund.bind(orderApi)
|
|
2046
|
-
};
|
|
2047
|
-
this.discounts = {
|
|
2048
|
-
validate: discountApi.validate.bind(discountApi)
|
|
2049
|
-
};
|
|
2050
|
-
this.shipping = {
|
|
2051
|
-
calculate: shippingApi.calculate.bind(shippingApi)
|
|
2052
|
-
};
|
|
1601
|
+
super("DiscountApi", options);
|
|
1602
|
+
}
|
|
1603
|
+
validate(params) {
|
|
1604
|
+
return this.request("/api/discounts/validate", params);
|
|
2053
1605
|
}
|
|
2054
1606
|
};
|
|
2055
1607
|
|
|
2056
|
-
// src/core/
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
defaultShouldDehydrateQuery
|
|
2061
|
-
} from "@tanstack/react-query";
|
|
2062
|
-
function makeQueryClient() {
|
|
2063
|
-
return new QueryClient({
|
|
2064
|
-
defaultOptions: {
|
|
2065
|
-
queries: {
|
|
2066
|
-
// Infinite staleTime: server-fetched data persists until explicitly invalidated.
|
|
2067
|
-
// For browser clients needing fresher data, override per-query:
|
|
2068
|
-
// useQuery({ ..., staleTime: 5 * 60 * 1000 })
|
|
2069
|
-
staleTime: Number.POSITIVE_INFINITY,
|
|
2070
|
-
refetchOnWindowFocus: false
|
|
2071
|
-
},
|
|
2072
|
-
dehydrate: {
|
|
2073
|
-
shouldDehydrateQuery: (query) => defaultShouldDehydrateQuery(query) || query.state.status === "pending",
|
|
2074
|
-
shouldRedactErrors: () => false
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
});
|
|
2078
|
-
}
|
|
2079
|
-
var browserQueryClient;
|
|
2080
|
-
function getQueryClient() {
|
|
2081
|
-
if (isServer) {
|
|
2082
|
-
return makeQueryClient();
|
|
1608
|
+
// src/core/api/shipping-api.ts
|
|
1609
|
+
var ShippingApi = class extends BaseApi {
|
|
1610
|
+
constructor(options) {
|
|
1611
|
+
super("ShippingApi", options);
|
|
2083
1612
|
}
|
|
2084
|
-
|
|
2085
|
-
|
|
1613
|
+
calculate(params) {
|
|
1614
|
+
return this.request("/api/shipping-policies/calculate", params);
|
|
2086
1615
|
}
|
|
2087
|
-
return browserQueryClient;
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
// src/core/query/query-hooks.ts
|
|
2091
|
-
import {
|
|
2092
|
-
useInfiniteQuery as useInfiniteQueryOriginal2,
|
|
2093
|
-
useQuery as useQueryOriginal3,
|
|
2094
|
-
useSuspenseInfiniteQuery as useSuspenseInfiniteQueryOriginal2,
|
|
2095
|
-
useSuspenseQuery as useSuspenseQueryOriginal2
|
|
2096
|
-
} from "@tanstack/react-query";
|
|
2097
|
-
|
|
2098
|
-
// src/core/query/collection-hooks.ts
|
|
2099
|
-
import {
|
|
2100
|
-
useQuery as useQueryOriginal,
|
|
2101
|
-
useSuspenseQuery as useSuspenseQueryOriginal,
|
|
2102
|
-
useInfiniteQuery as useInfiniteQueryOriginal,
|
|
2103
|
-
useSuspenseInfiniteQuery as useSuspenseInfiniteQueryOriginal,
|
|
2104
|
-
useMutation as useMutationOriginal
|
|
2105
|
-
} from "@tanstack/react-query";
|
|
2106
|
-
|
|
2107
|
-
// src/core/query/query-keys.ts
|
|
2108
|
-
function collectionKeys(collection) {
|
|
2109
|
-
return {
|
|
2110
|
-
all: [collection],
|
|
2111
|
-
lists: () => [collection, "list"],
|
|
2112
|
-
list: (options) => [collection, "list", options],
|
|
2113
|
-
details: () => [collection, "detail"],
|
|
2114
|
-
detail: (id, options) => [collection, "detail", id, options],
|
|
2115
|
-
infinites: () => [collection, "infinite"],
|
|
2116
|
-
infinite: (options) => [collection, "infinite", options]
|
|
2117
|
-
};
|
|
2118
|
-
}
|
|
2119
|
-
var customerKeys = {
|
|
2120
|
-
all: ["customer"],
|
|
2121
|
-
me: () => ["customer", "me"]
|
|
2122
|
-
};
|
|
2123
|
-
var productKeys = {
|
|
2124
|
-
listingGroups: (options) => ["products", "listing-groups", "list", options],
|
|
2125
|
-
listingGroupsInfinite: (options) => ["products", "listing-groups", "infinite", options],
|
|
2126
|
-
detail: (params) => ["products", "detail", params],
|
|
2127
|
-
detailAll: () => ["products", "detail"]
|
|
2128
1616
|
};
|
|
2129
1617
|
|
|
2130
|
-
// src/core/
|
|
2131
|
-
var
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
"product-options",
|
|
2135
|
-
"product-option-values",
|
|
2136
|
-
"product-categories",
|
|
2137
|
-
"product-tags",
|
|
2138
|
-
"product-collections",
|
|
2139
|
-
"brands",
|
|
2140
|
-
"brand-logos",
|
|
2141
|
-
"images"
|
|
2142
|
-
]);
|
|
2143
|
-
var DEFAULT_PAGE_SIZE = 20;
|
|
2144
|
-
var CollectionHooks = class {
|
|
2145
|
-
constructor(queryClient, collectionClient) {
|
|
2146
|
-
this.queryClient = queryClient;
|
|
2147
|
-
this.collectionClient = collectionClient;
|
|
2148
|
-
}
|
|
2149
|
-
// ===== useQuery =====
|
|
2150
|
-
useQuery(params, options) {
|
|
2151
|
-
const { collection, options: queryOptions } = params;
|
|
2152
|
-
const { placeholderData, ...restOptions } = options ?? {};
|
|
2153
|
-
return useQueryOriginal({
|
|
2154
|
-
queryKey: collectionKeys(collection).list(queryOptions),
|
|
2155
|
-
queryFn: async () => {
|
|
2156
|
-
return await this.collectionClient.from(collection).find(queryOptions);
|
|
2157
|
-
},
|
|
2158
|
-
...restOptions,
|
|
2159
|
-
// NonFunctionGuard<T> incompatible with generic union types — safe cast
|
|
2160
|
-
...placeholderData !== void 0 && {
|
|
2161
|
-
placeholderData
|
|
2162
|
-
}
|
|
2163
|
-
});
|
|
2164
|
-
}
|
|
2165
|
-
// ===== useSuspenseQuery =====
|
|
2166
|
-
useSuspenseQuery(params, options) {
|
|
2167
|
-
const { collection, options: queryOptions } = params;
|
|
2168
|
-
return useSuspenseQueryOriginal({
|
|
2169
|
-
queryKey: collectionKeys(collection).list(queryOptions),
|
|
2170
|
-
queryFn: async () => {
|
|
2171
|
-
return await this.collectionClient.from(collection).find(queryOptions);
|
|
2172
|
-
},
|
|
2173
|
-
...options
|
|
2174
|
-
});
|
|
1618
|
+
// src/core/api/product-api.ts
|
|
1619
|
+
var ProductApi = class extends BaseApi {
|
|
1620
|
+
constructor(options) {
|
|
1621
|
+
super("ProductApi", options);
|
|
2175
1622
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
return await this.collectionClient.from(collection).findById(id, queryOptions);
|
|
2184
|
-
},
|
|
2185
|
-
...restOptions,
|
|
2186
|
-
// NonFunctionGuard<T> incompatible with generic union types — safe cast
|
|
2187
|
-
...placeholderData !== void 0 && {
|
|
2188
|
-
placeholderData
|
|
2189
|
-
}
|
|
2190
|
-
});
|
|
1623
|
+
/**
|
|
1624
|
+
* Check point-in-time stock availability for one or more product variants.
|
|
1625
|
+
* Results reflect available stock at the moment of the call and are not guaranteed
|
|
1626
|
+
* to remain available by the time an order is placed.
|
|
1627
|
+
*/
|
|
1628
|
+
stockCheck(params) {
|
|
1629
|
+
return this.request("/api/products/stock-check", params);
|
|
2191
1630
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
queryFn: async () => {
|
|
2198
|
-
return await this.collectionClient.from(collection).findById(id, queryOptions);
|
|
2199
|
-
},
|
|
2200
|
-
...options
|
|
2201
|
-
});
|
|
1631
|
+
listingGroups(params) {
|
|
1632
|
+
return this.request(
|
|
1633
|
+
"/api/products/listing-groups",
|
|
1634
|
+
params
|
|
1635
|
+
);
|
|
2202
1636
|
}
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
initialPageParam: 1,
|
|
2217
|
-
getNextPageParam: (lastPage) => {
|
|
2218
|
-
return lastPage.hasNextPage ? lastPage.nextPage : void 0;
|
|
2219
|
-
},
|
|
2220
|
-
...options
|
|
2221
|
-
});
|
|
1637
|
+
/**
|
|
1638
|
+
* Fetch full product detail by slug or id.
|
|
1639
|
+
* Returns `null` on 404 regardless of reason (`not_found` / `not_published` /
|
|
1640
|
+
* `tenant_mismatch` / `feature_disabled`). For the reason behind a null,
|
|
1641
|
+
* inspect `client.lastRequestId` against backend logs.
|
|
1642
|
+
*/
|
|
1643
|
+
async detail(params) {
|
|
1644
|
+
try {
|
|
1645
|
+
return await this.request("/api/products/detail", params);
|
|
1646
|
+
} catch (err) {
|
|
1647
|
+
if (err instanceof NotFoundError) return null;
|
|
1648
|
+
throw err;
|
|
1649
|
+
}
|
|
2222
1650
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
return
|
|
2231
|
-
queryKey: collectionKeys(collection).infinite(queryOptions),
|
|
2232
|
-
queryFn: async ({ pageParam }) => {
|
|
2233
|
-
const response = await this.collectionClient.from(collection).find({ ...queryOptions, page: pageParam, limit: pageSize });
|
|
2234
|
-
return response;
|
|
2235
|
-
},
|
|
2236
|
-
initialPageParam: 1,
|
|
2237
|
-
getNextPageParam: (lastPage) => {
|
|
2238
|
-
return lastPage.hasNextPage ? lastPage.nextPage : void 0;
|
|
2239
|
-
},
|
|
2240
|
-
...options
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
// ===== prefetchQuery =====
|
|
2244
|
-
async prefetchQuery(params, options) {
|
|
2245
|
-
const { collection, options: queryOptions } = params;
|
|
2246
|
-
return this.queryClient.prefetchQuery({
|
|
2247
|
-
queryKey: collectionKeys(collection).list(queryOptions),
|
|
2248
|
-
queryFn: async () => {
|
|
2249
|
-
return await this.collectionClient.from(collection).find(queryOptions);
|
|
2250
|
-
},
|
|
2251
|
-
...options
|
|
2252
|
-
});
|
|
2253
|
-
}
|
|
2254
|
-
// ===== prefetchQueryById =====
|
|
2255
|
-
async prefetchQueryById(params, options) {
|
|
2256
|
-
const { collection, id, options: queryOptions } = params;
|
|
2257
|
-
return this.queryClient.prefetchQuery({
|
|
2258
|
-
queryKey: collectionKeys(collection).detail(id, queryOptions),
|
|
2259
|
-
queryFn: async () => {
|
|
2260
|
-
return await this.collectionClient.from(collection).findById(id, queryOptions);
|
|
2261
|
-
},
|
|
2262
|
-
...options
|
|
2263
|
-
});
|
|
2264
|
-
}
|
|
2265
|
-
// ===== prefetchInfiniteQuery =====
|
|
2266
|
-
async prefetchInfiniteQuery(params, options) {
|
|
2267
|
-
const {
|
|
2268
|
-
collection,
|
|
2269
|
-
options: queryOptions,
|
|
2270
|
-
pageSize = DEFAULT_PAGE_SIZE
|
|
2271
|
-
} = params;
|
|
2272
|
-
return this.queryClient.prefetchInfiniteQuery({
|
|
2273
|
-
queryKey: collectionKeys(collection).infinite(queryOptions),
|
|
2274
|
-
queryFn: async ({ pageParam }) => {
|
|
2275
|
-
const response = await this.collectionClient.from(collection).find({ ...queryOptions, page: pageParam, limit: pageSize });
|
|
2276
|
-
return response;
|
|
2277
|
-
},
|
|
2278
|
-
initialPageParam: 1,
|
|
2279
|
-
getNextPageParam: (lastPage) => {
|
|
2280
|
-
return lastPage.hasNextPage ? lastPage.nextPage : void 0;
|
|
2281
|
-
},
|
|
2282
|
-
pages: options?.pages ?? 1,
|
|
2283
|
-
staleTime: options?.staleTime
|
|
2284
|
-
});
|
|
2285
|
-
}
|
|
2286
|
-
// ===== Mutation Hooks =====
|
|
2287
|
-
useCreate(params, options) {
|
|
2288
|
-
const { collection } = params;
|
|
2289
|
-
return useMutationOriginal({
|
|
2290
|
-
mutationFn: async (variables) => {
|
|
2291
|
-
return await this.collectionClient.from(collection).create(
|
|
2292
|
-
variables.data,
|
|
2293
|
-
variables.file ? { file: variables.file, filename: variables.filename } : void 0
|
|
2294
|
-
);
|
|
2295
|
-
},
|
|
2296
|
-
onSuccess: (data) => {
|
|
2297
|
-
this.queryClient.invalidateQueries({
|
|
2298
|
-
queryKey: collectionKeys(collection).all
|
|
2299
|
-
});
|
|
2300
|
-
if (PRODUCT_DETAIL_INVALIDATING_COLLECTIONS.has(collection)) {
|
|
2301
|
-
this.queryClient.invalidateQueries({ queryKey: ["products", "detail"] });
|
|
2302
|
-
}
|
|
2303
|
-
options?.onSuccess?.(data);
|
|
2304
|
-
},
|
|
2305
|
-
onError: options?.onError,
|
|
2306
|
-
onSettled: options?.onSettled
|
|
2307
|
-
});
|
|
2308
|
-
}
|
|
2309
|
-
useUpdate(params, options) {
|
|
2310
|
-
const { collection } = params;
|
|
2311
|
-
return useMutationOriginal({
|
|
2312
|
-
mutationFn: async (variables) => {
|
|
2313
|
-
return await this.collectionClient.from(collection).update(
|
|
2314
|
-
variables.id,
|
|
2315
|
-
variables.data,
|
|
2316
|
-
variables.file ? { file: variables.file, filename: variables.filename } : void 0
|
|
2317
|
-
);
|
|
2318
|
-
},
|
|
2319
|
-
onSuccess: (data) => {
|
|
2320
|
-
this.queryClient.invalidateQueries({
|
|
2321
|
-
queryKey: collectionKeys(collection).all
|
|
2322
|
-
});
|
|
2323
|
-
if (PRODUCT_DETAIL_INVALIDATING_COLLECTIONS.has(collection)) {
|
|
2324
|
-
this.queryClient.invalidateQueries({ queryKey: ["products", "detail"] });
|
|
2325
|
-
}
|
|
2326
|
-
options?.onSuccess?.(data);
|
|
2327
|
-
},
|
|
2328
|
-
onError: options?.onError,
|
|
2329
|
-
onSettled: options?.onSettled
|
|
2330
|
-
});
|
|
2331
|
-
}
|
|
2332
|
-
useRemove(params, options) {
|
|
2333
|
-
const { collection } = params;
|
|
2334
|
-
return useMutationOriginal({
|
|
2335
|
-
mutationFn: async (id) => {
|
|
2336
|
-
return await this.collectionClient.from(collection).remove(id);
|
|
2337
|
-
},
|
|
2338
|
-
onSuccess: (data) => {
|
|
2339
|
-
this.queryClient.invalidateQueries({
|
|
2340
|
-
queryKey: collectionKeys(collection).all
|
|
2341
|
-
});
|
|
2342
|
-
if (PRODUCT_DETAIL_INVALIDATING_COLLECTIONS.has(collection)) {
|
|
2343
|
-
this.queryClient.invalidateQueries({ queryKey: ["products", "detail"] });
|
|
2344
|
-
}
|
|
2345
|
-
options?.onSuccess?.(data);
|
|
2346
|
-
},
|
|
2347
|
-
onError: options?.onError,
|
|
2348
|
-
onSettled: options?.onSettled
|
|
2349
|
-
});
|
|
1651
|
+
/**
|
|
1652
|
+
* Atomically create or update a product together with its options,
|
|
1653
|
+
* option-values, and variants in a single transaction. Mirrors Shopify's
|
|
1654
|
+
* `productSet` shape and is the canonical write path for the MCP
|
|
1655
|
+
* `product-upsert` tool.
|
|
1656
|
+
*/
|
|
1657
|
+
upsert(params) {
|
|
1658
|
+
return this.request("/api/products/upsert", params);
|
|
2350
1659
|
}
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
// src/core/webhook/index.ts
|
|
1663
|
+
function isValidWebhookEvent(data) {
|
|
1664
|
+
if (typeof data !== "object" || data === null) return false;
|
|
1665
|
+
const obj = data;
|
|
1666
|
+
return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
|
|
1667
|
+
}
|
|
1668
|
+
var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
|
|
1669
|
+
function isRecord(value) {
|
|
1670
|
+
return typeof value === "object" && value !== null;
|
|
1671
|
+
}
|
|
1672
|
+
function hasString(value, key) {
|
|
1673
|
+
return typeof value[key] === "string";
|
|
1674
|
+
}
|
|
1675
|
+
function hasStringOrNumber(value, key) {
|
|
1676
|
+
return typeof value[key] === "string" || typeof value[key] === "number";
|
|
1677
|
+
}
|
|
1678
|
+
function isCustomerPasswordResetWebhookEvent(event) {
|
|
1679
|
+
if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord(event.data)) {
|
|
1680
|
+
return false;
|
|
2355
1681
|
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
1682
|
+
return hasStringOrNumber(event.data, "customerId") && hasString(event.data, "email") && hasString(event.data, "name") && hasString(event.data, "resetPasswordToken") && hasString(event.data, "resetPasswordExpiresAt");
|
|
1683
|
+
}
|
|
1684
|
+
function createCustomerAuthWebhookHandler(handlers) {
|
|
1685
|
+
return async (event) => {
|
|
1686
|
+
if (isCustomerPasswordResetWebhookEvent(event) && handlers.passwordReset) {
|
|
1687
|
+
await handlers.passwordReset(event.data, event);
|
|
1688
|
+
return;
|
|
2361
1689
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
1690
|
+
await handlers.unhandled?.(event);
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
async function verifySignature(payload, secret, signature, timestamp, deliveryId) {
|
|
1694
|
+
const encoder = new TextEncoder();
|
|
1695
|
+
const key = await crypto.subtle.importKey(
|
|
1696
|
+
"raw",
|
|
1697
|
+
encoder.encode(secret),
|
|
1698
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
1699
|
+
false,
|
|
1700
|
+
["verify"]
|
|
1701
|
+
);
|
|
1702
|
+
if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
|
|
1703
|
+
return false;
|
|
2365
1704
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
1705
|
+
const sigBytes = new Uint8Array(
|
|
1706
|
+
(signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
|
|
1707
|
+
);
|
|
1708
|
+
return crypto.subtle.verify(
|
|
1709
|
+
"HMAC",
|
|
1710
|
+
key,
|
|
1711
|
+
sigBytes,
|
|
1712
|
+
encoder.encode(`${timestamp}.${deliveryId}.${payload}`)
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
function timestampIsFresh(timestamp, toleranceSeconds) {
|
|
1716
|
+
if (!/^\d+$/.test(timestamp)) return false;
|
|
1717
|
+
const timestampMs = Number(timestamp);
|
|
1718
|
+
if (!Number.isFinite(timestampMs)) return false;
|
|
1719
|
+
const skewMs = Math.abs(Date.now() - timestampMs);
|
|
1720
|
+
return skewMs <= toleranceSeconds * 1e3;
|
|
1721
|
+
}
|
|
1722
|
+
async function handleWebhook(request, handler, options) {
|
|
1723
|
+
try {
|
|
1724
|
+
const rawBody = await request.text();
|
|
1725
|
+
if (options?.secret) {
|
|
1726
|
+
const signature = request.headers.get("x-webhook-signature") || "";
|
|
1727
|
+
const timestamp = request.headers.get("x-webhook-timestamp") || "";
|
|
1728
|
+
const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
|
|
1729
|
+
const toleranceSeconds = options.toleranceSeconds ?? 300;
|
|
1730
|
+
const valid = Boolean(timestamp && deliveryId) && timestampIsFresh(timestamp, toleranceSeconds) && await verifySignature(
|
|
1731
|
+
rawBody,
|
|
1732
|
+
options.secret,
|
|
1733
|
+
signature,
|
|
1734
|
+
timestamp,
|
|
1735
|
+
deliveryId
|
|
2371
1736
|
);
|
|
1737
|
+
if (!valid) {
|
|
1738
|
+
return new Response(
|
|
1739
|
+
JSON.stringify({ error: "Invalid webhook signature" }),
|
|
1740
|
+
{ status: 401, headers: { "Content-Type": "application/json" } }
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
2372
1743
|
} else {
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
dataOrOptions
|
|
1744
|
+
console.warn(
|
|
1745
|
+
"[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
|
|
2376
1746
|
);
|
|
2377
1747
|
}
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
useQuery as useQueryOriginal2,
|
|
2384
|
-
useMutation as useMutationOriginal2
|
|
2385
|
-
} from "@tanstack/react-query";
|
|
2386
|
-
function createMutation(mutationFn, callbacks, onSuccessExtra) {
|
|
2387
|
-
return useMutationOriginal2({
|
|
2388
|
-
mutationFn,
|
|
2389
|
-
onSuccess: (data) => {
|
|
2390
|
-
onSuccessExtra?.(data);
|
|
2391
|
-
callbacks?.onSuccess?.(data);
|
|
2392
|
-
},
|
|
2393
|
-
onError: callbacks?.onError,
|
|
2394
|
-
onSettled: callbacks?.onSettled
|
|
2395
|
-
});
|
|
2396
|
-
}
|
|
2397
|
-
var CustomerHooks = class {
|
|
2398
|
-
constructor(queryClient, customerAuth) {
|
|
2399
|
-
this.invalidateMe = () => {
|
|
2400
|
-
this.queryClient.invalidateQueries({ queryKey: customerKeys.me() });
|
|
2401
|
-
};
|
|
2402
|
-
this.queryClient = queryClient;
|
|
2403
|
-
this.customerAuth = customerAuth;
|
|
2404
|
-
}
|
|
2405
|
-
ensureCustomerAuth() {
|
|
2406
|
-
if (!this.customerAuth) {
|
|
2407
|
-
throw createConfigError(
|
|
2408
|
-
"Customer hooks require Client. Use createClient() instead of createServerClient()."
|
|
1748
|
+
const body = JSON.parse(rawBody);
|
|
1749
|
+
if (!isValidWebhookEvent(body)) {
|
|
1750
|
+
return new Response(
|
|
1751
|
+
JSON.stringify({ error: "Invalid webhook event format" }),
|
|
1752
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
2409
1753
|
);
|
|
2410
1754
|
}
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
return useQueryOriginal2({
|
|
2416
|
-
queryKey: customerKeys.me(),
|
|
2417
|
-
queryFn: async () => {
|
|
2418
|
-
return await this.ensureCustomerAuth().me();
|
|
2419
|
-
},
|
|
2420
|
-
...options,
|
|
2421
|
-
enabled: (options?.enabled ?? true) && !!this.customerAuth?.isAuthenticated()
|
|
2422
|
-
});
|
|
2423
|
-
}
|
|
2424
|
-
// ===== Mutations =====
|
|
2425
|
-
useCustomerLogin(options) {
|
|
2426
|
-
return createMutation(
|
|
2427
|
-
(data) => this.ensureCustomerAuth().login(data),
|
|
2428
|
-
options,
|
|
2429
|
-
this.invalidateMe
|
|
2430
|
-
);
|
|
2431
|
-
}
|
|
2432
|
-
useCustomerRegister(options) {
|
|
2433
|
-
return createMutation(
|
|
2434
|
-
(data) => this.ensureCustomerAuth().register(data),
|
|
2435
|
-
options
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
useCustomerLogout(options) {
|
|
2439
|
-
return useMutationOriginal2({
|
|
2440
|
-
mutationFn: async () => {
|
|
2441
|
-
this.ensureCustomerAuth().logout();
|
|
2442
|
-
},
|
|
2443
|
-
onSuccess: () => {
|
|
2444
|
-
this.queryClient.removeQueries({ queryKey: customerKeys.all });
|
|
2445
|
-
options?.onSuccess?.();
|
|
2446
|
-
},
|
|
2447
|
-
onError: options?.onError,
|
|
2448
|
-
onSettled: options?.onSettled
|
|
2449
|
-
});
|
|
2450
|
-
}
|
|
2451
|
-
useCustomerForgotPassword(options) {
|
|
2452
|
-
return createMutation(
|
|
2453
|
-
(email) => this.ensureCustomerAuth().forgotPassword(email).then(() => {
|
|
2454
|
-
}),
|
|
2455
|
-
options
|
|
2456
|
-
);
|
|
2457
|
-
}
|
|
2458
|
-
useCustomerResetPassword(options) {
|
|
2459
|
-
return createMutation(
|
|
2460
|
-
(data) => this.ensureCustomerAuth().resetPassword(data.token, data.password).then(() => {
|
|
2461
|
-
}),
|
|
2462
|
-
options
|
|
2463
|
-
);
|
|
2464
|
-
}
|
|
2465
|
-
useCustomerRefreshToken(options) {
|
|
2466
|
-
return createMutation(
|
|
2467
|
-
() => this.ensureCustomerAuth().refreshToken(),
|
|
2468
|
-
options,
|
|
2469
|
-
this.invalidateMe
|
|
2470
|
-
);
|
|
2471
|
-
}
|
|
2472
|
-
useCustomerUpdateProfile(options) {
|
|
2473
|
-
return createMutation(
|
|
2474
|
-
(data) => this.ensureCustomerAuth().updateProfile(data),
|
|
2475
|
-
options,
|
|
2476
|
-
this.invalidateMe
|
|
2477
|
-
);
|
|
2478
|
-
}
|
|
2479
|
-
useCustomerChangePassword(options) {
|
|
2480
|
-
return createMutation(
|
|
2481
|
-
(data) => this.ensureCustomerAuth().changePassword(data.currentPassword, data.newPassword).then(() => {
|
|
2482
|
-
}),
|
|
2483
|
-
options
|
|
2484
|
-
);
|
|
2485
|
-
}
|
|
2486
|
-
// ===== Customer Cache Utilities =====
|
|
2487
|
-
invalidateCustomerQueries() {
|
|
2488
|
-
return this.queryClient.invalidateQueries({ queryKey: customerKeys.all });
|
|
2489
|
-
}
|
|
2490
|
-
getCustomerData() {
|
|
2491
|
-
return this.queryClient.getQueryData(customerKeys.me());
|
|
2492
|
-
}
|
|
2493
|
-
setCustomerData(data) {
|
|
2494
|
-
this.queryClient.setQueryData(customerKeys.me(), data);
|
|
2495
|
-
}
|
|
2496
|
-
};
|
|
2497
|
-
|
|
2498
|
-
// src/core/query/query-hooks.ts
|
|
2499
|
-
var QueryHooks = class extends CollectionHooks {
|
|
2500
|
-
constructor(queryClient, collectionClient, customerAuth, commerceClient) {
|
|
2501
|
-
super(queryClient, collectionClient);
|
|
2502
|
-
// --- Customer hooks delegation ---
|
|
2503
|
-
this.useCustomerMe = (...args) => this._customer.useCustomerMe(...args);
|
|
2504
|
-
this.useCustomerLogin = (...args) => this._customer.useCustomerLogin(...args);
|
|
2505
|
-
this.useCustomerRegister = (...args) => this._customer.useCustomerRegister(...args);
|
|
2506
|
-
this.useCustomerLogout = (...args) => this._customer.useCustomerLogout(...args);
|
|
2507
|
-
this.useCustomerForgotPassword = (...args) => this._customer.useCustomerForgotPassword(...args);
|
|
2508
|
-
this.useCustomerResetPassword = (...args) => this._customer.useCustomerResetPassword(...args);
|
|
2509
|
-
this.useCustomerRefreshToken = (...args) => this._customer.useCustomerRefreshToken(...args);
|
|
2510
|
-
this.useCustomerUpdateProfile = (...args) => this._customer.useCustomerUpdateProfile(...args);
|
|
2511
|
-
this.useCustomerChangePassword = (...args) => this._customer.useCustomerChangePassword(...args);
|
|
2512
|
-
// --- Customer cache delegation ---
|
|
2513
|
-
this.invalidateCustomerQueries = () => this._customer.invalidateCustomerQueries();
|
|
2514
|
-
this.getCustomerData = () => this._customer.getCustomerData();
|
|
2515
|
-
this.setCustomerData = (data) => this._customer.setCustomerData(data);
|
|
2516
|
-
this._customer = new CustomerHooks(queryClient, customerAuth);
|
|
2517
|
-
this._commerce = commerceClient;
|
|
2518
|
-
}
|
|
2519
|
-
useProductListingGroupsQuery(params, options) {
|
|
2520
|
-
const queryOptions = params.options;
|
|
2521
|
-
const { placeholderData, ...restOptions } = options ?? {};
|
|
2522
|
-
return useQueryOriginal3({
|
|
2523
|
-
queryKey: productKeys.listingGroups(queryOptions),
|
|
2524
|
-
queryFn: async () => this.collectionClient.requestFindEndpoint(
|
|
2525
|
-
"/api/products/listing-groups/query",
|
|
2526
|
-
{ options: queryOptions }
|
|
2527
|
-
),
|
|
2528
|
-
...restOptions,
|
|
2529
|
-
...placeholderData !== void 0 && {
|
|
2530
|
-
placeholderData
|
|
2531
|
-
}
|
|
2532
|
-
});
|
|
2533
|
-
}
|
|
2534
|
-
useSuspenseProductListingGroupsQuery(params, options) {
|
|
2535
|
-
const queryOptions = params.options;
|
|
2536
|
-
return useSuspenseQueryOriginal2({
|
|
2537
|
-
queryKey: productKeys.listingGroups(queryOptions),
|
|
2538
|
-
queryFn: async () => this.collectionClient.requestFindEndpoint(
|
|
2539
|
-
"/api/products/listing-groups/query",
|
|
2540
|
-
{ options: queryOptions }
|
|
2541
|
-
),
|
|
2542
|
-
...options
|
|
2543
|
-
});
|
|
2544
|
-
}
|
|
2545
|
-
useInfiniteProductListingGroupsQuery(params, options) {
|
|
2546
|
-
const {
|
|
2547
|
-
options: queryOptions,
|
|
2548
|
-
pageSize = 20
|
|
2549
|
-
} = params;
|
|
2550
|
-
return useInfiniteQueryOriginal2({
|
|
2551
|
-
queryKey: productKeys.listingGroupsInfinite(queryOptions),
|
|
2552
|
-
queryFn: async ({ pageParam }) => this.collectionClient.requestFindEndpoint(
|
|
2553
|
-
"/api/products/listing-groups/query",
|
|
2554
|
-
{
|
|
2555
|
-
options: { ...queryOptions, page: pageParam, limit: pageSize }
|
|
2556
|
-
}
|
|
2557
|
-
),
|
|
2558
|
-
initialPageParam: 1,
|
|
2559
|
-
getNextPageParam: (lastPage) => lastPage.hasNextPage ? lastPage.nextPage : void 0,
|
|
2560
|
-
...options
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
|
-
useSuspenseInfiniteProductListingGroupsQuery(params, options) {
|
|
2564
|
-
const {
|
|
2565
|
-
options: queryOptions,
|
|
2566
|
-
pageSize = 20
|
|
2567
|
-
} = params;
|
|
2568
|
-
return useSuspenseInfiniteQueryOriginal2({
|
|
2569
|
-
queryKey: productKeys.listingGroupsInfinite(queryOptions),
|
|
2570
|
-
queryFn: async ({ pageParam }) => this.collectionClient.requestFindEndpoint(
|
|
2571
|
-
"/api/products/listing-groups/query",
|
|
2572
|
-
{
|
|
2573
|
-
options: { ...queryOptions, page: pageParam, limit: pageSize }
|
|
2574
|
-
}
|
|
2575
|
-
),
|
|
2576
|
-
initialPageParam: 1,
|
|
2577
|
-
getNextPageParam: (lastPage) => lastPage.hasNextPage ? lastPage.nextPage : void 0,
|
|
2578
|
-
...options
|
|
2579
|
-
});
|
|
2580
|
-
}
|
|
2581
|
-
async prefetchProductListingGroupsQuery(params, options) {
|
|
2582
|
-
const queryOptions = params.options;
|
|
2583
|
-
return this.queryClient.prefetchQuery({
|
|
2584
|
-
queryKey: productKeys.listingGroups(queryOptions),
|
|
2585
|
-
queryFn: async () => this.collectionClient.requestFindEndpoint(
|
|
2586
|
-
"/api/products/listing-groups/query",
|
|
2587
|
-
{ options: queryOptions }
|
|
2588
|
-
),
|
|
2589
|
-
...options
|
|
2590
|
-
});
|
|
2591
|
-
}
|
|
2592
|
-
async prefetchInfiniteProductListingGroupsQuery(params, options) {
|
|
2593
|
-
const {
|
|
2594
|
-
options: queryOptions,
|
|
2595
|
-
pageSize = 20
|
|
2596
|
-
} = params;
|
|
2597
|
-
return this.queryClient.prefetchInfiniteQuery({
|
|
2598
|
-
queryKey: productKeys.listingGroupsInfinite(queryOptions),
|
|
2599
|
-
queryFn: async ({ pageParam }) => this.collectionClient.requestFindEndpoint(
|
|
2600
|
-
"/api/products/listing-groups/query",
|
|
2601
|
-
{
|
|
2602
|
-
options: { ...queryOptions, page: pageParam, limit: pageSize }
|
|
2603
|
-
}
|
|
2604
|
-
),
|
|
2605
|
-
initialPageParam: 1,
|
|
2606
|
-
getNextPageParam: (lastPage) => lastPage.hasNextPage ? lastPage.nextPage : void 0,
|
|
2607
|
-
pages: options?.pages ?? 1,
|
|
2608
|
-
staleTime: options?.staleTime
|
|
2609
|
-
});
|
|
2610
|
-
}
|
|
2611
|
-
useProductDetail(params, options) {
|
|
2612
|
-
const discriminator = "slug" in params ? params.slug : params.id;
|
|
2613
|
-
const enabled = options?.enabled !== false && Boolean(discriminator);
|
|
2614
|
-
return useQueryOriginal3({
|
|
2615
|
-
queryKey: productKeys.detail(params),
|
|
2616
|
-
queryFn: () => this._commerce.product.detail(params),
|
|
2617
|
-
enabled
|
|
2618
|
-
});
|
|
2619
|
-
}
|
|
2620
|
-
useProductDetailBySlug(slug, options) {
|
|
2621
|
-
return this.useProductDetail({ slug }, options);
|
|
2622
|
-
}
|
|
2623
|
-
useProductDetailById(id, options) {
|
|
2624
|
-
return this.useProductDetail({ id }, options);
|
|
2625
|
-
}
|
|
2626
|
-
};
|
|
2627
|
-
|
|
2628
|
-
// src/core/client/client.ts
|
|
2629
|
-
var Client = class {
|
|
2630
|
-
constructor(options) {
|
|
2631
|
-
this.lastRequestId = null;
|
|
2632
|
-
const publishableKey = options.publishableKey;
|
|
2633
|
-
if (!publishableKey) {
|
|
2634
|
-
throw createConfigError("publishableKey is required.");
|
|
2635
|
-
}
|
|
2636
|
-
this.config = { ...options, publishableKey };
|
|
2637
|
-
const metadata = {
|
|
2638
|
-
timestamp: Date.now(),
|
|
2639
|
-
userAgent: typeof window !== "undefined" ? window.navigator?.userAgent : "Node.js"
|
|
2640
|
-
};
|
|
2641
|
-
this.state = { metadata };
|
|
2642
|
-
this.queryClient = getQueryClient();
|
|
2643
|
-
this.customer = new CustomerNamespace(
|
|
2644
|
-
this.config.publishableKey,
|
|
2645
|
-
options.customer
|
|
1755
|
+
await handler(body);
|
|
1756
|
+
return new Response(
|
|
1757
|
+
JSON.stringify({ success: true, message: "Webhook processed" }),
|
|
1758
|
+
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
2646
1759
|
);
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
return null;
|
|
2653
|
-
}
|
|
2654
|
-
};
|
|
2655
|
-
const onRequestId = (id) => {
|
|
2656
|
-
this.lastRequestId = id;
|
|
2657
|
-
};
|
|
2658
|
-
this.commerce = new CommerceClient({
|
|
2659
|
-
publishableKey: this.config.publishableKey,
|
|
2660
|
-
customerToken: () => this.customer.auth.getToken(),
|
|
2661
|
-
onUnauthorized,
|
|
2662
|
-
onRequestId,
|
|
2663
|
-
customerAuth: this.customer.auth
|
|
2664
|
-
});
|
|
2665
|
-
this.community = new CommunityClient({
|
|
2666
|
-
publishableKey: this.config.publishableKey,
|
|
2667
|
-
customerToken: () => this.customer.auth.getToken(),
|
|
2668
|
-
onUnauthorized,
|
|
2669
|
-
onRequestId
|
|
1760
|
+
} catch (error) {
|
|
1761
|
+
console.error("Webhook processing error:", error);
|
|
1762
|
+
return new Response(JSON.stringify({ error: "Internal server error" }), {
|
|
1763
|
+
status: 500,
|
|
1764
|
+
headers: { "Content-Type": "application/json" }
|
|
2670
1765
|
});
|
|
2671
|
-
const collectionClient = new CollectionClient(
|
|
2672
|
-
this.config.publishableKey,
|
|
2673
|
-
void 0,
|
|
2674
|
-
() => this.customer.auth.getToken(),
|
|
2675
|
-
onUnauthorized,
|
|
2676
|
-
onRequestId
|
|
2677
|
-
);
|
|
2678
|
-
this.collections = new ReadOnlyCollectionClient(
|
|
2679
|
-
this.config.publishableKey,
|
|
2680
|
-
void 0,
|
|
2681
|
-
() => this.customer.auth.getToken(),
|
|
2682
|
-
onUnauthorized,
|
|
2683
|
-
onRequestId
|
|
2684
|
-
);
|
|
2685
|
-
this.query = new QueryHooks(
|
|
2686
|
-
this.queryClient,
|
|
2687
|
-
collectionClient,
|
|
2688
|
-
this.customer.auth,
|
|
2689
|
-
this.commerce
|
|
2690
|
-
);
|
|
2691
|
-
}
|
|
2692
|
-
getState() {
|
|
2693
|
-
return { ...this.state };
|
|
2694
|
-
}
|
|
2695
|
-
getConfig() {
|
|
2696
|
-
return { ...this.config };
|
|
2697
1766
|
}
|
|
2698
|
-
};
|
|
2699
|
-
function createClient(options) {
|
|
2700
|
-
return new Client(options);
|
|
2701
1767
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
if (typeof window !== "undefined") {
|
|
2708
|
-
throw createConfigError(
|
|
2709
|
-
"ServerClient must not be used in a browser environment. This risks exposing your secretKey in client bundles. Use createClient() for browser code instead."
|
|
2710
|
-
);
|
|
2711
|
-
}
|
|
2712
|
-
if (!options.secretKey) {
|
|
2713
|
-
throw createConfigError("secretKey is required.");
|
|
2714
|
-
}
|
|
2715
|
-
if (!options.publishableKey) {
|
|
2716
|
-
throw createConfigError(
|
|
2717
|
-
"publishableKey is required. It is used for rate limiting and monthly quota enforcement via the X-Publishable-Key header. Get it from Console > Settings > API Keys."
|
|
1768
|
+
function createTypedWebhookHandler(collection, handler) {
|
|
1769
|
+
return async (event) => {
|
|
1770
|
+
if (event.collection !== collection) {
|
|
1771
|
+
throw new Error(
|
|
1772
|
+
`Expected collection "${collection}", got "${event.collection}"`
|
|
2718
1773
|
);
|
|
2719
1774
|
}
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
timestamp: Date.now(),
|
|
2723
|
-
userAgent: "Node.js"
|
|
2724
|
-
};
|
|
2725
|
-
this.state = { metadata };
|
|
2726
|
-
const onRequestId = (id) => {
|
|
2727
|
-
this.lastRequestId = id;
|
|
2728
|
-
};
|
|
2729
|
-
const serverOptions = {
|
|
2730
|
-
publishableKey: this.config.publishableKey,
|
|
2731
|
-
secretKey: this.config.secretKey,
|
|
2732
|
-
onRequestId
|
|
2733
|
-
};
|
|
2734
|
-
this.commerce = new ServerCommerceClient(serverOptions);
|
|
2735
|
-
const communityClient = new CommunityClient(serverOptions);
|
|
2736
|
-
const moderationApi = new ModerationApi(serverOptions);
|
|
2737
|
-
this.community = Object.assign(communityClient, {
|
|
2738
|
-
moderation: {
|
|
2739
|
-
banCustomer: moderationApi.banCustomer.bind(moderationApi),
|
|
2740
|
-
unbanCustomer: moderationApi.unbanCustomer.bind(moderationApi)
|
|
2741
|
-
}
|
|
2742
|
-
});
|
|
2743
|
-
this.collections = new ServerCollectionClient(
|
|
2744
|
-
this.config.publishableKey,
|
|
2745
|
-
this.config.secretKey,
|
|
2746
|
-
void 0,
|
|
2747
|
-
void 0,
|
|
2748
|
-
onRequestId
|
|
2749
|
-
);
|
|
2750
|
-
this.queryClient = getQueryClient();
|
|
2751
|
-
this.query = new QueryHooks(this.queryClient, this.collections, void 0, this.commerce);
|
|
2752
|
-
}
|
|
2753
|
-
getState() {
|
|
2754
|
-
return { ...this.state };
|
|
2755
|
-
}
|
|
2756
|
-
getConfig() {
|
|
2757
|
-
const { secretKey: _, ...safeConfig } = this.config;
|
|
2758
|
-
return safeConfig;
|
|
2759
|
-
}
|
|
2760
|
-
};
|
|
2761
|
-
function createServerClient(options) {
|
|
2762
|
-
return new ServerClient(options);
|
|
1775
|
+
return handler(event);
|
|
1776
|
+
};
|
|
2763
1777
|
}
|
|
2764
1778
|
|
|
1779
|
+
// src/core/collection/const.ts
|
|
1780
|
+
var INTERNAL_COLLECTIONS = [
|
|
1781
|
+
"users",
|
|
1782
|
+
"payload-kv",
|
|
1783
|
+
"payload-locked-documents",
|
|
1784
|
+
"payload-preferences",
|
|
1785
|
+
"payload-migrations",
|
|
1786
|
+
"payload-folders",
|
|
1787
|
+
"field-configs",
|
|
1788
|
+
"system-media",
|
|
1789
|
+
"track-assets",
|
|
1790
|
+
"audiences",
|
|
1791
|
+
"email-logs",
|
|
1792
|
+
"api-usage",
|
|
1793
|
+
"tenant-analytics-daily",
|
|
1794
|
+
"tenant-web-analytics-config",
|
|
1795
|
+
"analytics-event-schemas",
|
|
1796
|
+
"subscriptions",
|
|
1797
|
+
"billing-history",
|
|
1798
|
+
"inventory-reservations",
|
|
1799
|
+
"order-status-logs",
|
|
1800
|
+
"api-keys",
|
|
1801
|
+
"personal-access-tokens",
|
|
1802
|
+
"tenant-entitlements",
|
|
1803
|
+
"tenant-purge-jobs",
|
|
1804
|
+
"direct-upload-sessions",
|
|
1805
|
+
"webhook-events",
|
|
1806
|
+
"webhook-deliveries",
|
|
1807
|
+
"audit-logs",
|
|
1808
|
+
"plans",
|
|
1809
|
+
"webhooks",
|
|
1810
|
+
"event-registrations"
|
|
1811
|
+
];
|
|
1812
|
+
var COLLECTIONS = [
|
|
1813
|
+
"tenants",
|
|
1814
|
+
"tenant-metadata",
|
|
1815
|
+
"tenant-logos",
|
|
1816
|
+
"products",
|
|
1817
|
+
"product-variants",
|
|
1818
|
+
"product-options",
|
|
1819
|
+
"product-option-values",
|
|
1820
|
+
"product-categories",
|
|
1821
|
+
"product-tags",
|
|
1822
|
+
"product-collections",
|
|
1823
|
+
"brands",
|
|
1824
|
+
"brand-logos",
|
|
1825
|
+
"orders",
|
|
1826
|
+
"order-items",
|
|
1827
|
+
"returns",
|
|
1828
|
+
"return-items",
|
|
1829
|
+
"fulfillments",
|
|
1830
|
+
"fulfillment-items",
|
|
1831
|
+
"transactions",
|
|
1832
|
+
"customers",
|
|
1833
|
+
"customer-profiles",
|
|
1834
|
+
"customer-profile-lists",
|
|
1835
|
+
"customer-addresses",
|
|
1836
|
+
"carts",
|
|
1837
|
+
"cart-items",
|
|
1838
|
+
"discounts",
|
|
1839
|
+
"shipping-policies",
|
|
1840
|
+
"shipping-zones",
|
|
1841
|
+
"documents",
|
|
1842
|
+
"document-categories",
|
|
1843
|
+
"document-types",
|
|
1844
|
+
"articles",
|
|
1845
|
+
"article-authors",
|
|
1846
|
+
"article-categories",
|
|
1847
|
+
"article-tags",
|
|
1848
|
+
"playlists",
|
|
1849
|
+
"playlist-categories",
|
|
1850
|
+
"playlist-tags",
|
|
1851
|
+
"tracks",
|
|
1852
|
+
"track-categories",
|
|
1853
|
+
"track-tags",
|
|
1854
|
+
"galleries",
|
|
1855
|
+
"gallery-categories",
|
|
1856
|
+
"gallery-tags",
|
|
1857
|
+
"gallery-items",
|
|
1858
|
+
"links",
|
|
1859
|
+
"link-categories",
|
|
1860
|
+
"link-tags",
|
|
1861
|
+
"canvases",
|
|
1862
|
+
"canvas-node-types",
|
|
1863
|
+
"canvas-edge-types",
|
|
1864
|
+
"canvas-categories",
|
|
1865
|
+
"canvas-tags",
|
|
1866
|
+
"canvas-nodes",
|
|
1867
|
+
"canvas-edges",
|
|
1868
|
+
"videos",
|
|
1869
|
+
"video-categories",
|
|
1870
|
+
"video-tags",
|
|
1871
|
+
"live-streams",
|
|
1872
|
+
"images",
|
|
1873
|
+
"forms",
|
|
1874
|
+
"form-submissions",
|
|
1875
|
+
// Community
|
|
1876
|
+
"posts",
|
|
1877
|
+
"comments",
|
|
1878
|
+
"reactions",
|
|
1879
|
+
"reaction-types",
|
|
1880
|
+
"bookmarks",
|
|
1881
|
+
"post-categories",
|
|
1882
|
+
// Events
|
|
1883
|
+
"event-calendars",
|
|
1884
|
+
"events",
|
|
1885
|
+
"event-categories",
|
|
1886
|
+
"event-occurrences",
|
|
1887
|
+
"event-tags"
|
|
1888
|
+
];
|
|
1889
|
+
var SERVER_ONLY_COLLECTIONS = [
|
|
1890
|
+
"customer-groups",
|
|
1891
|
+
"reports",
|
|
1892
|
+
"community-bans"
|
|
1893
|
+
];
|
|
1894
|
+
var SERVER_COLLECTIONS = [
|
|
1895
|
+
...COLLECTIONS,
|
|
1896
|
+
...SERVER_ONLY_COLLECTIONS
|
|
1897
|
+
];
|
|
1898
|
+
|
|
2765
1899
|
// src/core/query/realtime.ts
|
|
2766
1900
|
var INITIAL_RECONNECT_DELAY = 1e3;
|
|
2767
1901
|
var MAX_RECONNECT_DELAY = 3e4;
|
|
@@ -2907,123 +2041,6 @@ var RealtimeConnection = class {
|
|
|
2907
2041
|
}
|
|
2908
2042
|
};
|
|
2909
2043
|
|
|
2910
|
-
// src/core/webhook/index.ts
|
|
2911
|
-
function isValidWebhookEvent(data) {
|
|
2912
|
-
if (typeof data !== "object" || data === null) return false;
|
|
2913
|
-
const obj = data;
|
|
2914
|
-
return typeof obj.collection === "string" && typeof obj.operation === "string" && obj.operation.length > 0 && typeof obj.data === "object" && obj.data !== null;
|
|
2915
|
-
}
|
|
2916
|
-
var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
|
|
2917
|
-
function isRecord(value) {
|
|
2918
|
-
return typeof value === "object" && value !== null;
|
|
2919
|
-
}
|
|
2920
|
-
function hasString(value, key) {
|
|
2921
|
-
return typeof value[key] === "string";
|
|
2922
|
-
}
|
|
2923
|
-
function hasStringOrNumber(value, key) {
|
|
2924
|
-
return typeof value[key] === "string" || typeof value[key] === "number";
|
|
2925
|
-
}
|
|
2926
|
-
function isCustomerPasswordResetWebhookEvent(event) {
|
|
2927
|
-
if (event.collection !== "customers" || event.operation !== CUSTOMER_PASSWORD_RESET_OPERATION || !isRecord(event.data)) {
|
|
2928
|
-
return false;
|
|
2929
|
-
}
|
|
2930
|
-
return hasStringOrNumber(event.data, "customerId") && hasString(event.data, "email") && hasString(event.data, "name") && hasString(event.data, "resetPasswordToken") && hasString(event.data, "resetPasswordExpiresAt");
|
|
2931
|
-
}
|
|
2932
|
-
function createCustomerAuthWebhookHandler(handlers) {
|
|
2933
|
-
return async (event) => {
|
|
2934
|
-
if (isCustomerPasswordResetWebhookEvent(event) && handlers.passwordReset) {
|
|
2935
|
-
await handlers.passwordReset(event.data, event);
|
|
2936
|
-
return;
|
|
2937
|
-
}
|
|
2938
|
-
await handlers.unhandled?.(event);
|
|
2939
|
-
};
|
|
2940
|
-
}
|
|
2941
|
-
async function verifySignature(payload, secret, signature, timestamp, deliveryId) {
|
|
2942
|
-
const encoder = new TextEncoder();
|
|
2943
|
-
const key = await crypto.subtle.importKey(
|
|
2944
|
-
"raw",
|
|
2945
|
-
encoder.encode(secret),
|
|
2946
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
2947
|
-
false,
|
|
2948
|
-
["verify"]
|
|
2949
|
-
);
|
|
2950
|
-
if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
|
|
2951
|
-
return false;
|
|
2952
|
-
}
|
|
2953
|
-
const sigBytes = new Uint8Array(
|
|
2954
|
-
(signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
|
|
2955
|
-
);
|
|
2956
|
-
return crypto.subtle.verify(
|
|
2957
|
-
"HMAC",
|
|
2958
|
-
key,
|
|
2959
|
-
sigBytes,
|
|
2960
|
-
encoder.encode(`${timestamp}.${deliveryId}.${payload}`)
|
|
2961
|
-
);
|
|
2962
|
-
}
|
|
2963
|
-
function timestampIsFresh(timestamp, toleranceSeconds) {
|
|
2964
|
-
if (!/^\d+$/.test(timestamp)) return false;
|
|
2965
|
-
const timestampMs = Number(timestamp);
|
|
2966
|
-
if (!Number.isFinite(timestampMs)) return false;
|
|
2967
|
-
const skewMs = Math.abs(Date.now() - timestampMs);
|
|
2968
|
-
return skewMs <= toleranceSeconds * 1e3;
|
|
2969
|
-
}
|
|
2970
|
-
async function handleWebhook(request, handler, options) {
|
|
2971
|
-
try {
|
|
2972
|
-
const rawBody = await request.text();
|
|
2973
|
-
if (options?.secret) {
|
|
2974
|
-
const signature = request.headers.get("x-webhook-signature") || "";
|
|
2975
|
-
const timestamp = request.headers.get("x-webhook-timestamp") || "";
|
|
2976
|
-
const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
|
|
2977
|
-
const toleranceSeconds = options.toleranceSeconds ?? 300;
|
|
2978
|
-
const valid = Boolean(timestamp && deliveryId) && timestampIsFresh(timestamp, toleranceSeconds) && await verifySignature(
|
|
2979
|
-
rawBody,
|
|
2980
|
-
options.secret,
|
|
2981
|
-
signature,
|
|
2982
|
-
timestamp,
|
|
2983
|
-
deliveryId
|
|
2984
|
-
);
|
|
2985
|
-
if (!valid) {
|
|
2986
|
-
return new Response(
|
|
2987
|
-
JSON.stringify({ error: "Invalid webhook signature" }),
|
|
2988
|
-
{ status: 401, headers: { "Content-Type": "application/json" } }
|
|
2989
|
-
);
|
|
2990
|
-
}
|
|
2991
|
-
} else {
|
|
2992
|
-
console.warn(
|
|
2993
|
-
"[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
|
|
2994
|
-
);
|
|
2995
|
-
}
|
|
2996
|
-
const body = JSON.parse(rawBody);
|
|
2997
|
-
if (!isValidWebhookEvent(body)) {
|
|
2998
|
-
return new Response(
|
|
2999
|
-
JSON.stringify({ error: "Invalid webhook event format" }),
|
|
3000
|
-
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
3001
|
-
);
|
|
3002
|
-
}
|
|
3003
|
-
await handler(body);
|
|
3004
|
-
return new Response(
|
|
3005
|
-
JSON.stringify({ success: true, message: "Webhook processed" }),
|
|
3006
|
-
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
3007
|
-
);
|
|
3008
|
-
} catch (error) {
|
|
3009
|
-
console.error("Webhook processing error:", error);
|
|
3010
|
-
return new Response(JSON.stringify({ error: "Internal server error" }), {
|
|
3011
|
-
status: 500,
|
|
3012
|
-
headers: { "Content-Type": "application/json" }
|
|
3013
|
-
});
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
function createTypedWebhookHandler(collection, handler) {
|
|
3017
|
-
return async (event) => {
|
|
3018
|
-
if (event.collection !== collection) {
|
|
3019
|
-
throw new Error(
|
|
3020
|
-
`Expected collection "${collection}", got "${event.collection}"`
|
|
3021
|
-
);
|
|
3022
|
-
}
|
|
3023
|
-
return handler(event);
|
|
3024
|
-
};
|
|
3025
|
-
}
|
|
3026
|
-
|
|
3027
2044
|
// src/utils/ecommerce.ts
|
|
3028
2045
|
var ProductSelectionCodecError = class extends Error {
|
|
3029
2046
|
constructor(message) {
|
|
@@ -3308,38 +2325,45 @@ function hasExplicitSelection(selection) {
|
|
|
3308
2325
|
);
|
|
3309
2326
|
}
|
|
3310
2327
|
function assignSelectedValue(matrix, selectedByOptionId, optionId, valueId) {
|
|
3311
|
-
if (valueId == null) return;
|
|
2328
|
+
if (valueId == null) return false;
|
|
3312
2329
|
const normalizedValueId = String(valueId);
|
|
3313
|
-
if (matrix.valueToOptionId.get(normalizedValueId) !== optionId) return;
|
|
2330
|
+
if (matrix.valueToOptionId.get(normalizedValueId) !== optionId) return false;
|
|
3314
2331
|
selectedByOptionId.set(optionId, normalizedValueId);
|
|
2332
|
+
return true;
|
|
3315
2333
|
}
|
|
3316
2334
|
function assignSelectedValueSlugByOptionId(matrix, selectedByOptionId, optionId, valueSlug) {
|
|
3317
|
-
if (!valueSlug) return;
|
|
2335
|
+
if (!valueSlug) return false;
|
|
3318
2336
|
const option = matrix.optionById.get(optionId);
|
|
3319
|
-
if (!option) return;
|
|
3320
|
-
const
|
|
3321
|
-
|
|
2337
|
+
if (!option) return false;
|
|
2338
|
+
const values = option.values.filter(
|
|
2339
|
+
(candidate) => candidate.slug === valueSlug
|
|
2340
|
+
);
|
|
2341
|
+
if (values.length > 1) {
|
|
2342
|
+
throw new ProductSelectionCodecError(
|
|
2343
|
+
`Ambiguous product selection value slug "${valueSlug}" for option "${optionId}". Use opt.<optionId>=<valueId>.`
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
const value = values[0];
|
|
2347
|
+
if (!value) return false;
|
|
3322
2348
|
selectedByOptionId.set(optionId, value.id);
|
|
2349
|
+
return true;
|
|
3323
2350
|
}
|
|
3324
2351
|
function assignSelectedValueSlugByOptionSlug(matrix, selectedByOptionId, optionSlug, valueSlug) {
|
|
3325
|
-
if (!valueSlug) return;
|
|
2352
|
+
if (!valueSlug) return false;
|
|
3326
2353
|
const option = matrix.optionBySlug.get(optionSlug);
|
|
3327
|
-
if (!option) return;
|
|
3328
|
-
const
|
|
3329
|
-
|
|
3330
|
-
selectedByOptionId.set(option.id, value.id);
|
|
3331
|
-
}
|
|
3332
|
-
function requireValueSlug(value) {
|
|
3333
|
-
if (value.slug) return value.slug;
|
|
3334
|
-
throw new ProductSelectionCodecError(
|
|
3335
|
-
`Option value "${value.id}" does not have a slug and cannot be used in product selection URLs.`
|
|
3336
|
-
);
|
|
3337
|
-
}
|
|
3338
|
-
function requireOptionSlug(option) {
|
|
3339
|
-
if (option.slug) return option.slug;
|
|
3340
|
-
throw new ProductSelectionCodecError(
|
|
3341
|
-
`Option "${option.id}" does not have a slug and cannot be used in product selection URLs.`
|
|
2354
|
+
if (!option) return false;
|
|
2355
|
+
const values = option.values.filter(
|
|
2356
|
+
(candidate) => candidate.slug === valueSlug
|
|
3342
2357
|
);
|
|
2358
|
+
if (values.length > 1) {
|
|
2359
|
+
throw new ProductSelectionCodecError(
|
|
2360
|
+
`Ambiguous product selection value slug "${valueSlug}" for option "${optionSlug}". Use opt.<optionId>=<valueId>.`
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
2363
|
+
const value = values[0];
|
|
2364
|
+
if (!value) return false;
|
|
2365
|
+
selectedByOptionId.set(option.id, value.id);
|
|
2366
|
+
return true;
|
|
3343
2367
|
}
|
|
3344
2368
|
function toSearchParams(search) {
|
|
3345
2369
|
if (!search) return new URLSearchParams();
|
|
@@ -3363,6 +2387,15 @@ function slugLike(value) {
|
|
|
3363
2387
|
}
|
|
3364
2388
|
function assertNoAmbiguousSelectionParams(matrix, params) {
|
|
3365
2389
|
const knownSelectionKeys = /* @__PURE__ */ new Set();
|
|
2390
|
+
const hasVariantParam = params.has("variant");
|
|
2391
|
+
const hasOptionParams = Array.from(params.keys()).some(
|
|
2392
|
+
(key) => key.startsWith("opt.")
|
|
2393
|
+
);
|
|
2394
|
+
if (hasVariantParam && hasOptionParams) {
|
|
2395
|
+
throw new ProductSelectionCodecError(
|
|
2396
|
+
"Product selection URL cannot mix variant=<variantId> with opt.<optionId>=<valueId> params."
|
|
2397
|
+
);
|
|
2398
|
+
}
|
|
3366
2399
|
for (const option of matrix.options) {
|
|
3367
2400
|
knownSelectionKeys.add(slugLike(option.slug));
|
|
3368
2401
|
knownSelectionKeys.add(slugLike(option.title));
|
|
@@ -3375,12 +2408,25 @@ function assertNoAmbiguousSelectionParams(matrix, params) {
|
|
|
3375
2408
|
const optionToken = key.slice(4);
|
|
3376
2409
|
if (!optionToken || !matrix.optionBySlug.has(optionToken) && !matrix.optionById.has(optionToken)) {
|
|
3377
2410
|
throw new ProductSelectionCodecError(
|
|
3378
|
-
`Unknown product selection query parameter "${key}". Use opt.<
|
|
2411
|
+
`Unknown product selection query parameter "${key}". Use opt.<optionId>=<valueId>.`
|
|
2412
|
+
);
|
|
2413
|
+
}
|
|
2414
|
+
if (!value) {
|
|
2415
|
+
throw new ProductSelectionCodecError(
|
|
2416
|
+
`Product selection query parameter "${key}" requires a value ID or compatibility value slug.`
|
|
3379
2417
|
);
|
|
3380
2418
|
}
|
|
2419
|
+
continue;
|
|
2420
|
+
}
|
|
2421
|
+
if (key === "variant") {
|
|
3381
2422
|
if (!value) {
|
|
3382
2423
|
throw new ProductSelectionCodecError(
|
|
3383
|
-
|
|
2424
|
+
'Product selection query parameter "variant" requires a variant ID.'
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
if (!getVariantSelection(matrix, value)) {
|
|
2428
|
+
throw new ProductSelectionCodecError(
|
|
2429
|
+
`Unknown product selection variant "${value}".`
|
|
3384
2430
|
);
|
|
3385
2431
|
}
|
|
3386
2432
|
continue;
|
|
@@ -3388,55 +2434,97 @@ function assertNoAmbiguousSelectionParams(matrix, params) {
|
|
|
3388
2434
|
const keyToken = slugLike(key);
|
|
3389
2435
|
if (knownSelectionKeys.has(keyToken) || value === "" && knownSelectionKeys.has(keyToken)) {
|
|
3390
2436
|
throw new ProductSelectionCodecError(
|
|
3391
|
-
`Ambiguous product selection query parameter "${key}". Use opt.<
|
|
2437
|
+
`Ambiguous product selection query parameter "${key}". Use opt.<optionId>=<valueId>.`
|
|
3392
2438
|
);
|
|
3393
2439
|
}
|
|
3394
2440
|
}
|
|
3395
2441
|
}
|
|
3396
|
-
function
|
|
2442
|
+
function emitCompatibilityOptionIdParam(options, event) {
|
|
3397
2443
|
try {
|
|
2444
|
+
if (options?.onCompatibilityOptionIdParam) {
|
|
2445
|
+
options.onCompatibilityOptionIdParam(event);
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
3398
2448
|
options?.onLegacyOptionIdParam?.(event);
|
|
3399
2449
|
} catch {
|
|
3400
2450
|
}
|
|
3401
2451
|
}
|
|
3402
2452
|
function assignSearchSelection(matrix, selectedByOptionId, search, options) {
|
|
3403
|
-
if (!search) return;
|
|
2453
|
+
if (!search) return null;
|
|
3404
2454
|
const params = toSearchParams(search);
|
|
3405
2455
|
assertNoAmbiguousSelectionParams(matrix, params);
|
|
3406
|
-
|
|
2456
|
+
const variantParam = params.get("variant");
|
|
2457
|
+
if (variantParam != null) {
|
|
2458
|
+
const variantSelection = getVariantSelection(matrix, variantParam);
|
|
2459
|
+
if (!variantSelection) {
|
|
2460
|
+
throw new ProductSelectionCodecError(
|
|
2461
|
+
`Unknown product selection variant "${variantParam}".`
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2464
|
+
for (const [optionId, valueId] of variantSelection.optionValueByOptionId) {
|
|
2465
|
+
selectedByOptionId.set(optionId, valueId);
|
|
2466
|
+
}
|
|
2467
|
+
return variantSelection.id;
|
|
2468
|
+
}
|
|
2469
|
+
for (const [key, valueToken] of params.entries()) {
|
|
3407
2470
|
if (!key.startsWith("opt.")) continue;
|
|
3408
2471
|
const optionToken = key.slice(4);
|
|
2472
|
+
const optionById = matrix.optionById.get(optionToken);
|
|
2473
|
+
if (optionById) {
|
|
2474
|
+
if (assignSelectedValue(
|
|
2475
|
+
matrix,
|
|
2476
|
+
selectedByOptionId,
|
|
2477
|
+
optionById.id,
|
|
2478
|
+
valueToken
|
|
2479
|
+
)) {
|
|
2480
|
+
continue;
|
|
2481
|
+
}
|
|
2482
|
+
const before = selectedByOptionId.get(optionById.id);
|
|
2483
|
+
if (assignSelectedValueSlugByOptionId(
|
|
2484
|
+
matrix,
|
|
2485
|
+
selectedByOptionId,
|
|
2486
|
+
optionById.id,
|
|
2487
|
+
valueToken
|
|
2488
|
+
) && selectedByOptionId.get(optionById.id) !== before) {
|
|
2489
|
+
emitCompatibilityOptionIdParam(options, {
|
|
2490
|
+
optionId: optionById.id,
|
|
2491
|
+
optionSlug: optionById.slug,
|
|
2492
|
+
valueSlug: valueToken,
|
|
2493
|
+
searchParam: key
|
|
2494
|
+
});
|
|
2495
|
+
continue;
|
|
2496
|
+
}
|
|
2497
|
+
throw new ProductSelectionCodecError(
|
|
2498
|
+
`Unknown product selection value "${valueToken}" for option "${optionToken}". Use opt.<optionId>=<valueId>.`
|
|
2499
|
+
);
|
|
2500
|
+
}
|
|
3409
2501
|
const optionBySlug = matrix.optionBySlug.get(optionToken);
|
|
3410
2502
|
if (optionBySlug) {
|
|
3411
|
-
assignSelectedValueSlugByOptionSlug(
|
|
2503
|
+
if (assignSelectedValueSlugByOptionSlug(
|
|
3412
2504
|
matrix,
|
|
3413
2505
|
selectedByOptionId,
|
|
3414
2506
|
optionBySlug.slug,
|
|
3415
|
-
|
|
2507
|
+
valueToken
|
|
2508
|
+
)) {
|
|
2509
|
+
continue;
|
|
2510
|
+
}
|
|
2511
|
+
if (matrix.valueById.has(valueToken)) {
|
|
2512
|
+
throw new ProductSelectionCodecError(
|
|
2513
|
+
`Unknown product selection value "${valueToken}" for option "${optionToken}". Use opt.<optionId>=<valueId>.`
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
throw new ProductSelectionCodecError(
|
|
2517
|
+
`Unknown product selection value "${valueToken}" for option "${optionToken}". Use opt.<optionSlug>=<valueSlug> for compatibility URLs.`
|
|
3416
2518
|
);
|
|
3417
|
-
continue;
|
|
3418
|
-
}
|
|
3419
|
-
const legacyOption = matrix.optionById.get(optionToken);
|
|
3420
|
-
if (!legacyOption) continue;
|
|
3421
|
-
const before = selectedByOptionId.get(legacyOption.id);
|
|
3422
|
-
assignSelectedValueSlugByOptionId(
|
|
3423
|
-
matrix,
|
|
3424
|
-
selectedByOptionId,
|
|
3425
|
-
legacyOption.id,
|
|
3426
|
-
valueSlug
|
|
3427
|
-
);
|
|
3428
|
-
if (selectedByOptionId.get(legacyOption.id) !== before) {
|
|
3429
|
-
emitLegacyOptionIdParam(options, {
|
|
3430
|
-
optionId: legacyOption.id,
|
|
3431
|
-
optionSlug: legacyOption.slug,
|
|
3432
|
-
valueSlug,
|
|
3433
|
-
searchParam: key
|
|
3434
|
-
});
|
|
3435
2519
|
}
|
|
3436
2520
|
}
|
|
2521
|
+
return null;
|
|
3437
2522
|
}
|
|
3438
2523
|
function normalizeProductSelection(detail, selection = {}, options) {
|
|
3439
2524
|
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
2525
|
+
return normalizeProductSelectionFromMatrix(matrix, selection, options);
|
|
2526
|
+
}
|
|
2527
|
+
function normalizeProductSelectionFromMatrix(matrix, selection = {}, options) {
|
|
3440
2528
|
const selectedByOptionId = /* @__PURE__ */ new Map();
|
|
3441
2529
|
const variantSelection = getVariantSelection(matrix, selection.variantId);
|
|
3442
2530
|
const variantId = variantSelection?.id ?? null;
|
|
@@ -3452,7 +2540,12 @@ function normalizeProductSelection(detail, selection = {}, options) {
|
|
|
3452
2540
|
if (!optionId) continue;
|
|
3453
2541
|
selectedByOptionId.set(optionId, valueId);
|
|
3454
2542
|
}
|
|
3455
|
-
|
|
2543
|
+
const searchVariantId = assignSearchSelection(
|
|
2544
|
+
matrix,
|
|
2545
|
+
selectedByOptionId,
|
|
2546
|
+
selection.search,
|
|
2547
|
+
options
|
|
2548
|
+
);
|
|
3456
2549
|
for (const [rawOptionId, rawSelection] of Object.entries(
|
|
3457
2550
|
selection.byOptionId ?? {}
|
|
3458
2551
|
)) {
|
|
@@ -3529,7 +2622,7 @@ function normalizeProductSelection(detail, selection = {}, options) {
|
|
|
3529
2622
|
byOptionSlug,
|
|
3530
2623
|
byOptionId,
|
|
3531
2624
|
valueIds: matrix.optionIds.map((optionId) => byOptionId[optionId]).filter((valueId) => Boolean(valueId)),
|
|
3532
|
-
variantId
|
|
2625
|
+
variantId: searchVariantId ?? variantId
|
|
3533
2626
|
};
|
|
3534
2627
|
}
|
|
3535
2628
|
function parseProductSelection(detail, search, options) {
|
|
@@ -3537,15 +2630,31 @@ function parseProductSelection(detail, search, options) {
|
|
|
3537
2630
|
}
|
|
3538
2631
|
function stringifyProductSelection(detail, selection = {}, options) {
|
|
3539
2632
|
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
3540
|
-
const normalized =
|
|
2633
|
+
const normalized = normalizeProductSelectionFromMatrix(
|
|
2634
|
+
matrix,
|
|
2635
|
+
selection,
|
|
2636
|
+
options
|
|
2637
|
+
);
|
|
3541
2638
|
const params = new URLSearchParams();
|
|
2639
|
+
if (hasExplicitSelection(selection)) {
|
|
2640
|
+
const matchingVariants = getMatchingVariantEntries(matrix, normalized);
|
|
2641
|
+
const exactVariant = getExactSelectedVariantEntry(
|
|
2642
|
+
matrix,
|
|
2643
|
+
normalized,
|
|
2644
|
+
matchingVariants
|
|
2645
|
+
);
|
|
2646
|
+
if (exactVariant) {
|
|
2647
|
+
params.set("variant", exactVariant.id);
|
|
2648
|
+
return params.toString();
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
3542
2651
|
for (const optionId of matrix.optionIds) {
|
|
3543
2652
|
const valueId = normalized.byOptionId[optionId];
|
|
3544
2653
|
if (!valueId) continue;
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
params.append(`opt.${
|
|
2654
|
+
if (!matrix.optionById.has(optionId) || !matrix.valueById.has(valueId)) {
|
|
2655
|
+
continue;
|
|
2656
|
+
}
|
|
2657
|
+
params.append(`opt.${optionId}`, valueId);
|
|
3549
2658
|
}
|
|
3550
2659
|
return params.toString();
|
|
3551
2660
|
}
|
|
@@ -3646,11 +2755,39 @@ function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
|
3646
2755
|
availableStock: null
|
|
3647
2756
|
};
|
|
3648
2757
|
}
|
|
3649
|
-
function
|
|
3650
|
-
const
|
|
3651
|
-
const
|
|
3652
|
-
const
|
|
3653
|
-
|
|
2758
|
+
function buildAvailableValueStock(variants) {
|
|
2759
|
+
const activeVariants = variants.filter((variant) => variant.isActive !== false);
|
|
2760
|
+
const isUnlimited = activeVariants.some((variant) => variant.isUnlimited);
|
|
2761
|
+
const availableStock = isUnlimited ? null : activeVariants.reduce(
|
|
2762
|
+
(sum, variant) => sum + Math.max(0, variant.stock - variant.reservedStock),
|
|
2763
|
+
0
|
|
2764
|
+
);
|
|
2765
|
+
return {
|
|
2766
|
+
availableForSale: activeVariants.some(isVariantAvailableForSale),
|
|
2767
|
+
isUnlimited,
|
|
2768
|
+
availableStock
|
|
2769
|
+
};
|
|
2770
|
+
}
|
|
2771
|
+
function getCandidateVariantsForValue(matrix, optionId, valueId, selectedValueIds) {
|
|
2772
|
+
const selectedByOption = getSelectedValueByOptionId(matrix, selectedValueIds);
|
|
2773
|
+
selectedByOption.set(optionId, valueId);
|
|
2774
|
+
return matrix.variants.filter(
|
|
2775
|
+
(variant) => Array.from(selectedByOption.entries()).every(
|
|
2776
|
+
([selectedOptionId, selectedValueId]) => variant.optionValueByOptionId.get(selectedOptionId) === selectedValueId
|
|
2777
|
+
)
|
|
2778
|
+
).map((variant) => variant.source);
|
|
2779
|
+
}
|
|
2780
|
+
function getResolutionContext(context) {
|
|
2781
|
+
return {
|
|
2782
|
+
images: context?.images ?? context?.detail?.images ?? [],
|
|
2783
|
+
listing: context?.listing ?? context?.detail?.listing ?? {}
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
function resolveProductSelectionFromMatrix(matrix, selection = {}, options, context) {
|
|
2787
|
+
const { images, listing } = getResolutionContext(context);
|
|
2788
|
+
const effectiveSelection = hasExplicitSelection(selection) || listing.selectionHintVariant == null ? selection : { ...selection, variantId: listing.selectionHintVariant };
|
|
2789
|
+
const normalizedSelection = normalizeProductSelectionFromMatrix(
|
|
2790
|
+
matrix,
|
|
3654
2791
|
effectiveSelection,
|
|
3655
2792
|
options
|
|
3656
2793
|
);
|
|
@@ -3685,9 +2822,17 @@ function resolveProductSelection(detail, selection = {}, options) {
|
|
|
3685
2822
|
option.values.map((value) => ({
|
|
3686
2823
|
valueId: value.id,
|
|
3687
2824
|
value: value.label,
|
|
3688
|
-
slug:
|
|
2825
|
+
slug: value.slug ?? "",
|
|
3689
2826
|
selected: normalizedSelection.byOptionId[option.id] === value.id,
|
|
3690
2827
|
available: availableValueIds.has(value.id),
|
|
2828
|
+
...buildAvailableValueStock(
|
|
2829
|
+
getCandidateVariantsForValue(
|
|
2830
|
+
matrix,
|
|
2831
|
+
option.id,
|
|
2832
|
+
value.id,
|
|
2833
|
+
normalizedSelection.valueIds
|
|
2834
|
+
)
|
|
2835
|
+
),
|
|
3691
2836
|
swatchColor: value.swatchColor ?? null,
|
|
3692
2837
|
thumbnail: value.thumbnail ?? null,
|
|
3693
2838
|
images: value.images ?? null
|
|
@@ -3715,7 +2860,12 @@ function resolveProductSelection(detail, selection = {}, options) {
|
|
|
3715
2860
|
allOptionsSelected,
|
|
3716
2861
|
price: buildSelectionPrice(priceVariants),
|
|
3717
2862
|
media: buildSelectionMedia(
|
|
3718
|
-
|
|
2863
|
+
{
|
|
2864
|
+
images,
|
|
2865
|
+
listing: {
|
|
2866
|
+
primaryImage: listing.primaryImage ?? null
|
|
2867
|
+
}
|
|
2868
|
+
},
|
|
3719
2869
|
selectedVariant,
|
|
3720
2870
|
matchingVariants,
|
|
3721
2871
|
selectedValues
|
|
@@ -3723,6 +2873,100 @@ function resolveProductSelection(detail, selection = {}, options) {
|
|
|
3723
2873
|
stock: buildSelectionStock(selectedVariant, matchingVariants)
|
|
3724
2874
|
};
|
|
3725
2875
|
}
|
|
2876
|
+
function resolveProductSelection(detail, selection = {}, options) {
|
|
2877
|
+
const matrix = buildProductOptionMatrixFromDetail(detail);
|
|
2878
|
+
return resolveProductSelectionFromMatrix(matrix, selection, options, {
|
|
2879
|
+
detail
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2882
|
+
function isProductDetailImageMedia(value) {
|
|
2883
|
+
return typeof value === "object" && value !== null;
|
|
2884
|
+
}
|
|
2885
|
+
function mediaDedupeKey(value) {
|
|
2886
|
+
if (value.id != null) return `id:${String(value.id)}`;
|
|
2887
|
+
if (value.url) return `url:${value.url}`;
|
|
2888
|
+
return null;
|
|
2889
|
+
}
|
|
2890
|
+
function getProductSelectionImages(resolution) {
|
|
2891
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2892
|
+
const images = [];
|
|
2893
|
+
const candidates = [
|
|
2894
|
+
resolution.media.primaryImage,
|
|
2895
|
+
...resolution.media.images
|
|
2896
|
+
].filter(isProductDetailImageMedia);
|
|
2897
|
+
for (const candidate of candidates) {
|
|
2898
|
+
const key = mediaDedupeKey(candidate);
|
|
2899
|
+
if (key && seen.has(key)) continue;
|
|
2900
|
+
if (key) seen.add(key);
|
|
2901
|
+
images.push(candidate);
|
|
2902
|
+
}
|
|
2903
|
+
return images;
|
|
2904
|
+
}
|
|
2905
|
+
function getProductHrefSlug(product) {
|
|
2906
|
+
if ("product" in product && product.product?.slug) {
|
|
2907
|
+
return product.product.slug;
|
|
2908
|
+
}
|
|
2909
|
+
if ("slug" in product && product.slug) return product.slug;
|
|
2910
|
+
throw new ProductSelectionCodecError(
|
|
2911
|
+
"Product slug is required to build a product href."
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
2914
|
+
function joinProductPath(basePath, slug, trailingSlash) {
|
|
2915
|
+
const base = basePath.replace(/\/+$/, "");
|
|
2916
|
+
const encodedSlug = encodeURIComponent(slug);
|
|
2917
|
+
return `${base}/${encodedSlug}${trailingSlash ? "/" : ""}`;
|
|
2918
|
+
}
|
|
2919
|
+
function getProductHrefGroupSelection(group, matrix) {
|
|
2920
|
+
if (!group) return null;
|
|
2921
|
+
if (group.variantId != null) return { variantId: group.variantId };
|
|
2922
|
+
const listingVariantId = group.listing?.selectionHintVariant;
|
|
2923
|
+
const optionId = group.optionId != null ? String(group.optionId) : group.optionSlug ? matrix?.optionBySlug.get(group.optionSlug)?.id : void 0;
|
|
2924
|
+
if (!optionId) {
|
|
2925
|
+
return listingVariantId != null ? { variantId: listingVariantId } : null;
|
|
2926
|
+
}
|
|
2927
|
+
const option = matrix?.optionById.get(optionId);
|
|
2928
|
+
const optionValueId = group.optionValueId != null ? String(group.optionValueId) : group.optionValueSlug && option ? option.values.find((value) => value.slug === group.optionValueSlug)?.id : void 0;
|
|
2929
|
+
if (!optionValueId) {
|
|
2930
|
+
return listingVariantId != null ? { variantId: listingVariantId } : null;
|
|
2931
|
+
}
|
|
2932
|
+
return { byOptionId: { [optionId]: optionValueId } };
|
|
2933
|
+
}
|
|
2934
|
+
function buildProductHref(product, group, options = {}) {
|
|
2935
|
+
const path = joinProductPath(
|
|
2936
|
+
options.basePath ?? "/products",
|
|
2937
|
+
getProductHrefSlug(product),
|
|
2938
|
+
options.trailingSlash ?? false
|
|
2939
|
+
);
|
|
2940
|
+
const params = new URLSearchParams();
|
|
2941
|
+
if (options.detail && options.selection) {
|
|
2942
|
+
const selection = stringifyProductSelection(options.detail, options.selection);
|
|
2943
|
+
return selection ? `${path}?${selection}` : path;
|
|
2944
|
+
}
|
|
2945
|
+
const groupSelection = getProductHrefGroupSelection(group, options.matrix);
|
|
2946
|
+
if (groupSelection) {
|
|
2947
|
+
if (options.detail) {
|
|
2948
|
+
const selection = stringifyProductSelection(options.detail, groupSelection);
|
|
2949
|
+
return selection ? `${path}?${selection}` : path;
|
|
2950
|
+
}
|
|
2951
|
+
if (groupSelection.variantId != null) {
|
|
2952
|
+
params.set("variant", String(groupSelection.variantId));
|
|
2953
|
+
return `${path}?${params.toString()}`;
|
|
2954
|
+
}
|
|
2955
|
+
const [selectionEntry] = Object.entries(groupSelection.byOptionId ?? {});
|
|
2956
|
+
if (selectionEntry) {
|
|
2957
|
+
const [optionId, valueId] = selectionEntry;
|
|
2958
|
+
params.set(`opt.${optionId}`, String(valueId));
|
|
2959
|
+
return `${path}?${params.toString()}`;
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
if (group?.optionValueSlug) {
|
|
2963
|
+
const optionSlug = group.optionSlug ?? (group.optionId != null ? options.matrix?.optionById.get(String(group.optionId))?.slug : void 0);
|
|
2964
|
+
if (optionSlug) {
|
|
2965
|
+
params.set(`opt.${optionSlug}`, group.optionValueSlug);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
return params.size > 0 ? `${path}?${params.toString()}` : path;
|
|
2969
|
+
}
|
|
3726
2970
|
function compareVariantOrder(a, b) {
|
|
3727
2971
|
const aOrder = Number(a._order ?? Number.MAX_SAFE_INTEGER);
|
|
3728
2972
|
const bOrder = Number(b._order ?? Number.MAX_SAFE_INTEGER);
|
|
@@ -4102,6 +3346,11 @@ function createAnalytics(config) {
|
|
|
4102
3346
|
}
|
|
4103
3347
|
};
|
|
4104
3348
|
}
|
|
3349
|
+
|
|
3350
|
+
// src/index.ts
|
|
3351
|
+
function createClient2(options) {
|
|
3352
|
+
return createClient(options);
|
|
3353
|
+
}
|
|
4105
3354
|
export {
|
|
4106
3355
|
ApiError,
|
|
4107
3356
|
AuthError,
|
|
@@ -4109,61 +3358,47 @@ export {
|
|
|
4109
3358
|
COLLECTIONS,
|
|
4110
3359
|
CUSTOMER_PASSWORD_RESET_OPERATION,
|
|
4111
3360
|
CartApi,
|
|
4112
|
-
Client,
|
|
4113
|
-
CollectionClient,
|
|
4114
|
-
CollectionHooks,
|
|
4115
|
-
CollectionQueryBuilder,
|
|
4116
3361
|
CommerceClient,
|
|
4117
3362
|
CommunityClient,
|
|
4118
3363
|
ConfigError,
|
|
4119
3364
|
ConflictError,
|
|
4120
3365
|
CustomerAuth,
|
|
4121
|
-
CustomerHooks,
|
|
4122
3366
|
CustomerNamespace,
|
|
4123
3367
|
DiscountApi,
|
|
4124
3368
|
GoneError,
|
|
4125
3369
|
IMAGE_SIZES,
|
|
4126
3370
|
INTERNAL_COLLECTIONS,
|
|
4127
|
-
ModerationApi,
|
|
4128
3371
|
NetworkError,
|
|
4129
3372
|
NotFoundError,
|
|
4130
3373
|
OrderApi,
|
|
4131
3374
|
PermissionError,
|
|
4132
3375
|
ProductApi,
|
|
4133
3376
|
ProductSelectionCodecError,
|
|
4134
|
-
QueryHooks,
|
|
4135
3377
|
RateLimitError,
|
|
4136
|
-
ReadOnlyCollectionClient,
|
|
4137
3378
|
RealtimeConnection,
|
|
4138
3379
|
SDKError,
|
|
4139
3380
|
SERVER_COLLECTIONS,
|
|
4140
3381
|
SERVER_ONLY_COLLECTIONS,
|
|
4141
|
-
ServerClient,
|
|
4142
|
-
ServerCollectionClient,
|
|
4143
|
-
ServerCollectionQueryBuilder,
|
|
4144
|
-
ServerCommerceClient,
|
|
4145
3382
|
ServiceUnavailableError,
|
|
4146
3383
|
ShippingApi,
|
|
4147
3384
|
TimeoutError,
|
|
4148
3385
|
UsageLimitError,
|
|
4149
3386
|
ValidationError,
|
|
3387
|
+
buildProductHref,
|
|
4150
3388
|
buildProductListingGroupsByOption,
|
|
4151
3389
|
buildProductListingProjection,
|
|
4152
3390
|
buildProductOptionMatrix,
|
|
4153
3391
|
buildProductOptionMatrixFromDetail,
|
|
4154
|
-
collectionKeys,
|
|
4155
3392
|
createAnalytics,
|
|
4156
3393
|
createAuthError,
|
|
4157
|
-
createClient,
|
|
3394
|
+
createClient2 as createClient,
|
|
4158
3395
|
createConflictError,
|
|
4159
3396
|
createCustomerAuthWebhookHandler,
|
|
4160
3397
|
createNotFoundError,
|
|
4161
3398
|
createPermissionError,
|
|
4162
3399
|
createProductSelectionCodec,
|
|
4163
3400
|
createRateLimitError,
|
|
4164
|
-
createServerClient,
|
|
4165
3401
|
createTypedWebhookHandler,
|
|
4166
|
-
customerKeys,
|
|
4167
3402
|
formatOrderName,
|
|
4168
3403
|
generateOrderNumber,
|
|
4169
3404
|
getAvailableOptionValues,
|
|
@@ -4172,7 +3407,7 @@ export {
|
|
|
4172
3407
|
getImagePlaceholderStyle,
|
|
4173
3408
|
getImageSrcSet,
|
|
4174
3409
|
getImageUrl,
|
|
4175
|
-
|
|
3410
|
+
getProductSelectionImages,
|
|
4176
3411
|
getSelectedValueByOptionId,
|
|
4177
3412
|
getVideoGif,
|
|
4178
3413
|
getVideoMp4Url,
|
|
@@ -4197,10 +3432,11 @@ export {
|
|
|
4197
3432
|
isValidWebhookEvent,
|
|
4198
3433
|
isValidationError,
|
|
4199
3434
|
normalizeProductSelection,
|
|
3435
|
+
normalizeProductSelectionFromMatrix,
|
|
4200
3436
|
normalizeSelectedValueIds,
|
|
4201
3437
|
parseProductSelection,
|
|
4202
|
-
productKeys,
|
|
4203
3438
|
resolveProductSelection,
|
|
3439
|
+
resolveProductSelectionFromMatrix,
|
|
4204
3440
|
resolveRelation,
|
|
4205
3441
|
resolveVariantForSelection,
|
|
4206
3442
|
stringifyProductSelection
|