commerce-kit 0.66.0 → 0.67.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 +34 -1
- package/dist/api-types.d.ts +89 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/uploads.js +81 -0
- package/dist/uploads.js.map +1 -0
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -115,13 +115,46 @@ const cart = await commerce.cartUpsert({
|
|
|
115
115
|
// Get cart
|
|
116
116
|
const cart = await commerce.cartGet({ cartId: 'cart_123' });
|
|
117
117
|
|
|
118
|
-
// Remove item from cart
|
|
118
|
+
// Remove item from cart (pass lineItemId to remove one personalised line of the variant)
|
|
119
119
|
await commerce.cartRemoveItem({
|
|
120
120
|
cartId: 'cart_123',
|
|
121
121
|
variantId: 'variant_456',
|
|
122
122
|
});
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
### Personalised lines and shopper uploads
|
|
126
|
+
|
|
127
|
+
A line can carry `properties`: text (an engraving) or an uploaded file (a photo for a portrait).
|
|
128
|
+
The same variant with different properties becomes its own line.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
await commerce.cartUpsert({
|
|
132
|
+
variantId: 'variant_456',
|
|
133
|
+
quantity: 1,
|
|
134
|
+
properties: [{ key: 'engraving', label: 'Engraving', type: 'text', value: 'For Ana' }],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Files are uploaded from the browser with `commerce-kit/uploads` (needs the store's Customer Uploads
|
|
139
|
+
module). The platform endpoint is reached through the storefront's own `/checkout/api/**` proxy, so no
|
|
140
|
+
route or API key is needed in the storefront. Images (JPEG, PNG, WebP, GIF, HEIC, AVIF, TIFF) and PDF,
|
|
141
|
+
up to 20 MB, stored privately.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
'use client';
|
|
145
|
+
import { ACCEPTED_LINE_ITEM_UPLOAD_TYPES, lineItemFileProperty, uploadLineItemFile } from 'commerce-kit/uploads';
|
|
146
|
+
|
|
147
|
+
// <input type="file" accept={ACCEPTED_LINE_ITEM_UPLOAD_TYPES} onChange={...} />
|
|
148
|
+
const { uploadId } = await uploadLineItemFile(file, { variantId });
|
|
149
|
+
// then, on the server (server action):
|
|
150
|
+
await commerce.cartUpsert({
|
|
151
|
+
cartId,
|
|
152
|
+
variantId,
|
|
153
|
+
quantity: 1,
|
|
154
|
+
properties: [lineItemFileProperty({ key: 'photo', label: 'Photo', uploadId })],
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
125
158
|
## Orders
|
|
126
159
|
|
|
127
160
|
```typescript
|
package/dist/api-types.d.ts
CHANGED
|
@@ -4635,6 +4635,12 @@ type APICartGetResult = {
|
|
|
4635
4635
|
name: string;
|
|
4636
4636
|
email: string | null;
|
|
4637
4637
|
}[] | null;
|
|
4638
|
+
properties: {
|
|
4639
|
+
key: string;
|
|
4640
|
+
type: "text" | "file";
|
|
4641
|
+
value: string;
|
|
4642
|
+
label?: string | undefined;
|
|
4643
|
+
}[] | null;
|
|
4638
4644
|
subscriptionPlan: {
|
|
4639
4645
|
interval: number;
|
|
4640
4646
|
id: string;
|
|
@@ -5419,6 +5425,12 @@ type APICartCreateBody = {
|
|
|
5419
5425
|
groupId: string;
|
|
5420
5426
|
quantity: number;
|
|
5421
5427
|
}[] | undefined;
|
|
5428
|
+
properties?: {
|
|
5429
|
+
key: string;
|
|
5430
|
+
type: "text" | "file";
|
|
5431
|
+
value: string;
|
|
5432
|
+
label?: string | undefined;
|
|
5433
|
+
}[] | undefined;
|
|
5422
5434
|
};
|
|
5423
5435
|
type APICartCreateResult = {
|
|
5424
5436
|
id: string;
|
|
@@ -5876,6 +5888,12 @@ type APICartCreateResult = {
|
|
|
5876
5888
|
name: string;
|
|
5877
5889
|
email: string | null;
|
|
5878
5890
|
}[] | null;
|
|
5891
|
+
properties: {
|
|
5892
|
+
key: string;
|
|
5893
|
+
type: "text" | "file";
|
|
5894
|
+
value: string;
|
|
5895
|
+
label?: string | undefined;
|
|
5896
|
+
}[] | null;
|
|
5879
5897
|
subscriptionPlan: {
|
|
5880
5898
|
interval: number;
|
|
5881
5899
|
id: string;
|
|
@@ -7101,6 +7119,12 @@ type APICartRemoveItemResult = {
|
|
|
7101
7119
|
name: string;
|
|
7102
7120
|
email: string | null;
|
|
7103
7121
|
}[] | null;
|
|
7122
|
+
properties: {
|
|
7123
|
+
key: string;
|
|
7124
|
+
type: "text" | "file";
|
|
7125
|
+
value: string;
|
|
7126
|
+
label?: string | undefined;
|
|
7127
|
+
}[] | null;
|
|
7104
7128
|
subscriptionPlan: {
|
|
7105
7129
|
interval: number;
|
|
7106
7130
|
id: string;
|
|
@@ -7872,6 +7896,7 @@ type APICartRemoveItemResult = {
|
|
|
7872
7896
|
} | null | undefined;
|
|
7873
7897
|
type APICartRemoveItemQueryParams = {
|
|
7874
7898
|
subscriptionPlanId?: string | undefined;
|
|
7899
|
+
lineItemId?: string | undefined;
|
|
7875
7900
|
};
|
|
7876
7901
|
type APICartCouponApplyBody = {
|
|
7877
7902
|
code: string;
|
|
@@ -8332,6 +8357,12 @@ type APICartCouponApplyResult = {
|
|
|
8332
8357
|
name: string;
|
|
8333
8358
|
email: string | null;
|
|
8334
8359
|
}[] | null;
|
|
8360
|
+
properties: {
|
|
8361
|
+
key: string;
|
|
8362
|
+
type: "text" | "file";
|
|
8363
|
+
value: string;
|
|
8364
|
+
label?: string | undefined;
|
|
8365
|
+
}[] | null;
|
|
8335
8366
|
subscriptionPlan: {
|
|
8336
8367
|
interval: number;
|
|
8337
8368
|
id: string;
|
|
@@ -9365,6 +9396,7 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
9365
9396
|
carrier: "gls";
|
|
9366
9397
|
name: string;
|
|
9367
9398
|
service: "gls";
|
|
9399
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
9368
9400
|
} | null;
|
|
9369
9401
|
deliverySlots: unknown;
|
|
9370
9402
|
shippingTaxRate: {
|
|
@@ -9654,6 +9686,12 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
9654
9686
|
dietary: string | null;
|
|
9655
9687
|
notes: string | null;
|
|
9656
9688
|
}[] | null;
|
|
9689
|
+
properties: {
|
|
9690
|
+
key: string;
|
|
9691
|
+
type: "text" | "file";
|
|
9692
|
+
value: string;
|
|
9693
|
+
label?: string | undefined;
|
|
9694
|
+
}[] | null;
|
|
9657
9695
|
setSelections: {
|
|
9658
9696
|
id: string;
|
|
9659
9697
|
lineItemId: string;
|
|
@@ -10022,6 +10060,7 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
10022
10060
|
carrier: "gls";
|
|
10023
10061
|
name: string;
|
|
10024
10062
|
service: "gls";
|
|
10063
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
10025
10064
|
} | null;
|
|
10026
10065
|
deliverySlots: unknown;
|
|
10027
10066
|
shippingTaxRate: {
|
|
@@ -10311,6 +10350,12 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
10311
10350
|
dietary: string | null;
|
|
10312
10351
|
notes: string | null;
|
|
10313
10352
|
}[] | null;
|
|
10353
|
+
properties: {
|
|
10354
|
+
key: string;
|
|
10355
|
+
type: "text" | "file";
|
|
10356
|
+
value: string;
|
|
10357
|
+
label?: string | undefined;
|
|
10358
|
+
}[] | null;
|
|
10314
10359
|
setSelections: {
|
|
10315
10360
|
id: string;
|
|
10316
10361
|
lineItemId: string;
|
|
@@ -10619,6 +10664,7 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
10619
10664
|
carrier: "gls";
|
|
10620
10665
|
name: string;
|
|
10621
10666
|
service: "gls";
|
|
10667
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
10622
10668
|
} | null;
|
|
10623
10669
|
deliverySlots: unknown;
|
|
10624
10670
|
shippingTaxRate: {
|
|
@@ -10908,6 +10954,12 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
10908
10954
|
dietary: string | null;
|
|
10909
10955
|
notes: string | null;
|
|
10910
10956
|
}[] | null;
|
|
10957
|
+
properties: {
|
|
10958
|
+
key: string;
|
|
10959
|
+
type: "text" | "file";
|
|
10960
|
+
value: string;
|
|
10961
|
+
label?: string | undefined;
|
|
10962
|
+
}[] | null;
|
|
10911
10963
|
setSelections: {
|
|
10912
10964
|
id: string;
|
|
10913
10965
|
lineItemId: string;
|
|
@@ -11276,6 +11328,7 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
11276
11328
|
carrier: "gls";
|
|
11277
11329
|
name: string;
|
|
11278
11330
|
service: "gls";
|
|
11331
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
11279
11332
|
} | null;
|
|
11280
11333
|
deliverySlots: unknown;
|
|
11281
11334
|
shippingTaxRate: {
|
|
@@ -11565,6 +11618,12 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
11565
11618
|
dietary: string | null;
|
|
11566
11619
|
notes: string | null;
|
|
11567
11620
|
}[] | null;
|
|
11621
|
+
properties: {
|
|
11622
|
+
key: string;
|
|
11623
|
+
type: "text" | "file";
|
|
11624
|
+
value: string;
|
|
11625
|
+
label?: string | undefined;
|
|
11626
|
+
}[] | null;
|
|
11568
11627
|
setSelections: {
|
|
11569
11628
|
id: string;
|
|
11570
11629
|
lineItemId: string;
|
|
@@ -11865,6 +11924,7 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
11865
11924
|
carrier: "gls";
|
|
11866
11925
|
name: string;
|
|
11867
11926
|
service: "gls";
|
|
11927
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
11868
11928
|
} | null;
|
|
11869
11929
|
deliverySlots: unknown;
|
|
11870
11930
|
shippingTaxRate: {
|
|
@@ -12819,6 +12879,12 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
12819
12879
|
dietary: string | null;
|
|
12820
12880
|
notes: string | null;
|
|
12821
12881
|
}[] | null;
|
|
12882
|
+
properties: {
|
|
12883
|
+
key: string;
|
|
12884
|
+
type: "text" | "file";
|
|
12885
|
+
value: string;
|
|
12886
|
+
label?: string | undefined;
|
|
12887
|
+
}[] | null;
|
|
12822
12888
|
setSelections: {
|
|
12823
12889
|
id: string;
|
|
12824
12890
|
lineItemId: string;
|
|
@@ -13085,6 +13151,7 @@ type APIOrdersBrowseResult = Omit<{
|
|
|
13085
13151
|
type APIOrdersBrowseQueryParams = {
|
|
13086
13152
|
offset?: number | undefined;
|
|
13087
13153
|
limit?: number | undefined;
|
|
13154
|
+
source?: "counter" | "admin" | "storefront" | "baselinker" | "allegro" | "inpost-buy" | "wholesale" | undefined;
|
|
13088
13155
|
};
|
|
13089
13156
|
type APIOrderGetByIdResult = Omit<{
|
|
13090
13157
|
id: string;
|
|
@@ -13151,6 +13218,7 @@ type APIOrderGetByIdResult = Omit<{
|
|
|
13151
13218
|
carrier: "gls";
|
|
13152
13219
|
name: string;
|
|
13153
13220
|
service: "gls";
|
|
13221
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
13154
13222
|
} | null;
|
|
13155
13223
|
deliverySlots: unknown;
|
|
13156
13224
|
shippingTaxRate: {
|
|
@@ -13440,6 +13508,12 @@ type APIOrderGetByIdResult = Omit<{
|
|
|
13440
13508
|
dietary: string | null;
|
|
13441
13509
|
notes: string | null;
|
|
13442
13510
|
}[] | null;
|
|
13511
|
+
properties: {
|
|
13512
|
+
key: string;
|
|
13513
|
+
type: "text" | "file";
|
|
13514
|
+
value: string;
|
|
13515
|
+
label?: string | undefined;
|
|
13516
|
+
}[] | null;
|
|
13443
13517
|
setSelections: {
|
|
13444
13518
|
id: string;
|
|
13445
13519
|
lineItemId: string;
|
|
@@ -13818,6 +13892,7 @@ type APIOrderGetByIdResult = Omit<{
|
|
|
13818
13892
|
carrier: "gls";
|
|
13819
13893
|
name: string;
|
|
13820
13894
|
service: "gls";
|
|
13895
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
13821
13896
|
} | null;
|
|
13822
13897
|
deliverySlots: unknown;
|
|
13823
13898
|
shippingTaxRate: {
|
|
@@ -14107,6 +14182,12 @@ type APIOrderGetByIdResult = Omit<{
|
|
|
14107
14182
|
dietary: string | null;
|
|
14108
14183
|
notes: string | null;
|
|
14109
14184
|
}[] | null;
|
|
14185
|
+
properties: {
|
|
14186
|
+
key: string;
|
|
14187
|
+
type: "text" | "file";
|
|
14188
|
+
value: string;
|
|
14189
|
+
label?: string | undefined;
|
|
14190
|
+
}[] | null;
|
|
14110
14191
|
setSelections: {
|
|
14111
14192
|
id: string;
|
|
14112
14193
|
lineItemId: string;
|
|
@@ -14403,6 +14484,7 @@ type APIOrderGetByIdResult = Omit<{
|
|
|
14403
14484
|
carrier: "gls";
|
|
14404
14485
|
name: string;
|
|
14405
14486
|
service: "gls";
|
|
14487
|
+
defaultServices?: ("s10" | "s12" | "sat")[] | undefined;
|
|
14406
14488
|
} | null;
|
|
14407
14489
|
deliverySlots: unknown;
|
|
14408
14490
|
shippingTaxRate: {
|
|
@@ -15357,6 +15439,12 @@ type APIOrderGetByIdResult = Omit<{
|
|
|
15357
15439
|
dietary: string | null;
|
|
15358
15440
|
notes: string | null;
|
|
15359
15441
|
}[] | null;
|
|
15442
|
+
properties: {
|
|
15443
|
+
key: string;
|
|
15444
|
+
type: "text" | "file";
|
|
15445
|
+
value: string;
|
|
15446
|
+
label?: string | undefined;
|
|
15447
|
+
}[] | null;
|
|
15360
15448
|
setSelections: {
|
|
15361
15449
|
id: string;
|
|
15362
15450
|
lineItemId: string;
|
|
@@ -16209,6 +16297,7 @@ type APIMeStore = {
|
|
|
16209
16297
|
serialNumbers: boolean;
|
|
16210
16298
|
wholesale: boolean;
|
|
16211
16299
|
stockPricing: boolean;
|
|
16300
|
+
lineItemUploads: boolean;
|
|
16212
16301
|
} | null;
|
|
16213
16302
|
defaultLanguage: "en-US" | "fr-FR" | "it-IT" | "vi-VN" | "pl-PL" | "es-ES" | "de-DE" | null | undefined;
|
|
16214
16303
|
enabledLanguages: {
|
package/dist/index.d.ts
CHANGED
|
@@ -78,9 +78,15 @@ declare class YNSProvider {
|
|
|
78
78
|
cartId?: string;
|
|
79
79
|
currency?: string;
|
|
80
80
|
}): Promise<APICartCreateResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Remove a variant from the cart. A variant can sit on several lines when they carry different
|
|
83
|
+
* `properties` (personalisation); pass `lineItemId` to remove just that one line, otherwise all
|
|
84
|
+
* of the variant's one-time lines go.
|
|
85
|
+
*/
|
|
81
86
|
cartRemoveItem(params: {
|
|
82
87
|
cartId: string;
|
|
83
88
|
variantId: string;
|
|
89
|
+
lineItemId?: string;
|
|
84
90
|
}): Promise<APICartGetResult>;
|
|
85
91
|
cartGet(params: {
|
|
86
92
|
cartId: string;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"./chunk-PNKB6P4V.js";var C=process.env.YNS_API_KEY,B=process.env.YNS_STORE_ID,I={YNS_API_KEY:C,YNS_STORE_ID:B};var h=new Set(["/products","/collections","/categories","/brands"]),w=new Set(["/products/filters","/legal-pages"]),S=new Set(["products","collections","categories","brands","legal-pages"]),v=new Set(["batch","import","import-memberships","filters"]),$=(P,e)=>{if(w.has(P))return!0;if(h.has(P))return e.get("active")==="true";let[t,s,r,...o]=P.split("/").slice(1);return!t||!s||o.length>0||v.has(s)?!1:r===void 0?S.has(t):t==="products"&&r==="reviews"},p=(P,e)=>{let[t="",s=""]=P.split("?"),r=new URLSearchParams(s),o=r.get("active"),n=r.get("metafields")==="all";if(r.has("store")||o!==null&&o!=="true"||n||!$(t,r))return null;let u=[...r.entries()].sort(([i,f],[y,R])=>i===y?f.localeCompare(R):i.localeCompare(y)),a=new URLSearchParams([["store",e],...u]);return`/${t.slice(1)}?${a}`};var l={DEBUG:0,LOG:1,WARN:2,ERROR:3},T=process.env.NEXT_PUBLIC_LOG_LEVEL||"LOG",c=l[T],A="\x1B[0m",G="\x1B[34m",E="\x1B[32m",D="\x1B[33m",U="\x1B[31m",O="\u23F1\uFE0F",L="\u{1F41B}",M="\u2714\uFE0F",b="\u26A0\uFE0F",k="\u274C",g=`${O} `,q=`${G}${L}${A} `,Q=`${E}${M}${A} `,N=`${D}${b}${A} `,Y=`${U}${k}${A} `,m=P=>{let e=P?`[${P}] `:"";return{getLogger(t){return m([P,t].filter(Boolean).join(" > "))},time(t){c>l.DEBUG||console.time([g,e,t].filter(Boolean).join(" "))},timeEnd(t){c>l.DEBUG||console.timeEnd([g,e,t].filter(Boolean).join(" "))},debug(...t){c>l.DEBUG||console.log(...[q,e,...t].filter(Boolean))},log(...t){c>l.LOG||console.log(...[Q,e,...t].filter(Boolean))},dir(t,s){c>l.LOG||console.dir(t,s)},warn(...t){c>l.WARN||console.warn(...[N,e,...t].filter(Boolean))},error(...t){c>l.ERROR||console.error(...[Y,e,...t].filter(Boolean))}}},j=m();var _=new Set([400,401,403]),d=class{#t;#s=m("YNSProvider");#n=null;constructor(e={}){let t=e.token??I.YNS_API_KEY,s=I.YNS_API_KEY?.startsWith("sk-s-");if(!t)throw new Error("YNS API key is required. Set YNS_API_KEY environment variable or pass token in config.");let r=e.endpoint??(s?"https://yns.cx":"https://yns.store");this.#t={version:"v1",...e,token:t,endpoint:r},this.#s.debug("YNSProvider initialized",{endpoint:r,token:e.token?"from config":"from env"})}async#e(e,t="GET",s){let r=await this.#a(e,t,s);return this.#i(r,e,t)}async#r(e){let t=await this.#a(e,"GET");return t.status===404?null:this.#i(t,e,"GET")}#P(){let e=this.#t.store;return e===!1?Promise.resolve(null):(this.#n??=(async()=>{let t=e??I.YNS_STORE_ID;if(t)return t;try{let s=await this.#o("/me","GET");if(!s.ok)return null;let r=await s.json();return typeof r.store?.id=="string"?r.store.id:null}catch{return null}})(),this.#n)}async#a(e,t,s){if(t!=="GET")return this.#o(e,t,s);let r=await this.#P(),o=r?p(e,r):null;if(!o)return this.#o(e,t);let n=this.#s.getLogger("#restRequest"),u=`${this.#t.endpoint}/api/${this.#t.version}${o}`;n.debug(`Making keyless GET request to YNS API: ${u}`);let a=await fetch(u,{method:t,headers:{"Content-Type":"application/json"}});return _.has(a.status)?(a.status!==400&&(this.#n=Promise.resolve(null)),n.debug(`Keyless request answered ${a.status}, asking again with the key`),this.#o(e,t)):a}async#o(e,t,s){let r=this.#s.getLogger("#restRequest"),o=`${this.#t.endpoint}/api/${this.#t.version}${e}`;return r.debug(`Making ${t} request to YNS API: ${o}`),fetch(o,{method:t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.#t.token}`},body:s?JSON.stringify(s):void 0})}async#i(e,t,s){let r=this.#s.getLogger("#restRequest"),o=`${this.#t.endpoint}/api/${this.#t.version}${t}`;if(!e.ok){let u=e.headers.get("content-type"),a=`YNS REST request failed: ${s} ${o} ${e.status} ${e.statusText}`;if(u?.includes("application/json"))try{let i=await e.json();a=i.error||i.message||a}catch(i){r.error("Failed to parse YNS error response as JSON",i)}else{let i=await e.text();r.error(`YNS API request failed: ${e.status} ${e.statusText}`,a,i)}throw new Error(a)}let n=e.headers.get("content-type");if(!n?.includes("application/json"))throw new Error(`YNS API returned ${n} instead of JSON for ${t}`);return e.json()}async#u(e,t){let s=this.#s.getLogger("#multipartRequest"),r=`${this.#t.endpoint}/api/${this.#t.version}${e}`;s.debug(`Making multipart POST to YNS API: ${r}`);let o=await fetch(r,{method:"POST",headers:{Authorization:`Bearer ${this.#t.token}`},body:t});if(!o.ok){let u=o.headers.get("content-type"),a=`YNS REST request failed: POST ${r} ${o.status} ${o.statusText}`;if(u?.includes("application/json"))try{let i=await o.json();a=i.error||i.message||a}catch(i){s.error("Failed to parse YNS error response as JSON",i)}else{let i=await o.text();s.error(`YNS API request failed: ${o.status} ${o.statusText}`,a,i)}throw new Error(a)}let n=o.headers.get("content-type");if(!n?.includes("application/json"))throw new Error(`YNS API returned ${n} instead of JSON for ${e}`);return o.json()}async meGet(){let e=this.#s.getLogger("meGet");e.debug("Fetching my information");let s=await this.#e("/me");return e.debug("Received my information:",s),s}async socialsGet(){let e=this.#s.getLogger("socialsGet");e.debug("Fetching store social links");let s=await this.#e("/socials");return e.debug("Received store social links:",s),s}async brandBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString()),e.lang&&t.append("lang",e.lang);let r=`/brands${t.size?`?${t}`:""}`;return this.#e(r)}async brandGet(e){let t=`/brands/${e.idOrSlug}`;return this.#e(t)}async brandCreate(e){return this.#e("/brands","POST",e)}async brandUpdate(e,t){let s=`/brands/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async brandDelete(e){let t=`/brands/${e.idOrSlug}`;return this.#e(t,"DELETE")}async brandAssignProducts(e,t){let s=`/brands/${e.idOrSlug}/products`;return this.#e(s,"POST",t)}async orderRefundsBrowse(e){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString());let s=t.size?`?${t}`:"",r=`/orders/${e.id}/refunds${s}`;return this.#e(r)}async orderRefundGet(e){let t=`/orders/${e.id}/refunds/${e.refundId}`;return this.#e(t)}async productBatch(e){return this.#e("/products/batch","POST",e)}async cartDelete(e){let t=`/carts/${e.cartId}`;return this.#e(t,"DELETE")}async productBrowse(e){let t=this.#s.getLogger("productBrowse");t.debug("Browsing products with params:",e);let s=new URLSearchParams;e.limit&&s.append("limit",e.limit.toString()),e.offset&&s.append("offset",e.offset.toString()),e.category&&s.append("category",e.category),e.collection&&s.append("collection",e.collection),e.brand&&s.append("brand",e.brand),e.priceMin!==void 0&&s.append("priceMin",e.priceMin.toString()),e.priceMax!==void 0&&s.append("priceMax",e.priceMax.toString()),e.vts&&s.append("vts",e.vts),e.query&&s.append("query",e.query),e.active!==void 0&&s.append("active",e.active.toString()),e.orderBy&&s.append("orderBy",e.orderBy),e.orderDirection&&s.append("orderDirection",e.orderDirection),e.currency&&s.append("currency",e.currency),e.lang&&s.append("lang",e.lang),e.filter&&s.append("filter",e.filter),e.include&&s.append("include",e.include),e.metafields&&s.append("metafields",e.metafields);let o=`/products${s.size?`?${s}`:""}`;t.debug("Constructed pathname:",o);let n=await this.#e(o);return t.debug("Received product browse result:",{meta:n.meta}),n}async productFilters(e={}){let t=new URLSearchParams;e.lang&&t.append("lang",e.lang);let r=`/products/filters${t.size?`?${t}`:""}`;return this.#e(r)}async productGet(e){let t=new URLSearchParams;e.lang&&t.append("lang",e.lang),e.currency&&t.append("currency",e.currency),e.metafields&&t.append("metafields",e.metafields);let s=t.size?`?${t}`:"",r=`/products/${e.idOrSlug}${s}`,o=await this.#e(r);return o||null}async orderBrowse(e){let t=this.#s.getLogger("orderBrowse");t.debug("Browsing orders with params:",e);let s=new URLSearchParams;e.limit&&s.append("limit",e.limit.toString()),e.offset&&s.append("offset",e.offset.toString());let o=`/orders${s.size?`?${s}`:""}`;t.debug("Constructed pathname:",o);let n=await this.#e(o);return t.debug("Received orders browse result:",{meta:n.meta}),n}async orderGet(e){let t=`/orders/${e.id}`,s=await this.#e(t);return s||null}async cartUpsert(e){return await this.#e("/carts","POST",e)}async cartAddBundle(e){let t={bundleId:e.bundleId,selections:e.selections,...e.cartId?{cartId:e.cartId}:{},...e.currency?{currency:e.currency}:{}};return await this.#e("/carts","POST",t)}async cartRemoveItem(e){let t=`/carts/${e.cartId}/line-items/${e.variantId}`;return this.#e(t,"DELETE")}async cartGet(e){let t=`/carts/${e.cartId}`;return await this.#e(t)}async cartCouponApply(e){let t=`/carts/${e.cartId}/coupon`;return this.#e(t,"POST",{code:e.code})}async cartCouponRemove(e){let t=`/carts/${e.cartId}/coupon`;return this.#e(t,"DELETE")}async couponBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query);let r=`/coupons${t.size?`?${t}`:""}`;return this.#e(r)}async couponGet(e){let t=`/coupons/${e.idOrCode}`;return this.#r(t)}async couponCreate(e){return this.#e("/coupons","POST",e)}async couponUpdate(e,t){let s=`/coupons/${e.idOrCode}`;return this.#e(s,"PATCH",t)}async couponDelete(e){let t=`/coupons/${e.idOrCode}`;return this.#e(t,"DELETE")}async supportCaseBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.status&&t.append("status",e.status),e.severity&&t.append("severity",e.severity);let r=`/support-cases${t.size?`?${t}`:""}`;return this.#e(r)}async supportCaseGet(e){let t=`/support-cases/${e.idOrNumber}`;return this.#r(t)}async supportCaseCreate(e){return this.#e("/support-cases","POST",e)}async supportCaseUpdate(e,t){let s=`/support-cases/${e.idOrNumber}`;return this.#e(s,"PATCH",t)}async supportCaseReply(e,t){let s=`/support-cases/${e.idOrNumber}/messages`;return this.#e(s,"POST",t)}async collectionGet(e){let t=`/collections/${e.idOrSlug}`;return await this.#e(t)}async collectionBrowse(e){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString()),e.group&&t.append("group",e.group);let r=`/collections${t.size?`?${t}`:""}`;return await this.#e(r)}async collectionCreate(e){return this.#e("/collections","POST",e)}async collectionUpdate(e,t){let s=`/collections/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async collectionDelete(e){let t=`/collections/${e.idOrSlug}`;return this.#e(t,"DELETE")}async collectionImportMemberships(e){let t=new FormData;return t.append("file",e.file),this.#u("/collections/import-memberships",t)}async categoryGet(e){let t=`/categories/${e.idOrSlug}`;return await this.#e(t)}async categoriesBrowse(e){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString());let r=`/categories${t.size?`?${t}`:""}`;return await this.#e(r)}async postBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString()),e.tag&&t.append("tag",e.tag),e.categoryId&&t.append("categoryId",e.categoryId);let r=`/posts${t.size?`?${t}`:""}`;return this.#e(r)}async postGet(e){let t=`/posts/${e.idOrSlug}`;return this.#e(t)}async postCreate(e){return this.#e("/posts","POST",e)}async postUpdate(e,t){let s=`/posts/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async postDelete(e){let t=`/posts/${e.idOrSlug}`;return this.#e(t,"DELETE")}async postCommentsBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.offset&&s.append("offset",t.offset.toString());let r=s.size?`?${s}`:"",o=`/posts/${e.idOrSlug}/comments${r}`;return this.#e(o)}async postCommentCreate(e,t){let s=`/posts/${e.idOrSlug}/comments`;return this.#e(s,"POST",t)}async blogCategoryBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString());let r=`/blog-categories${t.size?`?${t}`:""}`;return this.#e(r)}async blogCategoryGet(e){let t=`/blog-categories/${e.idOrSlug}`;return this.#e(t)}async blogCategoryCreate(e){return this.#e("/blog-categories","POST",e)}async blogCategoryUpdate(e,t){let s=`/blog-categories/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async blogCategoryDelete(e){let t=`/blog-categories/${e.idOrSlug}`;return this.#e(t,"DELETE")}async customerBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.search&&t.append("search",e.search);let r=`/customers${t.size?`?${t}`:""}`;return this.#e(r)}async customerGet(e){let t=`/customers/${e.id}`;return this.#e(t)}async customerUpdate(e,t){let s=`/customers/${e.id}`;return this.#e(s,"PATCH",t)}async customerAddressCreate(e,t){let s=`/customers/${e.id}/addresses`;return this.#e(s,"POST",t)}async customerAddressDelete(e){let t=`/customers/${e.customerId}/addresses/${e.addressId}`;await this.#e(t,"DELETE")}async customerOrdersBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.offset&&s.append("offset",t.offset.toString());let r=s.size?`?${s}`:"",o=`/customers/${e.id}/orders${r}`;return this.#e(o)}async inventoryBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.cursor&&t.append("cursor",e.cursor),e.lowStock!==void 0&&t.append("lowStock",e.lowStock.toString());let r=`/inventory${t.size?`?${t}`:""}`;return this.#e(r)}async inventoryAdjust(e,t){let s=`/inventory/${encodeURIComponent(e)}/adjust`;return this.#e(s,"POST",t)}async variantGet(e){let t=`/variants/${e.idOrSku}`;return this.#e(t)}async variantUpdate(e,t){let s=`/variants/${e.idOrSku}`;return this.#e(s,"PATCH",t)}async variantDelete(e){let t=`/variants/${e.idOrSku}`;await this.#e(t,"DELETE")}async variantCreate(e,t){let s=`/products/${e}/variants`;return this.#e(s,"POST",t)}async subscriberCreate(e){return this.#e("/subscribers","POST",e)}async subscriberDelete(e){let t=`/subscribers?email=${encodeURIComponent(e)}`;return this.#e(t,"DELETE")}async contactMessageCreate(e){return this.#e("/contact-messages","POST",e)}async productCreate(e){return this.#e("/products","POST",e)}async productUpdate(e,t){let s=`/products/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async productDelete(e){let t=`/products/${e.idOrSlug}`;return this.#e(t,"DELETE")}async metafieldDefinitionBrowse(e={}){let t=new URLSearchParams;e.ownerType&&t.append("ownerType",e.ownerType),e.includeArchived&&t.append("includeArchived",e.includeArchived),e.lang&&t.append("lang",e.lang),e.metafields&&t.append("metafields",e.metafields);let r=`/metafield-definitions${t.size?`?${t}`:""}`;return this.#e(r)}async metafieldDefinitionGet(e){let t=new URLSearchParams;e.lang&&t.append("lang",e.lang),e.metafields&&t.append("metafields",e.metafields);let s=t.size?`?${t}`:"",r=`/metafield-definitions/${e.idOrKey}${s}`;return this.#r(r)}async metafieldDefinitionCreate(e){return this.#e("/metafield-definitions","POST",e)}async metafieldDefinitionUpdate(e,t){let s=`/metafield-definitions/${e.idOrKey}`;return this.#e(s,"PATCH",t)}async metafieldDefinitionArchive(e){let t=`/metafield-definitions/${e.idOrKey}`;return this.#e(t,"DELETE")}async metafieldDefinitionRestore(e){let t=`/metafield-definitions/${e.idOrKey}/restore`;return this.#e(t,"POST")}async metafieldDefinitionDelete(e,t){let s=`/metafield-definitions/${e.idOrKey}/purge`;return this.#e(s,"POST",t)}async metafieldDefinitionConversionPreview(e){let t=`/metafield-definitions/${e.idOrKey}/convert-to-choice`;return this.#e(t)}async metafieldDefinitionConvertToChoice(e,t){let s=`/metafield-definitions/${e.idOrKey}/convert-to-choice`;return this.#e(s,"POST",t)}async metafieldDefinitionTranslationPut(e,t){let s=`/metafield-definitions/${e.idOrKey}/translations/${e.locale}`;return this.#e(s,"PUT",t)}async productMetafieldTranslationsPut(e,t){let s=`/products/${e.idOrSlug}/metafields/translations/${e.locale}`;return this.#e(s,"PUT",t)}async variantMetafieldTranslationsPut(e,t){let s=`/variants/${e.idOrSku}/metafields/translations/${e.locale}`;return this.#e(s,"PUT",t)}async metafieldsTranslateMissing(e={}){return this.#e("/metafields/translate-missing","POST",e)}async productReviewsBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.offset&&s.append("offset",t.offset.toString());let r=s.size?`?${s}`:"",o=`/products/${e.idOrSlug}/reviews${r}`;return this.#e(o)}async productReviewCreate(e,t){let s=`/products/${e.idOrSlug}/reviews`;return this.#e(s,"POST",t)}async eventBrowse(e={}){let t=this.#s.getLogger("eventBrowse"),s=new URLSearchParams;e.offset!==void 0&&s.append("offset",e.offset.toString()),e.limit!==void 0&&s.append("limit",e.limit.toString());let o=`/events${s.size?`?${s}`:""}`;return t.debug("Browsing events:",o),this.#e(o)}async eventGet(e){let t=`/events/${e.idOrSlug}`;return this.#e(t)}async eventCreate(e){return this.#e("/events","POST",e)}async eventUpdate(e,t){let s=`/events/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async eventAttendeesBrowse(e){let t=`/events/${e.idOrSlug}/attendees`;return this.#e(t)}async ticketsGet(e){let t=this.#s.getLogger("ticketsGet"),s=new URLSearchParams({email:e.email}),r=`/tickets/${encodeURIComponent(e.code)}?${s}`;return t.debug("Fetching ticket bundle:",r),this.#r(r)}async ticketsUpdate(e,t){let s=`/tickets/${encodeURIComponent(e.code)}`;return this.#e(s,"PATCH",t)}async ticketAttendeeGet(e){let t=`/tickets/attendee/${encodeURIComponent(e.token)}`;return this.#r(t)}async categoryCreate(e){return this.#e("/categories","POST",e)}async categoryUpdate(e,t){let s=`/categories/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async categoryDelete(e){let t=`/categories/${e.idOrSlug}`;return this.#e(t,"DELETE")}async orderUpdate(e,t){let s=`/orders/${e.id}`;return this.#e(s,"PATCH",t)}async legalPageBrowse(e={}){return this.request("/legal-pages",{query:e})}async legalPageGet(e,t={}){let s=e.startsWith("/")?e.slice(1):e,r=`/legal-pages/${encodeURIComponent(s)}`;return this.request(r,{query:t})}async legalPageCreate(e,t={}){return this.request("/legal-pages",{method:"POST",body:e,query:t})}async legalPageUpdate(e,t,s={}){let r=e.startsWith("/")?e.slice(1):e,o=`/legal-pages/${encodeURIComponent(r)}`;return this.request(o,{method:"PATCH",body:t,query:s})}async search(e){return this.request("/search",{query:e})}async instaviewImagesBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.cursor&&s.append("cursor",t.cursor);let r=s.size?`?${s}`:"",o=`/instaview/accounts/${e.handle}/images${r}`;return this.#e(o)}async request(e,t){let s=t?.query?Object.entries(t.query).filter(o=>{let[,n]=o;return n!=null}):[],r=s.length>0?`?${new URLSearchParams(s.map(([o,n])=>[o,String(n)]))}`:"";return this.#e(`${e}${r}`,t?.method??"GET",t?.body)}};function x(P={}){return new d(P)}export{x as Commerce,d as YNSProvider};
|
|
1
|
+
import"./chunk-PNKB6P4V.js";var C=process.env.YNS_API_KEY,B=process.env.YNS_STORE_ID,I={YNS_API_KEY:C,YNS_STORE_ID:B};var h=new Set(["/products","/collections","/categories","/brands"]),w=new Set(["/products/filters","/legal-pages"]),S=new Set(["products","collections","categories","brands","legal-pages"]),$=new Set(["batch","import","import-memberships","filters"]),v=(P,e)=>{if(w.has(P))return!0;if(h.has(P))return e.get("active")==="true";let[t,s,r,...o]=P.split("/").slice(1);return!t||!s||o.length>0||$.has(s)?!1:r===void 0?S.has(t):t==="products"&&r==="reviews"},p=(P,e)=>{let[t="",s=""]=P.split("?"),r=new URLSearchParams(s),o=r.get("active"),n=r.get("metafields")==="all";if(r.has("store")||o!==null&&o!=="true"||n||!v(t,r))return null;let l=[...r.entries()].sort(([i,f],[y,R])=>i===y?f.localeCompare(R):i.localeCompare(y)),a=new URLSearchParams([["store",e],...l]);return`/${t.slice(1)}?${a}`};var u={DEBUG:0,LOG:1,WARN:2,ERROR:3},T=process.env.NEXT_PUBLIC_LOG_LEVEL||"LOG",c=u[T],A="\x1B[0m",G="\x1B[34m",E="\x1B[32m",D="\x1B[33m",U="\x1B[31m",O="\u23F1\uFE0F",L="\u{1F41B}",M="\u2714\uFE0F",b="\u26A0\uFE0F",k="\u274C",g=`${O} `,q=`${G}${L}${A} `,Q=`${E}${M}${A} `,N=`${D}${b}${A} `,Y=`${U}${k}${A} `,m=P=>{let e=P?`[${P}] `:"";return{getLogger(t){return m([P,t].filter(Boolean).join(" > "))},time(t){c>u.DEBUG||console.time([g,e,t].filter(Boolean).join(" "))},timeEnd(t){c>u.DEBUG||console.timeEnd([g,e,t].filter(Boolean).join(" "))},debug(...t){c>u.DEBUG||console.log(...[q,e,...t].filter(Boolean))},log(...t){c>u.LOG||console.log(...[Q,e,...t].filter(Boolean))},dir(t,s){c>u.LOG||console.dir(t,s)},warn(...t){c>u.WARN||console.warn(...[N,e,...t].filter(Boolean))},error(...t){c>u.ERROR||console.error(...[Y,e,...t].filter(Boolean))}}},j=m();var _=new Set([400,401,403]),d=class{#t;#s=m("YNSProvider");#n=null;constructor(e={}){let t=e.token??I.YNS_API_KEY,s=I.YNS_API_KEY?.startsWith("sk-s-");if(!t)throw new Error("YNS API key is required. Set YNS_API_KEY environment variable or pass token in config.");let r=e.endpoint??(s?"https://yns.cx":"https://yns.store");this.#t={version:"v1",...e,token:t,endpoint:r},this.#s.debug("YNSProvider initialized",{endpoint:r,token:e.token?"from config":"from env"})}async#e(e,t="GET",s){let r=await this.#a(e,t,s);return this.#i(r,e,t)}async#r(e){let t=await this.#a(e,"GET");return t.status===404?null:this.#i(t,e,"GET")}#P(){let e=this.#t.store;return e===!1?Promise.resolve(null):(this.#n??=(async()=>{let t=e??I.YNS_STORE_ID;if(t)return t;try{let s=await this.#o("/me","GET");if(!s.ok)return null;let r=await s.json();return typeof r.store?.id=="string"?r.store.id:null}catch{return null}})(),this.#n)}async#a(e,t,s){if(t!=="GET")return this.#o(e,t,s);let r=await this.#P(),o=r?p(e,r):null;if(!o)return this.#o(e,t);let n=this.#s.getLogger("#restRequest"),l=`${this.#t.endpoint}/api/${this.#t.version}${o}`;n.debug(`Making keyless GET request to YNS API: ${l}`);let a=await fetch(l,{method:t,headers:{"Content-Type":"application/json"}});return _.has(a.status)?(a.status!==400&&(this.#n=Promise.resolve(null)),n.debug(`Keyless request answered ${a.status}, asking again with the key`),this.#o(e,t)):a}async#o(e,t,s){let r=this.#s.getLogger("#restRequest"),o=`${this.#t.endpoint}/api/${this.#t.version}${e}`;return r.debug(`Making ${t} request to YNS API: ${o}`),fetch(o,{method:t,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.#t.token}`},body:s?JSON.stringify(s):void 0})}async#i(e,t,s){let r=this.#s.getLogger("#restRequest"),o=`${this.#t.endpoint}/api/${this.#t.version}${t}`;if(!e.ok){let l=e.headers.get("content-type"),a=`YNS REST request failed: ${s} ${o} ${e.status} ${e.statusText}`;if(l?.includes("application/json"))try{let i=await e.json();a=i.error||i.message||a}catch(i){r.error("Failed to parse YNS error response as JSON",i)}else{let i=await e.text();r.error(`YNS API request failed: ${e.status} ${e.statusText}`,a,i)}throw new Error(a)}let n=e.headers.get("content-type");if(!n?.includes("application/json"))throw new Error(`YNS API returned ${n} instead of JSON for ${t}`);return e.json()}async#l(e,t){let s=this.#s.getLogger("#multipartRequest"),r=`${this.#t.endpoint}/api/${this.#t.version}${e}`;s.debug(`Making multipart POST to YNS API: ${r}`);let o=await fetch(r,{method:"POST",headers:{Authorization:`Bearer ${this.#t.token}`},body:t});if(!o.ok){let l=o.headers.get("content-type"),a=`YNS REST request failed: POST ${r} ${o.status} ${o.statusText}`;if(l?.includes("application/json"))try{let i=await o.json();a=i.error||i.message||a}catch(i){s.error("Failed to parse YNS error response as JSON",i)}else{let i=await o.text();s.error(`YNS API request failed: ${o.status} ${o.statusText}`,a,i)}throw new Error(a)}let n=o.headers.get("content-type");if(!n?.includes("application/json"))throw new Error(`YNS API returned ${n} instead of JSON for ${e}`);return o.json()}async meGet(){let e=this.#s.getLogger("meGet");e.debug("Fetching my information");let s=await this.#e("/me");return e.debug("Received my information:",s),s}async socialsGet(){let e=this.#s.getLogger("socialsGet");e.debug("Fetching store social links");let s=await this.#e("/socials");return e.debug("Received store social links:",s),s}async brandBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString()),e.lang&&t.append("lang",e.lang);let r=`/brands${t.size?`?${t}`:""}`;return this.#e(r)}async brandGet(e){let t=`/brands/${e.idOrSlug}`;return this.#e(t)}async brandCreate(e){return this.#e("/brands","POST",e)}async brandUpdate(e,t){let s=`/brands/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async brandDelete(e){let t=`/brands/${e.idOrSlug}`;return this.#e(t,"DELETE")}async brandAssignProducts(e,t){let s=`/brands/${e.idOrSlug}/products`;return this.#e(s,"POST",t)}async orderRefundsBrowse(e){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString());let s=t.size?`?${t}`:"",r=`/orders/${e.id}/refunds${s}`;return this.#e(r)}async orderRefundGet(e){let t=`/orders/${e.id}/refunds/${e.refundId}`;return this.#e(t)}async productBatch(e){return this.#e("/products/batch","POST",e)}async cartDelete(e){let t=`/carts/${e.cartId}`;return this.#e(t,"DELETE")}async productBrowse(e){let t=this.#s.getLogger("productBrowse");t.debug("Browsing products with params:",e);let s=new URLSearchParams;e.limit&&s.append("limit",e.limit.toString()),e.offset&&s.append("offset",e.offset.toString()),e.category&&s.append("category",e.category),e.collection&&s.append("collection",e.collection),e.brand&&s.append("brand",e.brand),e.priceMin!==void 0&&s.append("priceMin",e.priceMin.toString()),e.priceMax!==void 0&&s.append("priceMax",e.priceMax.toString()),e.vts&&s.append("vts",e.vts),e.query&&s.append("query",e.query),e.active!==void 0&&s.append("active",e.active.toString()),e.orderBy&&s.append("orderBy",e.orderBy),e.orderDirection&&s.append("orderDirection",e.orderDirection),e.currency&&s.append("currency",e.currency),e.lang&&s.append("lang",e.lang),e.filter&&s.append("filter",e.filter),e.include&&s.append("include",e.include),e.metafields&&s.append("metafields",e.metafields);let o=`/products${s.size?`?${s}`:""}`;t.debug("Constructed pathname:",o);let n=await this.#e(o);return t.debug("Received product browse result:",{meta:n.meta}),n}async productFilters(e={}){let t=new URLSearchParams;e.lang&&t.append("lang",e.lang);let r=`/products/filters${t.size?`?${t}`:""}`;return this.#e(r)}async productGet(e){let t=new URLSearchParams;e.lang&&t.append("lang",e.lang),e.currency&&t.append("currency",e.currency),e.metafields&&t.append("metafields",e.metafields);let s=t.size?`?${t}`:"",r=`/products/${e.idOrSlug}${s}`,o=await this.#e(r);return o||null}async orderBrowse(e){let t=this.#s.getLogger("orderBrowse");t.debug("Browsing orders with params:",e);let s=new URLSearchParams;e.limit&&s.append("limit",e.limit.toString()),e.offset&&s.append("offset",e.offset.toString());let o=`/orders${s.size?`?${s}`:""}`;t.debug("Constructed pathname:",o);let n=await this.#e(o);return t.debug("Received orders browse result:",{meta:n.meta}),n}async orderGet(e){let t=`/orders/${e.id}`,s=await this.#e(t);return s||null}async cartUpsert(e){return await this.#e("/carts","POST",e)}async cartAddBundle(e){let t={bundleId:e.bundleId,selections:e.selections,...e.cartId?{cartId:e.cartId}:{},...e.currency?{currency:e.currency}:{}};return await this.#e("/carts","POST",t)}async cartRemoveItem(e){let t=e.lineItemId?`?${new URLSearchParams({lineItemId:e.lineItemId})}`:"",s=`/carts/${e.cartId}/line-items/${e.variantId}${t}`;return this.#e(s,"DELETE")}async cartGet(e){let t=`/carts/${e.cartId}`;return await this.#e(t)}async cartCouponApply(e){let t=`/carts/${e.cartId}/coupon`;return this.#e(t,"POST",{code:e.code})}async cartCouponRemove(e){let t=`/carts/${e.cartId}/coupon`;return this.#e(t,"DELETE")}async couponBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query);let r=`/coupons${t.size?`?${t}`:""}`;return this.#e(r)}async couponGet(e){let t=`/coupons/${e.idOrCode}`;return this.#r(t)}async couponCreate(e){return this.#e("/coupons","POST",e)}async couponUpdate(e,t){let s=`/coupons/${e.idOrCode}`;return this.#e(s,"PATCH",t)}async couponDelete(e){let t=`/coupons/${e.idOrCode}`;return this.#e(t,"DELETE")}async supportCaseBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.status&&t.append("status",e.status),e.severity&&t.append("severity",e.severity);let r=`/support-cases${t.size?`?${t}`:""}`;return this.#e(r)}async supportCaseGet(e){let t=`/support-cases/${e.idOrNumber}`;return this.#r(t)}async supportCaseCreate(e){return this.#e("/support-cases","POST",e)}async supportCaseUpdate(e,t){let s=`/support-cases/${e.idOrNumber}`;return this.#e(s,"PATCH",t)}async supportCaseReply(e,t){let s=`/support-cases/${e.idOrNumber}/messages`;return this.#e(s,"POST",t)}async collectionGet(e){let t=`/collections/${e.idOrSlug}`;return await this.#e(t)}async collectionBrowse(e){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString()),e.group&&t.append("group",e.group);let r=`/collections${t.size?`?${t}`:""}`;return await this.#e(r)}async collectionCreate(e){return this.#e("/collections","POST",e)}async collectionUpdate(e,t){let s=`/collections/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async collectionDelete(e){let t=`/collections/${e.idOrSlug}`;return this.#e(t,"DELETE")}async collectionImportMemberships(e){let t=new FormData;return t.append("file",e.file),this.#l("/collections/import-memberships",t)}async categoryGet(e){let t=`/categories/${e.idOrSlug}`;return await this.#e(t)}async categoriesBrowse(e){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString());let r=`/categories${t.size?`?${t}`:""}`;return await this.#e(r)}async postBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString()),e.tag&&t.append("tag",e.tag),e.categoryId&&t.append("categoryId",e.categoryId);let r=`/posts${t.size?`?${t}`:""}`;return this.#e(r)}async postGet(e){let t=`/posts/${e.idOrSlug}`;return this.#e(t)}async postCreate(e){return this.#e("/posts","POST",e)}async postUpdate(e,t){let s=`/posts/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async postDelete(e){let t=`/posts/${e.idOrSlug}`;return this.#e(t,"DELETE")}async postCommentsBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.offset&&s.append("offset",t.offset.toString());let r=s.size?`?${s}`:"",o=`/posts/${e.idOrSlug}/comments${r}`;return this.#e(o)}async postCommentCreate(e,t){let s=`/posts/${e.idOrSlug}/comments`;return this.#e(s,"POST",t)}async blogCategoryBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.query&&t.append("query",e.query),e.active!==void 0&&t.append("active",e.active.toString());let r=`/blog-categories${t.size?`?${t}`:""}`;return this.#e(r)}async blogCategoryGet(e){let t=`/blog-categories/${e.idOrSlug}`;return this.#e(t)}async blogCategoryCreate(e){return this.#e("/blog-categories","POST",e)}async blogCategoryUpdate(e,t){let s=`/blog-categories/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async blogCategoryDelete(e){let t=`/blog-categories/${e.idOrSlug}`;return this.#e(t,"DELETE")}async customerBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.offset&&t.append("offset",e.offset.toString()),e.search&&t.append("search",e.search);let r=`/customers${t.size?`?${t}`:""}`;return this.#e(r)}async customerGet(e){let t=`/customers/${e.id}`;return this.#e(t)}async customerUpdate(e,t){let s=`/customers/${e.id}`;return this.#e(s,"PATCH",t)}async customerAddressCreate(e,t){let s=`/customers/${e.id}/addresses`;return this.#e(s,"POST",t)}async customerAddressDelete(e){let t=`/customers/${e.customerId}/addresses/${e.addressId}`;await this.#e(t,"DELETE")}async customerOrdersBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.offset&&s.append("offset",t.offset.toString());let r=s.size?`?${s}`:"",o=`/customers/${e.id}/orders${r}`;return this.#e(o)}async inventoryBrowse(e={}){let t=new URLSearchParams;e.limit&&t.append("limit",e.limit.toString()),e.cursor&&t.append("cursor",e.cursor),e.lowStock!==void 0&&t.append("lowStock",e.lowStock.toString());let r=`/inventory${t.size?`?${t}`:""}`;return this.#e(r)}async inventoryAdjust(e,t){let s=`/inventory/${encodeURIComponent(e)}/adjust`;return this.#e(s,"POST",t)}async variantGet(e){let t=`/variants/${e.idOrSku}`;return this.#e(t)}async variantUpdate(e,t){let s=`/variants/${e.idOrSku}`;return this.#e(s,"PATCH",t)}async variantDelete(e){let t=`/variants/${e.idOrSku}`;await this.#e(t,"DELETE")}async variantCreate(e,t){let s=`/products/${e}/variants`;return this.#e(s,"POST",t)}async subscriberCreate(e){return this.#e("/subscribers","POST",e)}async subscriberDelete(e){let t=`/subscribers?email=${encodeURIComponent(e)}`;return this.#e(t,"DELETE")}async contactMessageCreate(e){return this.#e("/contact-messages","POST",e)}async productCreate(e){return this.#e("/products","POST",e)}async productUpdate(e,t){let s=`/products/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async productDelete(e){let t=`/products/${e.idOrSlug}`;return this.#e(t,"DELETE")}async metafieldDefinitionBrowse(e={}){let t=new URLSearchParams;e.ownerType&&t.append("ownerType",e.ownerType),e.includeArchived&&t.append("includeArchived",e.includeArchived),e.lang&&t.append("lang",e.lang),e.metafields&&t.append("metafields",e.metafields);let r=`/metafield-definitions${t.size?`?${t}`:""}`;return this.#e(r)}async metafieldDefinitionGet(e){let t=new URLSearchParams;e.lang&&t.append("lang",e.lang),e.metafields&&t.append("metafields",e.metafields);let s=t.size?`?${t}`:"",r=`/metafield-definitions/${e.idOrKey}${s}`;return this.#r(r)}async metafieldDefinitionCreate(e){return this.#e("/metafield-definitions","POST",e)}async metafieldDefinitionUpdate(e,t){let s=`/metafield-definitions/${e.idOrKey}`;return this.#e(s,"PATCH",t)}async metafieldDefinitionArchive(e){let t=`/metafield-definitions/${e.idOrKey}`;return this.#e(t,"DELETE")}async metafieldDefinitionRestore(e){let t=`/metafield-definitions/${e.idOrKey}/restore`;return this.#e(t,"POST")}async metafieldDefinitionDelete(e,t){let s=`/metafield-definitions/${e.idOrKey}/purge`;return this.#e(s,"POST",t)}async metafieldDefinitionConversionPreview(e){let t=`/metafield-definitions/${e.idOrKey}/convert-to-choice`;return this.#e(t)}async metafieldDefinitionConvertToChoice(e,t){let s=`/metafield-definitions/${e.idOrKey}/convert-to-choice`;return this.#e(s,"POST",t)}async metafieldDefinitionTranslationPut(e,t){let s=`/metafield-definitions/${e.idOrKey}/translations/${e.locale}`;return this.#e(s,"PUT",t)}async productMetafieldTranslationsPut(e,t){let s=`/products/${e.idOrSlug}/metafields/translations/${e.locale}`;return this.#e(s,"PUT",t)}async variantMetafieldTranslationsPut(e,t){let s=`/variants/${e.idOrSku}/metafields/translations/${e.locale}`;return this.#e(s,"PUT",t)}async metafieldsTranslateMissing(e={}){return this.#e("/metafields/translate-missing","POST",e)}async productReviewsBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.offset&&s.append("offset",t.offset.toString());let r=s.size?`?${s}`:"",o=`/products/${e.idOrSlug}/reviews${r}`;return this.#e(o)}async productReviewCreate(e,t){let s=`/products/${e.idOrSlug}/reviews`;return this.#e(s,"POST",t)}async eventBrowse(e={}){let t=this.#s.getLogger("eventBrowse"),s=new URLSearchParams;e.offset!==void 0&&s.append("offset",e.offset.toString()),e.limit!==void 0&&s.append("limit",e.limit.toString());let o=`/events${s.size?`?${s}`:""}`;return t.debug("Browsing events:",o),this.#e(o)}async eventGet(e){let t=`/events/${e.idOrSlug}`;return this.#e(t)}async eventCreate(e){return this.#e("/events","POST",e)}async eventUpdate(e,t){let s=`/events/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async eventAttendeesBrowse(e){let t=`/events/${e.idOrSlug}/attendees`;return this.#e(t)}async ticketsGet(e){let t=this.#s.getLogger("ticketsGet"),s=new URLSearchParams({email:e.email}),r=`/tickets/${encodeURIComponent(e.code)}?${s}`;return t.debug("Fetching ticket bundle:",r),this.#r(r)}async ticketsUpdate(e,t){let s=`/tickets/${encodeURIComponent(e.code)}`;return this.#e(s,"PATCH",t)}async ticketAttendeeGet(e){let t=`/tickets/attendee/${encodeURIComponent(e.token)}`;return this.#r(t)}async categoryCreate(e){return this.#e("/categories","POST",e)}async categoryUpdate(e,t){let s=`/categories/${e.idOrSlug}`;return this.#e(s,"PATCH",t)}async categoryDelete(e){let t=`/categories/${e.idOrSlug}`;return this.#e(t,"DELETE")}async orderUpdate(e,t){let s=`/orders/${e.id}`;return this.#e(s,"PATCH",t)}async legalPageBrowse(e={}){return this.request("/legal-pages",{query:e})}async legalPageGet(e,t={}){let s=e.startsWith("/")?e.slice(1):e,r=`/legal-pages/${encodeURIComponent(s)}`;return this.request(r,{query:t})}async legalPageCreate(e,t={}){return this.request("/legal-pages",{method:"POST",body:e,query:t})}async legalPageUpdate(e,t,s={}){let r=e.startsWith("/")?e.slice(1):e,o=`/legal-pages/${encodeURIComponent(r)}`;return this.request(o,{method:"PATCH",body:t,query:s})}async search(e){return this.request("/search",{query:e})}async instaviewImagesBrowse(e,t={}){let s=new URLSearchParams;t.limit&&s.append("limit",t.limit.toString()),t.cursor&&s.append("cursor",t.cursor);let r=s.size?`?${s}`:"",o=`/instaview/accounts/${e.handle}/images${r}`;return this.#e(o)}async request(e,t){let s=t?.query?Object.entries(t.query).filter(o=>{let[,n]=o;return n!=null}):[],r=s.length>0?`?${new URLSearchParams(s.map(([o,n])=>[o,String(n)]))}`:"";return this.#e(`${e}${r}`,t?.method??"GET",t?.body)}};function x(P={}){return new d(P)}export{x as Commerce,d as YNSProvider};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/env.ts","../src/keyless.ts","../src/logger.ts","../src/providers/yns.ts","../src/commerce.ts"],"sourcesContent":["const YNS_API_KEY = process.env.YNS_API_KEY;\nconst YNS_STORE_ID = process.env.YNS_STORE_ID;\n\nexport const env = {\n\tYNS_API_KEY,\n\tYNS_STORE_ID,\n};\n","/**\n * Catalog reads the platform also answers without an API key, so its CDN can keep the answer.\n * A request qualifies only when the keyless answer is the one the key would get.\n */\n\n/** `GET` paths that answer without a key. Lists also need `active=true`: without it a key sees inactive rows too. */\nconst KEYLESS_LISTS: ReadonlySet<string> = new Set([\"/products\", \"/collections\", \"/categories\", \"/brands\"]);\nconst KEYLESS_SINGLETONS: ReadonlySet<string> = new Set([\"/products/filters\", \"/legal-pages\"]);\nconst KEYLESS_DETAILS: ReadonlySet<string> = new Set([\n\t\"products\",\n\t\"collections\",\n\t\"categories\",\n\t\"brands\",\n\t\"legal-pages\",\n]);\n/** Second segments that are their own endpoints, not an id or slug. */\nconst NOT_A_RESOURCE: ReadonlySet<string> = new Set([\"batch\", \"import\", \"import-memberships\", \"filters\"]);\n\nconst isKeylessPath = (path: string, query: URLSearchParams): boolean => {\n\tif (KEYLESS_SINGLETONS.has(path)) return true;\n\tif (KEYLESS_LISTS.has(path)) return query.get(\"active\") === \"true\";\n\n\tconst [resource, idOrSlug, child, ...rest] = path.split(\"/\").slice(1);\n\tif (!resource || !idOrSlug || rest.length > 0 || NOT_A_RESOURCE.has(idOrSlug)) return false;\n\tif (child === undefined) return KEYLESS_DETAILS.has(resource);\n\treturn resource === \"products\" && child === \"reviews\";\n};\n\n/**\n * The keyless form of a `GET` pathname, or `null` when the request needs the key.\n *\n * `store` goes first and the other parameters are sorted, so two requests that mean the same\n * thing are one URL, and therefore one cached copy.\n */\nexport const keylessPathname = (pathname: `/${string}`, storeId: string): `/${string}` | null => {\n\tconst [path = \"\", search = \"\"] = pathname.split(\"?\");\n\tconst query = new URLSearchParams(search);\n\tconst active = query.get(\"active\");\n\t// Private custom fields are for keys with `catalog:write`: a keyless read is refused.\n\tconst privateFields = query.get(\"metafields\") === \"all\";\n\tif (\n\t\tquery.has(\"store\") ||\n\t\t(active !== null && active !== \"true\") ||\n\t\tprivateFields ||\n\t\t!isKeylessPath(path, query)\n\t) {\n\t\treturn null;\n\t}\n\n\tconst sorted = [...query.entries()].sort(([a, aValue], [b, bValue]) =>\n\t\ta === b ? aValue.localeCompare(bValue) : a.localeCompare(b),\n\t);\n\tconst keyless = new URLSearchParams([[\"store\", storeId], ...sorted]);\n\treturn `/${path.slice(1)}?${keyless}`;\n};\n","import type { InspectOptions } from \"node:util\";\n\ntype LogParms = [message: unknown, ...optionalParams: unknown[]];\n\n/**\n * Vercel only supports 3 levels of logging. We're adding additional DEBUG level.\n * https://vercel.com/docs/observability/runtime-logs#level\n *\n * ERROR - Fatal for a particular request. Should be fixed sooner than later.\n *\n * WARN - A note on something that should probably be looked at eventually.\n *\n * LOG - Detail on regular operation.\n *\n * DEBUG - Debug only info as well as time and timeEnd functions.\n */\nconst LogLevel = {\n\tDEBUG: 0,\n\tLOG: 1,\n\tWARN: 2,\n\tERROR: 3,\n} as const;\ntype LogLevel = keyof typeof LogLevel;\n\nconst strLogLevel = (process.env.NEXT_PUBLIC_LOG_LEVEL || \"LOG\") as LogLevel;\nconst valueLogLevel = LogLevel[strLogLevel];\n\nconst RESET = \"\\x1b[0m\";\nconst BLUE = \"\\x1b[34m\";\nconst GREEN = \"\\x1b[32m\";\nconst YELLOW = \"\\x1b[33m\";\nconst RED = \"\\x1b[31m\";\n\nconst TIME = `⏱️`;\nconst DEBUG = `🐛`;\nconst OK = `✔️`;\nconst WARN = `⚠️`;\nconst ERROR = `❌`;\n\nconst PREFIX_TIME = `${TIME} `;\nconst PREFIX_DEBUG = `${BLUE}${DEBUG}${RESET} `;\nconst PREFIX_OK = `${GREEN}${OK}${RESET} `;\nconst PREFIX_WARN = `${YELLOW}${WARN}${RESET} `;\nconst PREFIX_ERROR = `${RED}${ERROR}${RESET} `;\n\nexport const getLogger = (groupLabel?: string) => {\n\tconst PREFIX = groupLabel ? `[${groupLabel}] ` : \"\";\n\treturn {\n\t\tgetLogger(subGroupLabel: string) {\n\t\t\treturn getLogger([groupLabel, subGroupLabel].filter(Boolean).join(\" > \"));\n\t\t},\n\t\ttime(label: string) {\n\t\t\tif (valueLogLevel > LogLevel.DEBUG) return;\n\t\t\tconsole.time([PREFIX_TIME, PREFIX, label].filter(Boolean).join(\" \"));\n\t\t},\n\t\ttimeEnd(label: string) {\n\t\t\tif (valueLogLevel > LogLevel.DEBUG) return;\n\t\t\tconsole.timeEnd([PREFIX_TIME, PREFIX, label].filter(Boolean).join(\" \"));\n\t\t},\n\t\tdebug(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.DEBUG) return;\n\t\t\tconsole.log(...[PREFIX_DEBUG, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t\tlog(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.LOG) return;\n\t\t\tconsole.log(...[PREFIX_OK, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t\tdir(item?: unknown, options?: InspectOptions) {\n\t\t\tif (valueLogLevel > LogLevel.LOG) return;\n\t\t\tconsole.dir(item, options);\n\t\t},\n\t\twarn(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.WARN) return;\n\t\t\tconsole.warn(...[PREFIX_WARN, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t\terror(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.ERROR) return;\n\t\t\tconsole.error(...[PREFIX_ERROR, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t};\n};\n\nexport const logger = getLogger();\n","import type {\n\tAPIBlogCategoriesBrowseQueryParams,\n\tAPIBlogCategoriesBrowseResult,\n\tAPIBlogCategoryCreateBody,\n\tAPIBlogCategoryCreateResult,\n\tAPIBlogCategoryDeleteResult,\n\tAPIBlogCategoryGetByIdParams,\n\tAPIBlogCategoryGetByIdResult,\n\tAPIBlogCategoryUpdateBody,\n\tAPIBlogCategoryUpdateResult,\n\tAPIBrandAssignProductsBody,\n\tAPIBrandAssignProductsResult,\n\tAPIBrandCreateBody,\n\tAPIBrandCreateResult,\n\tAPIBrandDeleteResult,\n\tAPIBrandGetByIdParams,\n\tAPIBrandGetByIdResult,\n\tAPIBrandsBrowseQueryParams,\n\tAPIBrandsBrowseResult,\n\tAPIBrandUpdateBody,\n\tAPIBrandUpdateResult,\n\tAPICartCouponApplyResult,\n\tAPICartCouponRemoveResult,\n\tAPICartCreateBody,\n\tAPICartCreateResult,\n\tAPICartDeleteResult,\n\tAPICartGetResult,\n\tAPICategoriesBrowseQueryParams,\n\tAPICategoriesBrowseResult,\n\tAPICategoryCreateBody,\n\tAPICategoryCreateResult,\n\tAPICategoryDeleteResult,\n\tAPICategoryGetByIdParams,\n\tAPICategoryGetByIdResult,\n\tAPICategoryUpdateBody,\n\tAPICategoryUpdateResult,\n\tAPICollectionCreateBody,\n\tAPICollectionCreateResult,\n\tAPICollectionDeleteResult,\n\tAPICollectionGetByIdParams,\n\tAPICollectionGetByIdResult,\n\tAPICollectionsBrowseQueryParams,\n\tAPICollectionsBrowseResult,\n\tAPICollectionUpdateBody,\n\tAPICollectionUpdateResult,\n\tAPIContactMessageCreateBody,\n\tAPIContactMessageCreateResult,\n\tAPICouponCreateBody,\n\tAPICouponCreateResult,\n\tAPICouponDeleteResult,\n\tAPICouponGetByIdParams,\n\tAPICouponGetByIdResult,\n\tAPICouponsBrowseQueryParams,\n\tAPICouponsBrowseResult,\n\tAPICouponUpdateBody,\n\tAPICouponUpdateResult,\n\tAPICustomerAddressCreateBody,\n\tAPICustomerAddressCreateResult,\n\tAPICustomerGetByIdParams,\n\tAPICustomerGetByIdResult,\n\tAPICustomerOrdersBrowseQueryParams,\n\tAPICustomerOrdersBrowseResult,\n\tAPICustomersBrowseQueryParams,\n\tAPICustomersBrowseResult,\n\tAPICustomerUpdateBody,\n\tAPICustomerUpdateResult,\n\tAPIEventAttendeesBrowseResult,\n\tAPIEventCreateBody,\n\tAPIEventCreateResult,\n\tAPIEventGetByIdParams,\n\tAPIEventGetByIdResult,\n\tAPIEventsBrowseQueryParams,\n\tAPIEventsBrowseResult,\n\tAPIEventUpdateBody,\n\tAPIEventUpdateResult,\n\tAPIInstaviewImagesBrowseParams,\n\tAPIInstaviewImagesBrowseQueryParams,\n\tAPIInstaviewImagesBrowseResult,\n\tAPIInventoryAdjustBody,\n\tAPIInventoryAdjustResult,\n\tAPIInventoryBrowseQueryParams,\n\tAPIInventoryBrowseResult,\n\tAPILegalPageCreateBody,\n\tAPILegalPageCreateQueryParams,\n\tAPILegalPageCreateResult,\n\tAPILegalPageGetByPathQueryParams,\n\tAPILegalPageGetByPathResult,\n\tAPILegalPagesBrowseQueryParams,\n\tAPILegalPagesBrowseResult,\n\tAPILegalPageUpdateBody,\n\tAPILegalPageUpdateQueryParams,\n\tAPILegalPageUpdateResult,\n\tAPIMeGetResult,\n\tAPIMetafieldDefinitionArchiveResult,\n\tAPIMetafieldDefinitionConversionPreviewResult,\n\tAPIMetafieldDefinitionConvertBody,\n\tAPIMetafieldDefinitionConvertResult,\n\tAPIMetafieldDefinitionCreateBody,\n\tAPIMetafieldDefinitionCreateResult,\n\tAPIMetafieldDefinitionDeleteBody,\n\tAPIMetafieldDefinitionDeleteResult,\n\tAPIMetafieldDefinitionGetQueryParams,\n\tAPIMetafieldDefinitionGetResult,\n\tAPIMetafieldDefinitionParams,\n\tAPIMetafieldDefinitionRestoreResult,\n\tAPIMetafieldDefinitionsBrowseQueryParams,\n\tAPIMetafieldDefinitionsBrowseResult,\n\tAPIMetafieldDefinitionTranslationParams,\n\tAPIMetafieldDefinitionTranslationPutBody,\n\tAPIMetafieldDefinitionTranslationPutResult,\n\tAPIMetafieldDefinitionUpdateBody,\n\tAPIMetafieldDefinitionUpdateResult,\n\tAPIMetafieldsTranslateMissingBody,\n\tAPIMetafieldsTranslateMissingResult,\n\tAPIMetafieldTranslationsPutBody,\n\tAPIOrderGetByIdParams,\n\tAPIOrderGetByIdResult,\n\tAPIOrderRefundGetParams,\n\tAPIOrderRefundGetResult,\n\tAPIOrderRefundsBrowseQueryParams,\n\tAPIOrderRefundsBrowseResult,\n\tAPIOrderRefundsParams,\n\tAPIOrdersBrowseQueryParams,\n\tAPIOrdersBrowseResult,\n\tAPIOrderUpdateBody,\n\tAPIOrderUpdateResult,\n\tAPIPostCommentCreateBody,\n\tAPIPostCommentCreateResult,\n\tAPIPostCommentsBrowseQueryParams,\n\tAPIPostCommentsBrowseResult,\n\tAPIPostCreateBody,\n\tAPIPostCreateResult,\n\tAPIPostDeleteResult,\n\tAPIPostGetByIdParams,\n\tAPIPostGetByIdResult,\n\tAPIPostsBrowseQueryParams,\n\tAPIPostsBrowseResult,\n\tAPIPostUpdateBody,\n\tAPIPostUpdateResult,\n\tAPIProductBatchBody,\n\tAPIProductBatchResult,\n\tAPIProductCreateBody,\n\tAPIProductCreateResult,\n\tAPIProductDeleteResult,\n\tAPIProductFiltersQueryParams,\n\tAPIProductFiltersResult,\n\tAPIProductGetByIdParams,\n\tAPIProductGetByIdQueryParams,\n\tAPIProductGetByIdResult,\n\tAPIProductMetafieldTranslationsPutParams,\n\tAPIProductMetafieldTranslationsPutResult,\n\tAPIProductReviewCreateBody,\n\tAPIProductReviewCreateResult,\n\tAPIProductReviewsBrowseQueryParams,\n\tAPIProductReviewsBrowseResult,\n\tAPIProductsBrowseQueryParams,\n\tAPIProductsBrowseResult,\n\tAPIProductUpdateBody,\n\tAPIProductUpdateResult,\n\tAPISearchQueryParams,\n\tAPISearchResult,\n\tAPISocialsGetResult,\n\tAPISubscriberCreateBody,\n\tAPISubscriberCreateResult,\n\tAPISubscriberDeleteResult,\n\tAPISupportCaseCreateBody,\n\tAPISupportCaseCreateResult,\n\tAPISupportCaseGetParams,\n\tAPISupportCaseGetResult,\n\tAPISupportCaseMessageCreateBody,\n\tAPISupportCaseMessageCreateResult,\n\tAPISupportCasesBrowseQueryParams,\n\tAPISupportCasesBrowseResult,\n\tAPISupportCaseUpdateBody,\n\tAPISupportCaseUpdateResult,\n\tAPITicketAttendeeGetResult,\n\tAPITicketsGetResult,\n\tAPITicketsUpdateBody,\n\tAPITicketsUpdateResult,\n\tAPIVariantCreateBody,\n\tAPIVariantCreateResult,\n\tAPIVariantGetByIdParams,\n\tAPIVariantGetByIdResult,\n\tAPIVariantMetafieldTranslationsPutParams,\n\tAPIVariantMetafieldTranslationsPutResult,\n\tAPIVariantUpdateBody,\n\tAPIVariantUpdateResult,\n} from \"../api-types\";\nimport { env } from \"../env\";\nimport { keylessPathname } from \"../keyless\";\nimport { getLogger } from \"../logger\";\nimport type { CommerceConfig } from \"../types\";\n\nexport type APICollectionImportMembershipsBody = { file: File | Blob };\n\nexport type APICollectionImportMembershipsResult = {\n\tok: true;\n\tprocessed: number;\n\tinserted: number;\n\tskipped_existing: number;\n\terrors: Array<{\n\t\trow: number;\n\t\tcollection_slug?: string;\n\t\tproduct_slug?: string;\n\t\treason: string;\n\t}>;\n};\n\n/** Answers that mean \"this platform or this request does not take keyless reads\": ask again with the key. */\nconst KEYLESS_REFUSALS: ReadonlySet<number> = new Set([400, 401, 403]);\n\nexport class YNSProvider {\n\t#config: CommerceConfig;\n\t#logger = getLogger(\"YNSProvider\");\n\t/** `null` once keyless reads are off for this process: opted out, refused, or no store id. */\n\t#storeId: Promise<string | null> | null = null;\n\n\tconstructor(config: CommerceConfig = {}) {\n\t\tconst token = config.token ?? env.YNS_API_KEY;\n\t\tconst isStaging = env.YNS_API_KEY?.startsWith(\"sk-s-\");\n\n\t\tif (!token) {\n\t\t\tthrow new Error(\n\t\t\t\t\"YNS API key is required. Set YNS_API_KEY environment variable or pass token in config.\",\n\t\t\t);\n\t\t}\n\t\tconst endpoint = config.endpoint ?? (isStaging ? \"https://yns.cx\" : \"https://yns.store\");\n\n\t\tthis.#config = { version: \"v1\", ...config, token, endpoint };\n\n\t\tthis.#logger.debug(\"YNSProvider initialized\", {\n\t\t\tendpoint,\n\t\t\ttoken: config.token ? `from config` : \"from env\",\n\t\t});\n\t}\n\n\tasync #restRequest<T>(\n\t\tpathname: `/${string}`,\n\t\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" = \"GET\",\n\t\tbody?: unknown,\n\t): Promise<T> {\n\t\tconst response = await this.#fetchJson(pathname, method, body);\n\t\treturn this.#parseResponse<T>(response, pathname, method);\n\t}\n\n\t/**\n\t * Like {@link #restRequest} but resolves to `null` on a 404 response. For lookups where\n\t * \"not found\" is an expected outcome (e.g. ticket access codes answered with a uniform 404).\n\t */\n\tasync #restRequestNullable<T>(pathname: `/${string}`): Promise<T | null> {\n\t\tconst response = await this.#fetchJson(pathname, \"GET\");\n\t\tif (response.status === 404) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.#parseResponse<T>(response, pathname, \"GET\");\n\t}\n\n\t/**\n\t * The store id for keyless reads: from the config, then the environment, then one keyed\n\t * `GET /me`, asked once per process. Any failure leaves every request keyed, as before.\n\t */\n\t#resolveStoreId(): Promise<string | null> {\n\t\tconst configured = this.#config.store;\n\t\tif (configured === false) return Promise.resolve(null);\n\t\tthis.#storeId ??= (async () => {\n\t\t\tconst known = configured ?? env.YNS_STORE_ID;\n\t\t\tif (known) return known;\n\t\t\ttry {\n\t\t\t\tconst response = await this.#fetchKeyed(\"/me\", \"GET\");\n\t\t\t\tif (!response.ok) return null;\n\t\t\t\tconst me: { store?: { id?: unknown } } = await response.json();\n\t\t\t\treturn typeof me.store?.id === \"string\" ? me.store.id : null;\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t})();\n\t\treturn this.#storeId;\n\t}\n\n\tasync #fetchJson(\n\t\tpathname: `/${string}`,\n\t\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n\t\tbody?: unknown,\n\t): Promise<Response> {\n\t\tif (method !== \"GET\") return this.#fetchKeyed(pathname, method, body);\n\n\t\tconst storeId = await this.#resolveStoreId();\n\t\tconst keyless = storeId ? keylessPathname(pathname, storeId) : null;\n\t\tif (!keyless) return this.#fetchKeyed(pathname, method);\n\n\t\tconst logger = this.#logger.getLogger(\"#restRequest\");\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${keyless}`;\n\t\tlogger.debug(`Making keyless GET request to YNS API: ${endpoint}`);\n\t\tconst response = await fetch(endpoint, { method, headers: { \"Content-Type\": \"application/json\" } });\n\t\tif (!KEYLESS_REFUSALS.has(response.status)) return response;\n\n\t\t// A platform that still wants the key answers 401 to every keyless read, so stop trying.\n\t\tif (response.status !== 400) this.#storeId = Promise.resolve(null);\n\t\tlogger.debug(`Keyless request answered ${response.status}, asking again with the key`);\n\t\treturn this.#fetchKeyed(pathname, method);\n\t}\n\n\tasync #fetchKeyed(\n\t\tpathname: `/${string}`,\n\t\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n\t\tbody?: unknown,\n\t): Promise<Response> {\n\t\tconst logger = this.#logger.getLogger(\"#restRequest\");\n\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${pathname}`;\n\t\tlogger.debug(`Making ${method} request to YNS API: ${endpoint}`);\n\t\treturn fetch(endpoint, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${this.#config.token}`,\n\t\t\t},\n\t\t\tbody: body ? JSON.stringify(body) : undefined,\n\t\t});\n\t}\n\n\tasync #parseResponse<T>(response: Response, pathname: `/${string}`, method: string): Promise<T> {\n\t\tconst logger = this.#logger.getLogger(\"#restRequest\");\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${pathname}`;\n\n\t\tif (!response.ok) {\n\t\t\t// Handle different error types\n\t\t\tconst contentType = response.headers.get(\"content-type\");\n\t\t\tlet errorMessage = `YNS REST request failed: ${method} ${endpoint} ${response.status} ${response.statusText}`;\n\n\t\t\tif (contentType?.includes(\"application/json\")) {\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = await response.json();\n\t\t\t\t\terrorMessage = errorData.error || errorData.message || errorMessage;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to parse YNS error response as JSON\", error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst errorText = await response.text();\n\t\t\t\tlogger.error(\n\t\t\t\t\t`YNS API request failed: ${response.status} ${response.statusText}`,\n\t\t\t\t\terrorMessage,\n\t\t\t\t\terrorText,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\n\t\t// Check if response is JSON before parsing\n\t\tconst contentType = response.headers.get(\"content-type\");\n\t\tif (!contentType?.includes(\"application/json\")) {\n\t\t\tthrow new Error(`YNS API returned ${contentType} instead of JSON for ${pathname}`);\n\t\t}\n\n\t\treturn response.json();\n\t}\n\n\tasync #multipartRequest<T>(pathname: `/${string}`, formData: FormData): Promise<T> {\n\t\tconst logger = this.#logger.getLogger(\"#multipartRequest\");\n\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${pathname}`;\n\t\tlogger.debug(`Making multipart POST to YNS API: ${endpoint}`);\n\t\tconst response = await fetch(endpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.#config.token}`,\n\t\t\t},\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst contentType = response.headers.get(\"content-type\");\n\t\t\tlet errorMessage = `YNS REST request failed: POST ${endpoint} ${response.status} ${response.statusText}`;\n\n\t\t\tif (contentType?.includes(\"application/json\")) {\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = await response.json();\n\t\t\t\t\terrorMessage = errorData.error || errorData.message || errorMessage;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to parse YNS error response as JSON\", error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst errorText = await response.text();\n\t\t\t\tlogger.error(\n\t\t\t\t\t`YNS API request failed: ${response.status} ${response.statusText}`,\n\t\t\t\t\terrorMessage,\n\t\t\t\t\terrorText,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\n\t\tconst contentType = response.headers.get(\"content-type\");\n\t\tif (!contentType?.includes(\"application/json\")) {\n\t\t\tthrow new Error(`YNS API returned ${contentType} instead of JSON for ${pathname}`);\n\t\t}\n\n\t\treturn response.json();\n\t}\n\n\tasync meGet(): Promise<APIMeGetResult> {\n\t\tconst logger = this.#logger.getLogger(\"meGet\");\n\t\tlogger.debug(\"Fetching my information\");\n\n\t\tconst pathname = `/me` as const;\n\t\tconst result = await this.#restRequest<APIMeGetResult>(pathname);\n\t\tlogger.debug(\"Received my information:\", result);\n\t\treturn result;\n\t}\n\n\tasync socialsGet(): Promise<APISocialsGetResult> {\n\t\tconst logger = this.#logger.getLogger(\"socialsGet\");\n\t\tlogger.debug(\"Fetching store social links\");\n\n\t\tconst pathname = `/socials` as const;\n\t\tconst result = await this.#restRequest<APISocialsGetResult>(pathname);\n\t\tlogger.debug(\"Received store social links:\", result);\n\t\treturn result;\n\t}\n\n\t// Brands ---------------------------------------------------------------\n\n\tasync brandBrowse(params: APIBrandsBrowseQueryParams = {}): Promise<APIBrandsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/brands${searchParams}` as const;\n\t\treturn this.#restRequest<APIBrandsBrowseResult>(pathname);\n\t}\n\n\tasync brandGet(params: APIBrandGetByIdParams): Promise<APIBrandGetByIdResult | null> {\n\t\tconst pathname = `/brands/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBrandGetByIdResult>(pathname);\n\t}\n\n\tasync brandCreate(body: APIBrandCreateBody): Promise<APIBrandCreateResult> {\n\t\treturn this.#restRequest<APIBrandCreateResult>(\"/brands\", \"POST\", body);\n\t}\n\n\tasync brandUpdate(params: APIBrandGetByIdParams, body: APIBrandUpdateBody): Promise<APIBrandUpdateResult> {\n\t\tconst pathname = `/brands/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBrandUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync brandDelete(params: APIBrandGetByIdParams): Promise<APIBrandDeleteResult> {\n\t\tconst pathname = `/brands/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBrandDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync brandAssignProducts(\n\t\tparams: APIBrandGetByIdParams,\n\t\tbody: APIBrandAssignProductsBody,\n\t): Promise<APIBrandAssignProductsResult> {\n\t\tconst pathname = `/brands/${params.idOrSlug}/products` as const;\n\t\treturn this.#restRequest<APIBrandAssignProductsResult>(pathname, \"POST\", body);\n\t}\n\n\t// Order refunds --------------------------------------------------------\n\n\tasync orderRefundsBrowse(\n\t\tparams: APIOrderRefundsParams & APIOrderRefundsBrowseQueryParams,\n\t): Promise<APIOrderRefundsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/orders/${params.id}/refunds${searchParams}` as const;\n\t\treturn this.#restRequest<APIOrderRefundsBrowseResult>(pathname);\n\t}\n\n\tasync orderRefundGet(params: APIOrderRefundGetParams): Promise<APIOrderRefundGetResult | null> {\n\t\tconst pathname = `/orders/${params.id}/refunds/${params.refundId}` as const;\n\t\treturn this.#restRequest<APIOrderRefundGetResult>(pathname);\n\t}\n\n\t// Product bulk ---------------------------------------------------------\n\n\tasync productBatch(body: APIProductBatchBody): Promise<APIProductBatchResult> {\n\t\treturn this.#restRequest<APIProductBatchResult>(\"/products/batch\", \"POST\", body);\n\t}\n\n\t// Cart -----------------------------------------------------------------\n\n\tasync cartDelete(params: { cartId: string }): Promise<APICartDeleteResult> {\n\t\tconst pathname = `/carts/${params.cartId}` as const;\n\t\treturn this.#restRequest<APICartDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync productBrowse(params: APIProductsBrowseQueryParams): Promise<APIProductsBrowseResult> {\n\t\tconst logger = this.#logger.getLogger(\"productBrowse\");\n\t\tlogger.debug(\"Browsing products with params:\", params);\n\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.category) queryParams.append(\"category\", params.category);\n\t\tif (params.collection) queryParams.append(\"collection\", params.collection);\n\t\tif (params.brand) queryParams.append(\"brand\", params.brand);\n\t\tif (params.priceMin !== undefined) queryParams.append(\"priceMin\", params.priceMin.toString());\n\t\tif (params.priceMax !== undefined) queryParams.append(\"priceMax\", params.priceMax.toString());\n\t\tif (params.vts) queryParams.append(\"vts\", params.vts);\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.orderBy) queryParams.append(\"orderBy\", params.orderBy);\n\t\tif (params.orderDirection) queryParams.append(\"orderDirection\", params.orderDirection);\n\t\t// Prices come back in this currency, with its own `…Gross` twins; `lang` picks the translation.\n\t\tif (params.currency) queryParams.append(\"currency\", params.currency);\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\t// Custom fields: `filter` narrows by their values (`product.custom.material:wool,silk;\n\t\t// variant.custom.weight:100..300`), `include` adds the values of every product and\n\t\t// variant to the list, `metafields: \"all\"` adds private fields (needs a key with\n\t\t// `catalog:write`; refused without a key).\n\t\tif (params.filter) queryParams.append(\"filter\", params.filter);\n\t\tif (params.include) queryParams.append(\"include\", params.include);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/products${searchParams}` as const;\n\t\tlogger.debug(\"Constructed pathname:\", pathname);\n\t\tconst result = await this.#restRequest<APIProductsBrowseResult>(pathname);\n\t\tlogger.debug(\"Received product browse result:\", { meta: result.meta });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Available storefront filter facets for the store: price bounds, variant\n\t * types/values, active categories, collections and brands, and the filterable custom\n\t * fields (`metafields`, present only when the store has any) with their options or\n\t * number range. Pair with `productBrowse`'s `collection`, `brand`, `priceMin`/`priceMax`,\n\t * `vts` and `filter` params to build a filter UI. `lang` translates field names and\n\t * option labels.\n\t */\n\tasync productFilters(params: APIProductFiltersQueryParams = {}): Promise<APIProductFiltersResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/products/filters${searchParams}` as const;\n\t\treturn this.#restRequest<APIProductFiltersResult>(pathname);\n\t}\n\n\t/**\n\t * A single product by id or slug. `lang` selects the translation (and resolves a translated\n\t * slug); `currency` prices the variants in that currency, twins included. The product and\n\t * its variants carry their custom fields under `metafields`; `metafields: \"all\"` adds the\n\t * private ones (needs a key with `catalog:write`; refused without a key).\n\t */\n\tasync productGet(\n\t\tparams: APIProductGetByIdParams & APIProductGetByIdQueryParams,\n\t): Promise<APIProductGetByIdResult | null> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tif (params.currency) queryParams.append(\"currency\", params.currency);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/products/${params.idOrSlug}${searchParams}` as const;\n\n\t\tconst result = await this.#restRequest<APIProductGetByIdResult>(pathname);\n\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync orderBrowse(params: APIOrdersBrowseQueryParams): Promise<APIOrdersBrowseResult> {\n\t\tconst logger = this.#logger.getLogger(\"orderBrowse\");\n\t\tlogger.debug(\"Browsing orders with params:\", params);\n\n\t\tconst queryParams = new URLSearchParams();\n\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/orders${searchParams}` as const;\n\t\tlogger.debug(\"Constructed pathname:\", pathname);\n\t\tconst result = await this.#restRequest<APIOrdersBrowseResult>(pathname);\n\t\tlogger.debug(\"Received orders browse result:\", { meta: result.meta });\n\t\treturn result;\n\t}\n\n\tasync orderGet(params: APIOrderGetByIdParams): Promise<APIOrderGetByIdResult | null> {\n\t\tconst pathname = `/orders/${params.id}` as const;\n\n\t\tconst result = await this.#restRequest<APIOrderGetByIdResult>(pathname);\n\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// @todo\n\t// async cartAdd(params: APICartAddBody): Promise<APICartAddResult> {\n\t// \tconst body = {\n\t// \t\tvariantId: params.variantId,\n\t// \t\tcartId: params.cartId,\n\t// \t\tquantity: params.quantity,\n\t// \t\tsubscriptionId: params.subscriptionId,\n\t// \t};\n\n\t// \tconst result = await this.#restRequest<APICartCreateResult>(\"/carts\", \"PATCH\", body);\n\t// \treturn result;\n\t// }\n\n\tasync cartUpsert(body: APICartCreateBody): Promise<APICartCreateResult> {\n\t\tconst result = await this.#restRequest<APICartCreateResult>(\"/carts\", \"POST\", body);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Add a configured bundle to the cart in one call. `selections` are the customer's per-group\n\t * choices; always-included (forced) items may be omitted — the server fills them in and\n\t * validates the rest against the bundle's groups. Omit `cartId` to start a new cart. The\n\t * returned cart prices the bundle line (componentTotal × (1 − discount)).\n\t */\n\tasync cartAddBundle(params: {\n\t\tbundleId: string;\n\t\tselections: NonNullable<APICartCreateBody[\"selections\"]>;\n\t\tcartId?: string;\n\t\tcurrency?: string;\n\t}): Promise<APICartCreateResult> {\n\t\tconst body: APICartCreateBody = {\n\t\t\tbundleId: params.bundleId,\n\t\t\tselections: params.selections,\n\t\t\t...(params.cartId ? { cartId: params.cartId } : {}),\n\t\t\t...(params.currency ? { currency: params.currency } : {}),\n\t\t};\n\t\tconst result = await this.#restRequest<APICartCreateResult>(\"/carts\", \"POST\", body);\n\t\treturn result;\n\t}\n\n\tasync cartRemoveItem(params: { cartId: string; variantId: string }): Promise<APICartGetResult> {\n\t\tconst pathname = `/carts/${params.cartId}/line-items/${params.variantId}` as const;\n\t\treturn this.#restRequest<APICartGetResult>(pathname, \"DELETE\");\n\t}\n\n\tasync cartGet(params: { cartId: string }): Promise<APICartGetResult | null> {\n\t\tconst pathname = `/carts/${params.cartId}` as const;\n\t\tconst result = await this.#restRequest<APICartGetResult>(pathname);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Validate and attach a coupon to the cart. Failures surface as an ApiError with\n\t * status 422 and a machine-readable `reason` (couponNotFound, couponHasExpired,\n\t * couponMaxUsesReached, couponIsNotValidYet, couponMinProductCountNotMet,\n\t * couponMaxProductCountExceeded, couponIsNotApplicable). Returns the updated cart.\n\t */\n\tasync cartCouponApply(params: { cartId: string; code: string }): Promise<APICartCouponApplyResult> {\n\t\tconst pathname = `/carts/${params.cartId}/coupon` as const;\n\t\treturn this.#restRequest<APICartCouponApplyResult>(pathname, \"POST\", { code: params.code });\n\t}\n\n\t/** Detach the applied coupon from the cart, if any. */\n\tasync cartCouponRemove(params: { cartId: string }): Promise<APICartCouponRemoveResult> {\n\t\tconst pathname = `/carts/${params.cartId}/coupon` as const;\n\t\treturn this.#restRequest<APICartCouponRemoveResult>(pathname, \"DELETE\");\n\t}\n\n\tasync couponBrowse(params: APICouponsBrowseQueryParams = {}): Promise<APICouponsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/coupons${searchParams}` as const;\n\n\t\treturn this.#restRequest<APICouponsBrowseResult>(pathname);\n\t}\n\n\t/** Look up a coupon by its UUID or its code. Resolves to `null` when not found. */\n\tasync couponGet(params: APICouponGetByIdParams): Promise<APICouponGetByIdResult | null> {\n\t\tconst pathname = `/coupons/${params.idOrCode}` as const;\n\t\treturn this.#restRequestNullable<APICouponGetByIdResult>(pathname);\n\t}\n\n\tasync couponCreate(body: APICouponCreateBody): Promise<APICouponCreateResult> {\n\t\treturn this.#restRequest<APICouponCreateResult>(\"/coupons\", \"POST\", body);\n\t}\n\n\tasync couponUpdate(\n\t\tparams: APICouponGetByIdParams,\n\t\tbody: APICouponUpdateBody,\n\t): Promise<APICouponUpdateResult> {\n\t\tconst pathname = `/coupons/${params.idOrCode}` as const;\n\t\treturn this.#restRequest<APICouponUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync couponDelete(params: APICouponGetByIdParams): Promise<APICouponDeleteResult> {\n\t\tconst pathname = `/coupons/${params.idOrCode}` as const;\n\t\treturn this.#restRequest<APICouponDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t/** List the store's support cases (merchant ↔ YNS support), newest activity first. */\n\tasync supportCaseBrowse(\n\t\tparams: APISupportCasesBrowseQueryParams = {},\n\t): Promise<APISupportCasesBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.status) queryParams.append(\"status\", params.status);\n\t\tif (params.severity) queryParams.append(\"severity\", params.severity);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/support-cases${searchParams}` as const;\n\n\t\treturn this.#restRequest<APISupportCasesBrowseResult>(pathname);\n\t}\n\n\t/**\n\t * Look up a case with its message thread by UUID or case number (\"123\" or \"000123\").\n\t * Resolves to `null` when not found. Internal YNS notes are never included.\n\t */\n\tasync supportCaseGet(params: APISupportCaseGetParams): Promise<APISupportCaseGetResult | null> {\n\t\tconst pathname = `/support-cases/${params.idOrNumber}` as const;\n\t\treturn this.#restRequestNullable<APISupportCaseGetResult>(pathname);\n\t}\n\n\t/** Open a support case with the YNS team. Omit `subject` to have one generated from the description. */\n\tasync supportCaseCreate(body: APISupportCaseCreateBody): Promise<APISupportCaseCreateResult> {\n\t\treturn this.#restRequest<APISupportCaseCreateResult>(\"/support-cases\", \"POST\", body);\n\t}\n\n\t/** Close (`status: \"closed\"`) or reopen (`status: \"open\"`) a case. */\n\tasync supportCaseUpdate(\n\t\tparams: APISupportCaseGetParams,\n\t\tbody: APISupportCaseUpdateBody,\n\t): Promise<APISupportCaseUpdateResult> {\n\t\tconst pathname = `/support-cases/${params.idOrNumber}` as const;\n\t\treturn this.#restRequest<APISupportCaseUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t/** Add a merchant-side reply to the case thread; replying reopens a closed or answered case. */\n\tasync supportCaseReply(\n\t\tparams: APISupportCaseGetParams,\n\t\tbody: APISupportCaseMessageCreateBody,\n\t): Promise<APISupportCaseMessageCreateResult> {\n\t\tconst pathname = `/support-cases/${params.idOrNumber}/messages` as const;\n\t\treturn this.#restRequest<APISupportCaseMessageCreateResult>(pathname, \"POST\", body);\n\t}\n\n\tasync collectionGet(params: APICollectionGetByIdParams): Promise<APICollectionGetByIdResult | null> {\n\t\tconst pathname = `/collections/${params.idOrSlug}` as const;\n\n\t\tconst result = await this.#restRequest<APICollectionGetByIdResult>(pathname);\n\t\treturn result;\n\t}\n\n\tasync collectionBrowse(params: APICollectionsBrowseQueryParams): Promise<APICollectionsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.group) queryParams.append(\"group\", params.group);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/collections${searchParams}` as const;\n\n\t\tconst result = await this.#restRequest<APICollectionsBrowseResult>(pathname);\n\t\treturn result;\n\t}\n\n\tasync collectionCreate(body: APICollectionCreateBody): Promise<APICollectionCreateResult> {\n\t\treturn this.#restRequest<APICollectionCreateResult>(\"/collections\", \"POST\", body);\n\t}\n\n\tasync collectionUpdate(\n\t\tparams: APICollectionGetByIdParams,\n\t\tbody: APICollectionUpdateBody,\n\t): Promise<APICollectionUpdateResult> {\n\t\tconst pathname = `/collections/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICollectionUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync collectionDelete(params: APICollectionGetByIdParams): Promise<APICollectionDeleteResult> {\n\t\tconst pathname = `/collections/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICollectionDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync collectionImportMemberships(\n\t\tbody: APICollectionImportMembershipsBody,\n\t): Promise<APICollectionImportMembershipsResult> {\n\t\tconst formData = new FormData();\n\t\tformData.append(\"file\", body.file);\n\t\treturn this.#multipartRequest<APICollectionImportMembershipsResult>(\n\t\t\t\"/collections/import-memberships\",\n\t\t\tformData,\n\t\t);\n\t}\n\n\tasync categoryGet(params: APICategoryGetByIdParams): Promise<APICategoryGetByIdResult | null> {\n\t\tconst pathname = `/categories/${params.idOrSlug}` as const;\n\n\t\tconst result = await this.#restRequest<APICategoryGetByIdResult>(pathname);\n\t\treturn result;\n\t}\n\n\tasync categoriesBrowse(params: APICategoriesBrowseQueryParams): Promise<APICategoriesBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/categories${searchParams}` as const;\n\n\t\tconst result = await this.#restRequest<APICategoriesBrowseResult>(pathname);\n\t\treturn result;\n\t}\n\n\t// ============================================\n\t// Posts\n\t// ============================================\n\n\tasync postBrowse(params: APIPostsBrowseQueryParams = {}): Promise<APIPostsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.tag) queryParams.append(\"tag\", params.tag);\n\t\tif (params.categoryId) queryParams.append(\"categoryId\", params.categoryId);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/posts${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIPostsBrowseResult>(pathname);\n\t}\n\n\tasync postGet(params: APIPostGetByIdParams): Promise<APIPostGetByIdResult | null> {\n\t\tconst pathname = `/posts/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIPostGetByIdResult>(pathname);\n\t}\n\n\tasync postCreate(body: APIPostCreateBody): Promise<APIPostCreateResult> {\n\t\treturn this.#restRequest<APIPostCreateResult>(\"/posts\", \"POST\", body);\n\t}\n\n\tasync postUpdate(params: APIPostGetByIdParams, body: APIPostUpdateBody): Promise<APIPostUpdateResult> {\n\t\tconst pathname = `/posts/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIPostUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync postDelete(params: APIPostGetByIdParams): Promise<APIPostDeleteResult> {\n\t\tconst pathname = `/posts/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIPostDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync postCommentsBrowse(\n\t\tparams: APIPostGetByIdParams,\n\t\tqueryParams: APIPostCommentsBrowseQueryParams = {},\n\t): Promise<APIPostCommentsBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.offset) urlParams.append(\"offset\", queryParams.offset.toString());\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/posts/${params.idOrSlug}/comments${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIPostCommentsBrowseResult>(pathname);\n\t}\n\n\tasync postCommentCreate(\n\t\tparams: APIPostGetByIdParams,\n\t\tbody: APIPostCommentCreateBody,\n\t): Promise<APIPostCommentCreateResult> {\n\t\tconst pathname = `/posts/${params.idOrSlug}/comments` as const;\n\t\treturn this.#restRequest<APIPostCommentCreateResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Blog Categories\n\t// ============================================\n\n\tasync blogCategoryBrowse(\n\t\tparams: APIBlogCategoriesBrowseQueryParams = {},\n\t): Promise<APIBlogCategoriesBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/blog-categories${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIBlogCategoriesBrowseResult>(pathname);\n\t}\n\n\tasync blogCategoryGet(params: APIBlogCategoryGetByIdParams): Promise<APIBlogCategoryGetByIdResult | null> {\n\t\tconst pathname = `/blog-categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBlogCategoryGetByIdResult>(pathname);\n\t}\n\n\tasync blogCategoryCreate(body: APIBlogCategoryCreateBody): Promise<APIBlogCategoryCreateResult> {\n\t\treturn this.#restRequest<APIBlogCategoryCreateResult>(\"/blog-categories\", \"POST\", body);\n\t}\n\n\tasync blogCategoryUpdate(\n\t\tparams: APIBlogCategoryGetByIdParams,\n\t\tbody: APIBlogCategoryUpdateBody,\n\t): Promise<APIBlogCategoryUpdateResult> {\n\t\tconst pathname = `/blog-categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBlogCategoryUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync blogCategoryDelete(params: APIBlogCategoryGetByIdParams): Promise<APIBlogCategoryDeleteResult> {\n\t\tconst pathname = `/blog-categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBlogCategoryDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Customers\n\t// ============================================\n\n\tasync customerBrowse(params: APICustomersBrowseQueryParams = {}): Promise<APICustomersBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.search) queryParams.append(\"search\", params.search);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/customers${searchParams}` as const;\n\n\t\treturn this.#restRequest<APICustomersBrowseResult>(pathname);\n\t}\n\n\tasync customerGet(params: APICustomerGetByIdParams): Promise<APICustomerGetByIdResult | null> {\n\t\tconst pathname = `/customers/${params.id}` as const;\n\t\treturn this.#restRequest<APICustomerGetByIdResult>(pathname);\n\t}\n\n\tasync customerUpdate(\n\t\tparams: APICustomerGetByIdParams,\n\t\tbody: APICustomerUpdateBody,\n\t): Promise<APICustomerUpdateResult> {\n\t\tconst pathname = `/customers/${params.id}` as const;\n\t\treturn this.#restRequest<APICustomerUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync customerAddressCreate(\n\t\tparams: APICustomerGetByIdParams,\n\t\tbody: APICustomerAddressCreateBody,\n\t): Promise<APICustomerAddressCreateResult> {\n\t\tconst pathname = `/customers/${params.id}/addresses` as const;\n\t\treturn this.#restRequest<APICustomerAddressCreateResult>(pathname, \"POST\", body);\n\t}\n\n\tasync customerAddressDelete(params: { customerId: string; addressId: string }): Promise<void> {\n\t\tconst pathname = `/customers/${params.customerId}/addresses/${params.addressId}` as const;\n\t\tawait this.#restRequest<unknown>(pathname, \"DELETE\");\n\t}\n\n\tasync customerOrdersBrowse(\n\t\tparams: APICustomerGetByIdParams,\n\t\tqueryParams: APICustomerOrdersBrowseQueryParams = {},\n\t): Promise<APICustomerOrdersBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.offset) urlParams.append(\"offset\", queryParams.offset.toString());\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/customers/${params.id}/orders${searchParams}` as const;\n\n\t\treturn this.#restRequest<APICustomerOrdersBrowseResult>(pathname);\n\t}\n\n\t// ============================================\n\t// Inventory\n\t// ============================================\n\n\tasync inventoryBrowse(params: APIInventoryBrowseQueryParams = {}): Promise<APIInventoryBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.cursor) queryParams.append(\"cursor\", params.cursor);\n\t\tif (params.lowStock !== undefined) queryParams.append(\"lowStock\", params.lowStock.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/inventory${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIInventoryBrowseResult>(pathname);\n\t}\n\n\tasync inventoryAdjust(sku: string, body: APIInventoryAdjustBody): Promise<APIInventoryAdjustResult> {\n\t\tconst pathname = `/inventory/${encodeURIComponent(sku)}/adjust` as const;\n\t\treturn this.#restRequest<APIInventoryAdjustResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Variants\n\t// ============================================\n\n\tasync variantGet(params: APIVariantGetByIdParams): Promise<APIVariantGetByIdResult | null> {\n\t\tconst pathname = `/variants/${params.idOrSku}` as const;\n\t\treturn this.#restRequest<APIVariantGetByIdResult>(pathname);\n\t}\n\n\tasync variantUpdate(\n\t\tparams: APIVariantGetByIdParams,\n\t\tbody: APIVariantUpdateBody,\n\t): Promise<APIVariantUpdateResult> {\n\t\tconst pathname = `/variants/${params.idOrSku}` as const;\n\t\treturn this.#restRequest<APIVariantUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync variantDelete(params: APIVariantGetByIdParams): Promise<void> {\n\t\tconst pathname = `/variants/${params.idOrSku}` as const;\n\t\tawait this.#restRequest<unknown>(pathname, \"DELETE\");\n\t}\n\n\tasync variantCreate(productId: string, body: APIVariantCreateBody): Promise<APIVariantCreateResult> {\n\t\tconst pathname = `/products/${productId}/variants` as const;\n\t\treturn this.#restRequest<APIVariantCreateResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Subscribers\n\t// ============================================\n\n\tasync subscriberCreate(body: APISubscriberCreateBody): Promise<APISubscriberCreateResult> {\n\t\treturn this.#restRequest<APISubscriberCreateResult>(\"/subscribers\", \"POST\", body);\n\t}\n\n\tasync subscriberDelete(email: string): Promise<APISubscriberDeleteResult> {\n\t\tconst pathname = `/subscribers?email=${encodeURIComponent(email)}` as const;\n\t\treturn this.#restRequest<APISubscriberDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Contact Messages\n\t// ============================================\n\n\tasync contactMessageCreate(body: APIContactMessageCreateBody): Promise<APIContactMessageCreateResult> {\n\t\treturn this.#restRequest<APIContactMessageCreateResult>(\"/contact-messages\", \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Product mutations\n\t// ============================================\n\n\tasync productCreate(body: APIProductCreateBody): Promise<APIProductCreateResult> {\n\t\treturn this.#restRequest<APIProductCreateResult>(\"/products\", \"POST\", body);\n\t}\n\n\tasync productUpdate(\n\t\tparams: APIProductGetByIdParams,\n\t\tbody: APIProductUpdateBody,\n\t): Promise<APIProductUpdateResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIProductUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync productDelete(params: APIProductGetByIdParams): Promise<APIProductDeleteResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIProductDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Custom fields (metafields)\n\t// ============================================\n\t//\n\t// A field is defined once per store (name, kind of value, products or variants) and each\n\t// product or variant then holds its own value under `metafields`. Values are written with\n\t// the product or variant (`productCreate`, `productUpdate`, `variantCreate`,\n\t// `variantUpdate`); the methods here manage the fields and their translations. Variant\n\t// `attributes` keep coming back, derived from the variant's fields.\n\n\t/** The store's fields, in display order. Archived ones only with `includeArchived: \"true\"`. */\n\tasync metafieldDefinitionBrowse(\n\t\tparams: APIMetafieldDefinitionsBrowseQueryParams = {},\n\t): Promise<APIMetafieldDefinitionsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.ownerType) queryParams.append(\"ownerType\", params.ownerType);\n\t\tif (params.includeArchived) queryParams.append(\"includeArchived\", params.includeArchived);\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/metafield-definitions${searchParams}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionsBrowseResult>(pathname);\n\t}\n\n\t/** One field, by id or by its address `<ownerType>.<namespace>.<key>`, e.g. `product.custom.material`. */\n\tasync metafieldDefinitionGet(\n\t\tparams: APIMetafieldDefinitionParams & APIMetafieldDefinitionGetQueryParams,\n\t): Promise<APIMetafieldDefinitionGetResult | null> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}${searchParams}` as const;\n\t\treturn this.#restRequestNullable<APIMetafieldDefinitionGetResult>(pathname);\n\t}\n\n\tasync metafieldDefinitionCreate(\n\t\tbody: APIMetafieldDefinitionCreateBody,\n\t): Promise<APIMetafieldDefinitionCreateResult> {\n\t\treturn this.#restRequest<APIMetafieldDefinitionCreateResult>(\"/metafield-definitions\", \"POST\", body);\n\t}\n\n\t/** Name, description, switches, options, limits. The kind of value cannot change here. */\n\tasync metafieldDefinitionUpdate(\n\t\tparams: APIMetafieldDefinitionParams,\n\t\tbody: APIMetafieldDefinitionUpdateBody,\n\t): Promise<APIMetafieldDefinitionUpdateResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t/**\n\t * Archive: the field leaves the admin, the storefront and the API, every value is kept.\n\t * `metafieldDefinitionRestore` brings it back; `metafieldDefinitionDelete` removes it for good.\n\t */\n\tasync metafieldDefinitionArchive(\n\t\tparams: APIMetafieldDefinitionParams,\n\t): Promise<APIMetafieldDefinitionArchiveResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionArchiveResult>(pathname, \"DELETE\");\n\t}\n\n\tasync metafieldDefinitionRestore(\n\t\tparams: APIMetafieldDefinitionParams,\n\t): Promise<APIMetafieldDefinitionRestoreResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/restore` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionRestoreResult>(pathname, \"POST\");\n\t}\n\n\t/**\n\t * Delete an ARCHIVED field for good, with every value and translation it holds. `confirm`\n\t * repeats the field's key and `expectedValueCount` the number of values it holds (a 409\n\t * tells the real count); both guard against deleting the wrong field.\n\t */\n\tasync metafieldDefinitionDelete(\n\t\tparams: APIMetafieldDefinitionParams,\n\t\tbody: APIMetafieldDefinitionDeleteBody,\n\t): Promise<APIMetafieldDefinitionDeleteResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/purge` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionDeleteResult>(pathname, \"POST\", body);\n\t}\n\n\t/**\n\t * What turning a text field into a choice would do: every distinct value in use and a\n\t * suggested grouping into options. Hand the groups and the `planHash` to\n\t * `metafieldDefinitionConvertToChoice`.\n\t */\n\tasync metafieldDefinitionConversionPreview(\n\t\tparams: APIMetafieldDefinitionParams,\n\t): Promise<APIMetafieldDefinitionConversionPreviewResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/convert-to-choice` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionConversionPreviewResult>(pathname);\n\t}\n\n\t/** In place: the field keeps its key and id, each value becomes the option of its group. */\n\tasync metafieldDefinitionConvertToChoice(\n\t\tparams: APIMetafieldDefinitionParams,\n\t\tbody: APIMetafieldDefinitionConvertBody,\n\t): Promise<APIMetafieldDefinitionConvertResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/convert-to-choice` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionConvertResult>(pathname, \"POST\", body);\n\t}\n\n\t/** The field's name, description and option labels in one language. `null` clears a part. */\n\tasync metafieldDefinitionTranslationPut(\n\t\tparams: APIMetafieldDefinitionTranslationParams,\n\t\tbody: APIMetafieldDefinitionTranslationPutBody,\n\t): Promise<APIMetafieldDefinitionTranslationPutResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/translations/${params.locale}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionTranslationPutResult>(pathname, \"PUT\", body);\n\t}\n\n\t/** Translated values of a product's fields in one language. `value: null` removes one. */\n\tasync productMetafieldTranslationsPut(\n\t\tparams: APIProductMetafieldTranslationsPutParams,\n\t\tbody: APIMetafieldTranslationsPutBody,\n\t): Promise<APIProductMetafieldTranslationsPutResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}/metafields/translations/${params.locale}` as const;\n\t\treturn this.#restRequest<APIProductMetafieldTranslationsPutResult>(pathname, \"PUT\", body);\n\t}\n\n\t/** Translated values of a variant's fields in one language. `value: null` removes one. */\n\tasync variantMetafieldTranslationsPut(\n\t\tparams: APIVariantMetafieldTranslationsPutParams,\n\t\tbody: APIMetafieldTranslationsPutBody,\n\t): Promise<APIVariantMetafieldTranslationsPutResult> {\n\t\tconst pathname = `/variants/${params.idOrSku}/metafields/translations/${params.locale}` as const;\n\t\treturn this.#restRequest<APIVariantMetafieldTranslationsPutResult>(pathname, \"PUT\", body);\n\t}\n\n\t/**\n\t * Machine-translate the field values that have no translation yet. Translations a person\n\t * wrote are never replaced. With `productIds` it runs right away and returns what it wrote;\n\t * without, it starts a background run over the whole catalogue (answered 202 with a `runId`).\n\t */\n\tasync metafieldsTranslateMissing(\n\t\tbody: APIMetafieldsTranslateMissingBody = {},\n\t): Promise<APIMetafieldsTranslateMissingResult> {\n\t\treturn this.#restRequest<APIMetafieldsTranslateMissingResult>(\n\t\t\t\"/metafields/translate-missing\",\n\t\t\t\"POST\",\n\t\t\tbody,\n\t\t);\n\t}\n\n\t// ============================================\n\t// Product Reviews\n\t// ============================================\n\n\tasync productReviewsBrowse(\n\t\tparams: APIProductGetByIdParams,\n\t\tqueryParams: APIProductReviewsBrowseQueryParams = {},\n\t): Promise<APIProductReviewsBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.offset) urlParams.append(\"offset\", queryParams.offset.toString());\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/products/${params.idOrSlug}/reviews${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIProductReviewsBrowseResult>(pathname);\n\t}\n\n\tasync productReviewCreate(\n\t\tparams: APIProductGetByIdParams,\n\t\tbody: APIProductReviewCreateBody,\n\t): Promise<APIProductReviewCreateResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}/reviews` as const;\n\t\treturn this.#restRequest<APIProductReviewCreateResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Events (products flagged `flags.event` with a single non-shippable ticket variant)\n\t// ============================================\n\n\tasync eventBrowse(params: APIEventsBrowseQueryParams = {}): Promise<APIEventsBrowseResult> {\n\t\tconst logger = this.#logger.getLogger(\"eventBrowse\");\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.offset !== undefined) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.limit !== undefined) queryParams.append(\"limit\", params.limit.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/events${searchParams}` as const;\n\t\tlogger.debug(\"Browsing events:\", pathname);\n\t\treturn this.#restRequest<APIEventsBrowseResult>(pathname);\n\t}\n\n\tasync eventGet(params: APIEventGetByIdParams): Promise<APIEventGetByIdResult> {\n\t\tconst pathname = `/events/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIEventGetByIdResult>(pathname);\n\t}\n\n\tasync eventCreate(body: APIEventCreateBody): Promise<APIEventCreateResult> {\n\t\treturn this.#restRequest<APIEventCreateResult>(\"/events\", \"POST\", body);\n\t}\n\n\tasync eventUpdate(params: APIEventGetByIdParams, body: APIEventUpdateBody): Promise<APIEventUpdateResult> {\n\t\tconst pathname = `/events/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIEventUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync eventAttendeesBrowse(params: APIEventGetByIdParams): Promise<APIEventAttendeesBrowseResult> {\n\t\tconst pathname = `/events/${params.idOrSlug}/attendees` as const;\n\t\treturn this.#restRequest<APIEventAttendeesBrowseResult>(pathname);\n\t}\n\n\t// ============================================\n\t// Tickets (no-login buyer/attendee access to purchased event tickets)\n\t// ============================================\n\n\t/**\n\t * Buyer ticket lookup: the order's 6-character access code plus the purchase email.\n\t * Resolves to `null` on mismatch — the API answers a uniform 404 for an unknown code,\n\t * an email that doesn't match, or an order without tickets.\n\t */\n\tasync ticketsGet(params: { code: string; email: string }): Promise<APITicketsGetResult | null> {\n\t\tconst logger = this.#logger.getLogger(\"ticketsGet\");\n\t\tconst queryParams = new URLSearchParams({ email: params.email });\n\t\tconst pathname = `/tickets/${encodeURIComponent(params.code)}?${queryParams}` as const;\n\t\tlogger.debug(\"Fetching ticket bundle:\", pathname);\n\t\treturn this.#restRequestNullable<APITicketsGetResult>(pathname);\n\t}\n\n\t/**\n\t * Buyer bulk-edit of attendee names/emails. The body carries the purchase email; seat\n\t * tokens not belonging to the order are silently ignored. Throws on code/email mismatch\n\t * (404) or when the order is cancelled/refunded (409).\n\t */\n\tasync ticketsUpdate(params: { code: string }, body: APITicketsUpdateBody): Promise<APITicketsUpdateResult> {\n\t\tconst pathname = `/tickets/${encodeURIComponent(params.code)}` as const;\n\t\treturn this.#restRequest<APITicketsUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t/**\n\t * View-only attendee ticket by per-seat token (the capability embedded in the attendee\n\t * link/QR). Resolves to `null` for an unknown token. Attendee details can only be edited\n\t * by the buyer via {@link ticketsUpdate} — attendee links must not escalate.\n\t */\n\tasync ticketAttendeeGet(params: { token: string }): Promise<APITicketAttendeeGetResult | null> {\n\t\tconst pathname = `/tickets/attendee/${encodeURIComponent(params.token)}` as const;\n\t\treturn this.#restRequestNullable<APITicketAttendeeGetResult>(pathname);\n\t}\n\n\t// ============================================\n\t// Category mutations\n\t// ============================================\n\n\tasync categoryCreate(body: APICategoryCreateBody): Promise<APICategoryCreateResult> {\n\t\treturn this.#restRequest<APICategoryCreateResult>(\"/categories\", \"POST\", body);\n\t}\n\n\tasync categoryUpdate(\n\t\tparams: APICategoryGetByIdParams,\n\t\tbody: APICategoryUpdateBody,\n\t): Promise<APICategoryUpdateResult> {\n\t\tconst pathname = `/categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICategoryUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync categoryDelete(params: APICategoryGetByIdParams): Promise<APICategoryDeleteResult> {\n\t\tconst pathname = `/categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICategoryDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Order mutations\n\t// ============================================\n\n\tasync orderUpdate(params: APIOrderGetByIdParams, body: APIOrderUpdateBody): Promise<APIOrderUpdateResult> {\n\t\tconst pathname = `/orders/${params.id}` as const;\n\t\treturn this.#restRequest<APIOrderUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t// ============================================\n\t// Legal Pages\n\t// ============================================\n\n\tasync legalPageBrowse(\n\t\tqueryParams: APILegalPagesBrowseQueryParams = {},\n\t): Promise<APILegalPagesBrowseResult> {\n\t\treturn this.request<APILegalPagesBrowseResult>(\"/legal-pages\", {\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync legalPageGet(\n\t\tkey: string,\n\t\tqueryParams: APILegalPageGetByPathQueryParams = {},\n\t): Promise<APILegalPageGetByPathResult> {\n\t\tconst normalized = key.startsWith(\"/\") ? key.slice(1) : key;\n\t\tconst pathname = `/legal-pages/${encodeURIComponent(normalized)}` as const;\n\t\treturn this.request<APILegalPageGetByPathResult>(pathname, {\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync legalPageCreate(\n\t\tbody: APILegalPageCreateBody,\n\t\tqueryParams: APILegalPageCreateQueryParams = {},\n\t): Promise<APILegalPageCreateResult> {\n\t\treturn this.request<APILegalPageCreateResult, APILegalPageCreateBody>(\"/legal-pages\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody,\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync legalPageUpdate(\n\t\tkey: string,\n\t\tbody: APILegalPageUpdateBody,\n\t\tqueryParams: APILegalPageUpdateQueryParams = {},\n\t): Promise<APILegalPageUpdateResult> {\n\t\tconst normalized = key.startsWith(\"/\") ? key.slice(1) : key;\n\t\tconst pathname = `/legal-pages/${encodeURIComponent(normalized)}` as const;\n\t\treturn this.request<APILegalPageUpdateResult, APILegalPageUpdateBody>(pathname, {\n\t\t\tmethod: \"PATCH\",\n\t\t\tbody,\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync search(params: APISearchQueryParams): Promise<APISearchResult> {\n\t\treturn this.request<APISearchResult>(\"/search\", {\n\t\t\tquery: params,\n\t\t});\n\t}\n\n\t// ============================================\n\t// Instaview\n\t// ============================================\n\n\tasync instaviewImagesBrowse(\n\t\tparams: APIInstaviewImagesBrowseParams,\n\t\tqueryParams: APIInstaviewImagesBrowseQueryParams = {},\n\t): Promise<APIInstaviewImagesBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.cursor) urlParams.append(\"cursor\", queryParams.cursor);\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/instaview/accounts/${params.handle}/images${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIInstaviewImagesBrowseResult>(pathname);\n\t}\n\n\t/**\n\t * Make a raw API request to any endpoint.\n\t * Use this for new API features not yet supported by typed methods.\n\t *\n\t * @example\n\t * // GET request (default method)\n\t * const webhooks = await provider.request<Webhook[]>('/webhooks');\n\t *\n\t * // POST with typed body\n\t * const webhook = await provider.request<Webhook, CreateWebhookBody>('/webhooks', {\n\t * method: 'POST',\n\t * body: { url: 'https://...' }\n\t * });\n\t *\n\t * // GET with query parameters\n\t * const products = await provider.request<Product[]>('/products', {\n\t * query: { limit: 10, category: 'shoes' }\n\t * });\n\t *\n\t * // Path parameters via template literals\n\t * const product = await provider.request<Product>(`/products/${id}`);\n\t */\n\tasync request<TResponse = unknown, TBody = unknown>(\n\t\tpathname: `/${string}`,\n\t\toptions?: {\n\t\t\tmethod?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n\t\t\tbody?: TBody;\n\t\t\tquery?: Record<string, string | number | boolean | null | undefined>;\n\t\t},\n\t) {\n\t\tconst queryEntries = options?.query\n\t\t\t? Object.entries(options.query).filter((entry): entry is [string, string | number | boolean] => {\n\t\t\t\t\tconst [, value] = entry;\n\t\t\t\t\treturn value !== null && value !== undefined;\n\t\t\t\t})\n\t\t\t: [];\n\t\tconst queryString =\n\t\t\tqueryEntries.length > 0 ? `?${new URLSearchParams(queryEntries.map(([k, v]) => [k, String(v)]))}` : \"\";\n\n\t\treturn this.#restRequest<TResponse>(`${pathname}${queryString}`, options?.method ?? \"GET\", options?.body);\n\t}\n}\n","import { YNSProvider } from \"./providers/yns\";\nimport type { CommerceConfig } from \"./types\";\n\nexport function Commerce(config: CommerceConfig = {}): YNSProvider {\n\treturn new YNSProvider(config);\n}\n"],"mappings":"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","names":["YNS_API_KEY","YNS_STORE_ID","env","KEYLESS_LISTS","KEYLESS_SINGLETONS","KEYLESS_DETAILS","NOT_A_RESOURCE","isKeylessPath","path","query","resource","idOrSlug","child","rest","keylessPathname","pathname","storeId","search","active","privateFields","sorted","a","aValue","b","bValue","keyless","LogLevel","strLogLevel","valueLogLevel","RESET","BLUE","GREEN","YELLOW","RED","TIME","DEBUG","OK","WARN","ERROR","PREFIX_TIME","PREFIX_DEBUG","PREFIX_OK","PREFIX_WARN","PREFIX_ERROR","getLogger","groupLabel","PREFIX","subGroupLabel","label","args","item","options","logger","KEYLESS_REFUSALS","YNSProvider","#config","#logger","getLogger","#storeId","config","token","env","isStaging","endpoint","#restRequest","pathname","method","body","response","#fetchJson","#parseResponse","#restRequestNullable","#resolveStoreId","configured","known","#fetchKeyed","me","storeId","keyless","keylessPathname","logger","contentType","errorMessage","errorData","error","errorText","#multipartRequest","formData","result","params","queryParams","searchParams","urlParams","sku","productId","email","key","normalized","options","queryEntries","entry","value","queryString","k","v","Commerce","config","YNSProvider"]}
|
|
1
|
+
{"version":3,"sources":["../src/env.ts","../src/keyless.ts","../src/logger.ts","../src/providers/yns.ts","../src/commerce.ts"],"sourcesContent":["const YNS_API_KEY = process.env.YNS_API_KEY;\nconst YNS_STORE_ID = process.env.YNS_STORE_ID;\n\nexport const env = {\n\tYNS_API_KEY,\n\tYNS_STORE_ID,\n};\n","/**\n * Catalog reads the platform also answers without an API key, so its CDN can keep the answer.\n * A request qualifies only when the keyless answer is the one the key would get.\n */\n\n/** `GET` paths that answer without a key. Lists also need `active=true`: without it a key sees inactive rows too. */\nconst KEYLESS_LISTS: ReadonlySet<string> = new Set([\"/products\", \"/collections\", \"/categories\", \"/brands\"]);\nconst KEYLESS_SINGLETONS: ReadonlySet<string> = new Set([\"/products/filters\", \"/legal-pages\"]);\nconst KEYLESS_DETAILS: ReadonlySet<string> = new Set([\n\t\"products\",\n\t\"collections\",\n\t\"categories\",\n\t\"brands\",\n\t\"legal-pages\",\n]);\n/** Second segments that are their own endpoints, not an id or slug. */\nconst NOT_A_RESOURCE: ReadonlySet<string> = new Set([\"batch\", \"import\", \"import-memberships\", \"filters\"]);\n\nconst isKeylessPath = (path: string, query: URLSearchParams): boolean => {\n\tif (KEYLESS_SINGLETONS.has(path)) return true;\n\tif (KEYLESS_LISTS.has(path)) return query.get(\"active\") === \"true\";\n\n\tconst [resource, idOrSlug, child, ...rest] = path.split(\"/\").slice(1);\n\tif (!resource || !idOrSlug || rest.length > 0 || NOT_A_RESOURCE.has(idOrSlug)) return false;\n\tif (child === undefined) return KEYLESS_DETAILS.has(resource);\n\treturn resource === \"products\" && child === \"reviews\";\n};\n\n/**\n * The keyless form of a `GET` pathname, or `null` when the request needs the key.\n *\n * `store` goes first and the other parameters are sorted, so two requests that mean the same\n * thing are one URL, and therefore one cached copy.\n */\nexport const keylessPathname = (pathname: `/${string}`, storeId: string): `/${string}` | null => {\n\tconst [path = \"\", search = \"\"] = pathname.split(\"?\");\n\tconst query = new URLSearchParams(search);\n\tconst active = query.get(\"active\");\n\t// Private custom fields are for keys with `catalog:write`: a keyless read is refused.\n\tconst privateFields = query.get(\"metafields\") === \"all\";\n\tif (\n\t\tquery.has(\"store\") ||\n\t\t(active !== null && active !== \"true\") ||\n\t\tprivateFields ||\n\t\t!isKeylessPath(path, query)\n\t) {\n\t\treturn null;\n\t}\n\n\tconst sorted = [...query.entries()].sort(([a, aValue], [b, bValue]) =>\n\t\ta === b ? aValue.localeCompare(bValue) : a.localeCompare(b),\n\t);\n\tconst keyless = new URLSearchParams([[\"store\", storeId], ...sorted]);\n\treturn `/${path.slice(1)}?${keyless}`;\n};\n","import type { InspectOptions } from \"node:util\";\n\ntype LogParms = [message: unknown, ...optionalParams: unknown[]];\n\n/**\n * Vercel only supports 3 levels of logging. We're adding additional DEBUG level.\n * https://vercel.com/docs/observability/runtime-logs#level\n *\n * ERROR - Fatal for a particular request. Should be fixed sooner than later.\n *\n * WARN - A note on something that should probably be looked at eventually.\n *\n * LOG - Detail on regular operation.\n *\n * DEBUG - Debug only info as well as time and timeEnd functions.\n */\nconst LogLevel = {\n\tDEBUG: 0,\n\tLOG: 1,\n\tWARN: 2,\n\tERROR: 3,\n} as const;\ntype LogLevel = keyof typeof LogLevel;\n\nconst strLogLevel = (process.env.NEXT_PUBLIC_LOG_LEVEL || \"LOG\") as LogLevel;\nconst valueLogLevel = LogLevel[strLogLevel];\n\nconst RESET = \"\\x1b[0m\";\nconst BLUE = \"\\x1b[34m\";\nconst GREEN = \"\\x1b[32m\";\nconst YELLOW = \"\\x1b[33m\";\nconst RED = \"\\x1b[31m\";\n\nconst TIME = `⏱️`;\nconst DEBUG = `🐛`;\nconst OK = `✔️`;\nconst WARN = `⚠️`;\nconst ERROR = `❌`;\n\nconst PREFIX_TIME = `${TIME} `;\nconst PREFIX_DEBUG = `${BLUE}${DEBUG}${RESET} `;\nconst PREFIX_OK = `${GREEN}${OK}${RESET} `;\nconst PREFIX_WARN = `${YELLOW}${WARN}${RESET} `;\nconst PREFIX_ERROR = `${RED}${ERROR}${RESET} `;\n\nexport const getLogger = (groupLabel?: string) => {\n\tconst PREFIX = groupLabel ? `[${groupLabel}] ` : \"\";\n\treturn {\n\t\tgetLogger(subGroupLabel: string) {\n\t\t\treturn getLogger([groupLabel, subGroupLabel].filter(Boolean).join(\" > \"));\n\t\t},\n\t\ttime(label: string) {\n\t\t\tif (valueLogLevel > LogLevel.DEBUG) return;\n\t\t\tconsole.time([PREFIX_TIME, PREFIX, label].filter(Boolean).join(\" \"));\n\t\t},\n\t\ttimeEnd(label: string) {\n\t\t\tif (valueLogLevel > LogLevel.DEBUG) return;\n\t\t\tconsole.timeEnd([PREFIX_TIME, PREFIX, label].filter(Boolean).join(\" \"));\n\t\t},\n\t\tdebug(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.DEBUG) return;\n\t\t\tconsole.log(...[PREFIX_DEBUG, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t\tlog(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.LOG) return;\n\t\t\tconsole.log(...[PREFIX_OK, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t\tdir(item?: unknown, options?: InspectOptions) {\n\t\t\tif (valueLogLevel > LogLevel.LOG) return;\n\t\t\tconsole.dir(item, options);\n\t\t},\n\t\twarn(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.WARN) return;\n\t\t\tconsole.warn(...[PREFIX_WARN, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t\terror(...args: LogParms) {\n\t\t\tif (valueLogLevel > LogLevel.ERROR) return;\n\t\t\tconsole.error(...[PREFIX_ERROR, PREFIX, ...args].filter(Boolean));\n\t\t},\n\t};\n};\n\nexport const logger = getLogger();\n","import type {\n\tAPIBlogCategoriesBrowseQueryParams,\n\tAPIBlogCategoriesBrowseResult,\n\tAPIBlogCategoryCreateBody,\n\tAPIBlogCategoryCreateResult,\n\tAPIBlogCategoryDeleteResult,\n\tAPIBlogCategoryGetByIdParams,\n\tAPIBlogCategoryGetByIdResult,\n\tAPIBlogCategoryUpdateBody,\n\tAPIBlogCategoryUpdateResult,\n\tAPIBrandAssignProductsBody,\n\tAPIBrandAssignProductsResult,\n\tAPIBrandCreateBody,\n\tAPIBrandCreateResult,\n\tAPIBrandDeleteResult,\n\tAPIBrandGetByIdParams,\n\tAPIBrandGetByIdResult,\n\tAPIBrandsBrowseQueryParams,\n\tAPIBrandsBrowseResult,\n\tAPIBrandUpdateBody,\n\tAPIBrandUpdateResult,\n\tAPICartCouponApplyResult,\n\tAPICartCouponRemoveResult,\n\tAPICartCreateBody,\n\tAPICartCreateResult,\n\tAPICartDeleteResult,\n\tAPICartGetResult,\n\tAPICategoriesBrowseQueryParams,\n\tAPICategoriesBrowseResult,\n\tAPICategoryCreateBody,\n\tAPICategoryCreateResult,\n\tAPICategoryDeleteResult,\n\tAPICategoryGetByIdParams,\n\tAPICategoryGetByIdResult,\n\tAPICategoryUpdateBody,\n\tAPICategoryUpdateResult,\n\tAPICollectionCreateBody,\n\tAPICollectionCreateResult,\n\tAPICollectionDeleteResult,\n\tAPICollectionGetByIdParams,\n\tAPICollectionGetByIdResult,\n\tAPICollectionsBrowseQueryParams,\n\tAPICollectionsBrowseResult,\n\tAPICollectionUpdateBody,\n\tAPICollectionUpdateResult,\n\tAPIContactMessageCreateBody,\n\tAPIContactMessageCreateResult,\n\tAPICouponCreateBody,\n\tAPICouponCreateResult,\n\tAPICouponDeleteResult,\n\tAPICouponGetByIdParams,\n\tAPICouponGetByIdResult,\n\tAPICouponsBrowseQueryParams,\n\tAPICouponsBrowseResult,\n\tAPICouponUpdateBody,\n\tAPICouponUpdateResult,\n\tAPICustomerAddressCreateBody,\n\tAPICustomerAddressCreateResult,\n\tAPICustomerGetByIdParams,\n\tAPICustomerGetByIdResult,\n\tAPICustomerOrdersBrowseQueryParams,\n\tAPICustomerOrdersBrowseResult,\n\tAPICustomersBrowseQueryParams,\n\tAPICustomersBrowseResult,\n\tAPICustomerUpdateBody,\n\tAPICustomerUpdateResult,\n\tAPIEventAttendeesBrowseResult,\n\tAPIEventCreateBody,\n\tAPIEventCreateResult,\n\tAPIEventGetByIdParams,\n\tAPIEventGetByIdResult,\n\tAPIEventsBrowseQueryParams,\n\tAPIEventsBrowseResult,\n\tAPIEventUpdateBody,\n\tAPIEventUpdateResult,\n\tAPIInstaviewImagesBrowseParams,\n\tAPIInstaviewImagesBrowseQueryParams,\n\tAPIInstaviewImagesBrowseResult,\n\tAPIInventoryAdjustBody,\n\tAPIInventoryAdjustResult,\n\tAPIInventoryBrowseQueryParams,\n\tAPIInventoryBrowseResult,\n\tAPILegalPageCreateBody,\n\tAPILegalPageCreateQueryParams,\n\tAPILegalPageCreateResult,\n\tAPILegalPageGetByPathQueryParams,\n\tAPILegalPageGetByPathResult,\n\tAPILegalPagesBrowseQueryParams,\n\tAPILegalPagesBrowseResult,\n\tAPILegalPageUpdateBody,\n\tAPILegalPageUpdateQueryParams,\n\tAPILegalPageUpdateResult,\n\tAPIMeGetResult,\n\tAPIMetafieldDefinitionArchiveResult,\n\tAPIMetafieldDefinitionConversionPreviewResult,\n\tAPIMetafieldDefinitionConvertBody,\n\tAPIMetafieldDefinitionConvertResult,\n\tAPIMetafieldDefinitionCreateBody,\n\tAPIMetafieldDefinitionCreateResult,\n\tAPIMetafieldDefinitionDeleteBody,\n\tAPIMetafieldDefinitionDeleteResult,\n\tAPIMetafieldDefinitionGetQueryParams,\n\tAPIMetafieldDefinitionGetResult,\n\tAPIMetafieldDefinitionParams,\n\tAPIMetafieldDefinitionRestoreResult,\n\tAPIMetafieldDefinitionsBrowseQueryParams,\n\tAPIMetafieldDefinitionsBrowseResult,\n\tAPIMetafieldDefinitionTranslationParams,\n\tAPIMetafieldDefinitionTranslationPutBody,\n\tAPIMetafieldDefinitionTranslationPutResult,\n\tAPIMetafieldDefinitionUpdateBody,\n\tAPIMetafieldDefinitionUpdateResult,\n\tAPIMetafieldsTranslateMissingBody,\n\tAPIMetafieldsTranslateMissingResult,\n\tAPIMetafieldTranslationsPutBody,\n\tAPIOrderGetByIdParams,\n\tAPIOrderGetByIdResult,\n\tAPIOrderRefundGetParams,\n\tAPIOrderRefundGetResult,\n\tAPIOrderRefundsBrowseQueryParams,\n\tAPIOrderRefundsBrowseResult,\n\tAPIOrderRefundsParams,\n\tAPIOrdersBrowseQueryParams,\n\tAPIOrdersBrowseResult,\n\tAPIOrderUpdateBody,\n\tAPIOrderUpdateResult,\n\tAPIPostCommentCreateBody,\n\tAPIPostCommentCreateResult,\n\tAPIPostCommentsBrowseQueryParams,\n\tAPIPostCommentsBrowseResult,\n\tAPIPostCreateBody,\n\tAPIPostCreateResult,\n\tAPIPostDeleteResult,\n\tAPIPostGetByIdParams,\n\tAPIPostGetByIdResult,\n\tAPIPostsBrowseQueryParams,\n\tAPIPostsBrowseResult,\n\tAPIPostUpdateBody,\n\tAPIPostUpdateResult,\n\tAPIProductBatchBody,\n\tAPIProductBatchResult,\n\tAPIProductCreateBody,\n\tAPIProductCreateResult,\n\tAPIProductDeleteResult,\n\tAPIProductFiltersQueryParams,\n\tAPIProductFiltersResult,\n\tAPIProductGetByIdParams,\n\tAPIProductGetByIdQueryParams,\n\tAPIProductGetByIdResult,\n\tAPIProductMetafieldTranslationsPutParams,\n\tAPIProductMetafieldTranslationsPutResult,\n\tAPIProductReviewCreateBody,\n\tAPIProductReviewCreateResult,\n\tAPIProductReviewsBrowseQueryParams,\n\tAPIProductReviewsBrowseResult,\n\tAPIProductsBrowseQueryParams,\n\tAPIProductsBrowseResult,\n\tAPIProductUpdateBody,\n\tAPIProductUpdateResult,\n\tAPISearchQueryParams,\n\tAPISearchResult,\n\tAPISocialsGetResult,\n\tAPISubscriberCreateBody,\n\tAPISubscriberCreateResult,\n\tAPISubscriberDeleteResult,\n\tAPISupportCaseCreateBody,\n\tAPISupportCaseCreateResult,\n\tAPISupportCaseGetParams,\n\tAPISupportCaseGetResult,\n\tAPISupportCaseMessageCreateBody,\n\tAPISupportCaseMessageCreateResult,\n\tAPISupportCasesBrowseQueryParams,\n\tAPISupportCasesBrowseResult,\n\tAPISupportCaseUpdateBody,\n\tAPISupportCaseUpdateResult,\n\tAPITicketAttendeeGetResult,\n\tAPITicketsGetResult,\n\tAPITicketsUpdateBody,\n\tAPITicketsUpdateResult,\n\tAPIVariantCreateBody,\n\tAPIVariantCreateResult,\n\tAPIVariantGetByIdParams,\n\tAPIVariantGetByIdResult,\n\tAPIVariantMetafieldTranslationsPutParams,\n\tAPIVariantMetafieldTranslationsPutResult,\n\tAPIVariantUpdateBody,\n\tAPIVariantUpdateResult,\n} from \"../api-types\";\nimport { env } from \"../env\";\nimport { keylessPathname } from \"../keyless\";\nimport { getLogger } from \"../logger\";\nimport type { CommerceConfig } from \"../types\";\n\nexport type APICollectionImportMembershipsBody = { file: File | Blob };\n\nexport type APICollectionImportMembershipsResult = {\n\tok: true;\n\tprocessed: number;\n\tinserted: number;\n\tskipped_existing: number;\n\terrors: Array<{\n\t\trow: number;\n\t\tcollection_slug?: string;\n\t\tproduct_slug?: string;\n\t\treason: string;\n\t}>;\n};\n\n/** Answers that mean \"this platform or this request does not take keyless reads\": ask again with the key. */\nconst KEYLESS_REFUSALS: ReadonlySet<number> = new Set([400, 401, 403]);\n\nexport class YNSProvider {\n\t#config: CommerceConfig;\n\t#logger = getLogger(\"YNSProvider\");\n\t/** `null` once keyless reads are off for this process: opted out, refused, or no store id. */\n\t#storeId: Promise<string | null> | null = null;\n\n\tconstructor(config: CommerceConfig = {}) {\n\t\tconst token = config.token ?? env.YNS_API_KEY;\n\t\tconst isStaging = env.YNS_API_KEY?.startsWith(\"sk-s-\");\n\n\t\tif (!token) {\n\t\t\tthrow new Error(\n\t\t\t\t\"YNS API key is required. Set YNS_API_KEY environment variable or pass token in config.\",\n\t\t\t);\n\t\t}\n\t\tconst endpoint = config.endpoint ?? (isStaging ? \"https://yns.cx\" : \"https://yns.store\");\n\n\t\tthis.#config = { version: \"v1\", ...config, token, endpoint };\n\n\t\tthis.#logger.debug(\"YNSProvider initialized\", {\n\t\t\tendpoint,\n\t\t\ttoken: config.token ? `from config` : \"from env\",\n\t\t});\n\t}\n\n\tasync #restRequest<T>(\n\t\tpathname: `/${string}`,\n\t\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\" = \"GET\",\n\t\tbody?: unknown,\n\t): Promise<T> {\n\t\tconst response = await this.#fetchJson(pathname, method, body);\n\t\treturn this.#parseResponse<T>(response, pathname, method);\n\t}\n\n\t/**\n\t * Like {@link #restRequest} but resolves to `null` on a 404 response. For lookups where\n\t * \"not found\" is an expected outcome (e.g. ticket access codes answered with a uniform 404).\n\t */\n\tasync #restRequestNullable<T>(pathname: `/${string}`): Promise<T | null> {\n\t\tconst response = await this.#fetchJson(pathname, \"GET\");\n\t\tif (response.status === 404) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.#parseResponse<T>(response, pathname, \"GET\");\n\t}\n\n\t/**\n\t * The store id for keyless reads: from the config, then the environment, then one keyed\n\t * `GET /me`, asked once per process. Any failure leaves every request keyed, as before.\n\t */\n\t#resolveStoreId(): Promise<string | null> {\n\t\tconst configured = this.#config.store;\n\t\tif (configured === false) return Promise.resolve(null);\n\t\tthis.#storeId ??= (async () => {\n\t\t\tconst known = configured ?? env.YNS_STORE_ID;\n\t\t\tif (known) return known;\n\t\t\ttry {\n\t\t\t\tconst response = await this.#fetchKeyed(\"/me\", \"GET\");\n\t\t\t\tif (!response.ok) return null;\n\t\t\t\tconst me: { store?: { id?: unknown } } = await response.json();\n\t\t\t\treturn typeof me.store?.id === \"string\" ? me.store.id : null;\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t})();\n\t\treturn this.#storeId;\n\t}\n\n\tasync #fetchJson(\n\t\tpathname: `/${string}`,\n\t\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n\t\tbody?: unknown,\n\t): Promise<Response> {\n\t\tif (method !== \"GET\") return this.#fetchKeyed(pathname, method, body);\n\n\t\tconst storeId = await this.#resolveStoreId();\n\t\tconst keyless = storeId ? keylessPathname(pathname, storeId) : null;\n\t\tif (!keyless) return this.#fetchKeyed(pathname, method);\n\n\t\tconst logger = this.#logger.getLogger(\"#restRequest\");\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${keyless}`;\n\t\tlogger.debug(`Making keyless GET request to YNS API: ${endpoint}`);\n\t\tconst response = await fetch(endpoint, { method, headers: { \"Content-Type\": \"application/json\" } });\n\t\tif (!KEYLESS_REFUSALS.has(response.status)) return response;\n\n\t\t// A platform that still wants the key answers 401 to every keyless read, so stop trying.\n\t\tif (response.status !== 400) this.#storeId = Promise.resolve(null);\n\t\tlogger.debug(`Keyless request answered ${response.status}, asking again with the key`);\n\t\treturn this.#fetchKeyed(pathname, method);\n\t}\n\n\tasync #fetchKeyed(\n\t\tpathname: `/${string}`,\n\t\tmethod: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\",\n\t\tbody?: unknown,\n\t): Promise<Response> {\n\t\tconst logger = this.#logger.getLogger(\"#restRequest\");\n\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${pathname}`;\n\t\tlogger.debug(`Making ${method} request to YNS API: ${endpoint}`);\n\t\treturn fetch(endpoint, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${this.#config.token}`,\n\t\t\t},\n\t\t\tbody: body ? JSON.stringify(body) : undefined,\n\t\t});\n\t}\n\n\tasync #parseResponse<T>(response: Response, pathname: `/${string}`, method: string): Promise<T> {\n\t\tconst logger = this.#logger.getLogger(\"#restRequest\");\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${pathname}`;\n\n\t\tif (!response.ok) {\n\t\t\t// Handle different error types\n\t\t\tconst contentType = response.headers.get(\"content-type\");\n\t\t\tlet errorMessage = `YNS REST request failed: ${method} ${endpoint} ${response.status} ${response.statusText}`;\n\n\t\t\tif (contentType?.includes(\"application/json\")) {\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = await response.json();\n\t\t\t\t\terrorMessage = errorData.error || errorData.message || errorMessage;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to parse YNS error response as JSON\", error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst errorText = await response.text();\n\t\t\t\tlogger.error(\n\t\t\t\t\t`YNS API request failed: ${response.status} ${response.statusText}`,\n\t\t\t\t\terrorMessage,\n\t\t\t\t\terrorText,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\n\t\t// Check if response is JSON before parsing\n\t\tconst contentType = response.headers.get(\"content-type\");\n\t\tif (!contentType?.includes(\"application/json\")) {\n\t\t\tthrow new Error(`YNS API returned ${contentType} instead of JSON for ${pathname}`);\n\t\t}\n\n\t\treturn response.json();\n\t}\n\n\tasync #multipartRequest<T>(pathname: `/${string}`, formData: FormData): Promise<T> {\n\t\tconst logger = this.#logger.getLogger(\"#multipartRequest\");\n\n\t\tconst endpoint = `${this.#config.endpoint}/api/${this.#config.version}${pathname}`;\n\t\tlogger.debug(`Making multipart POST to YNS API: ${endpoint}`);\n\t\tconst response = await fetch(endpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.#config.token}`,\n\t\t\t},\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst contentType = response.headers.get(\"content-type\");\n\t\t\tlet errorMessage = `YNS REST request failed: POST ${endpoint} ${response.status} ${response.statusText}`;\n\n\t\t\tif (contentType?.includes(\"application/json\")) {\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = await response.json();\n\t\t\t\t\terrorMessage = errorData.error || errorData.message || errorMessage;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.error(\"Failed to parse YNS error response as JSON\", error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst errorText = await response.text();\n\t\t\t\tlogger.error(\n\t\t\t\t\t`YNS API request failed: ${response.status} ${response.statusText}`,\n\t\t\t\t\terrorMessage,\n\t\t\t\t\terrorText,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthrow new Error(errorMessage);\n\t\t}\n\n\t\tconst contentType = response.headers.get(\"content-type\");\n\t\tif (!contentType?.includes(\"application/json\")) {\n\t\t\tthrow new Error(`YNS API returned ${contentType} instead of JSON for ${pathname}`);\n\t\t}\n\n\t\treturn response.json();\n\t}\n\n\tasync meGet(): Promise<APIMeGetResult> {\n\t\tconst logger = this.#logger.getLogger(\"meGet\");\n\t\tlogger.debug(\"Fetching my information\");\n\n\t\tconst pathname = `/me` as const;\n\t\tconst result = await this.#restRequest<APIMeGetResult>(pathname);\n\t\tlogger.debug(\"Received my information:\", result);\n\t\treturn result;\n\t}\n\n\tasync socialsGet(): Promise<APISocialsGetResult> {\n\t\tconst logger = this.#logger.getLogger(\"socialsGet\");\n\t\tlogger.debug(\"Fetching store social links\");\n\n\t\tconst pathname = `/socials` as const;\n\t\tconst result = await this.#restRequest<APISocialsGetResult>(pathname);\n\t\tlogger.debug(\"Received store social links:\", result);\n\t\treturn result;\n\t}\n\n\t// Brands ---------------------------------------------------------------\n\n\tasync brandBrowse(params: APIBrandsBrowseQueryParams = {}): Promise<APIBrandsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/brands${searchParams}` as const;\n\t\treturn this.#restRequest<APIBrandsBrowseResult>(pathname);\n\t}\n\n\tasync brandGet(params: APIBrandGetByIdParams): Promise<APIBrandGetByIdResult | null> {\n\t\tconst pathname = `/brands/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBrandGetByIdResult>(pathname);\n\t}\n\n\tasync brandCreate(body: APIBrandCreateBody): Promise<APIBrandCreateResult> {\n\t\treturn this.#restRequest<APIBrandCreateResult>(\"/brands\", \"POST\", body);\n\t}\n\n\tasync brandUpdate(params: APIBrandGetByIdParams, body: APIBrandUpdateBody): Promise<APIBrandUpdateResult> {\n\t\tconst pathname = `/brands/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBrandUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync brandDelete(params: APIBrandGetByIdParams): Promise<APIBrandDeleteResult> {\n\t\tconst pathname = `/brands/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBrandDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync brandAssignProducts(\n\t\tparams: APIBrandGetByIdParams,\n\t\tbody: APIBrandAssignProductsBody,\n\t): Promise<APIBrandAssignProductsResult> {\n\t\tconst pathname = `/brands/${params.idOrSlug}/products` as const;\n\t\treturn this.#restRequest<APIBrandAssignProductsResult>(pathname, \"POST\", body);\n\t}\n\n\t// Order refunds --------------------------------------------------------\n\n\tasync orderRefundsBrowse(\n\t\tparams: APIOrderRefundsParams & APIOrderRefundsBrowseQueryParams,\n\t): Promise<APIOrderRefundsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/orders/${params.id}/refunds${searchParams}` as const;\n\t\treturn this.#restRequest<APIOrderRefundsBrowseResult>(pathname);\n\t}\n\n\tasync orderRefundGet(params: APIOrderRefundGetParams): Promise<APIOrderRefundGetResult | null> {\n\t\tconst pathname = `/orders/${params.id}/refunds/${params.refundId}` as const;\n\t\treturn this.#restRequest<APIOrderRefundGetResult>(pathname);\n\t}\n\n\t// Product bulk ---------------------------------------------------------\n\n\tasync productBatch(body: APIProductBatchBody): Promise<APIProductBatchResult> {\n\t\treturn this.#restRequest<APIProductBatchResult>(\"/products/batch\", \"POST\", body);\n\t}\n\n\t// Cart -----------------------------------------------------------------\n\n\tasync cartDelete(params: { cartId: string }): Promise<APICartDeleteResult> {\n\t\tconst pathname = `/carts/${params.cartId}` as const;\n\t\treturn this.#restRequest<APICartDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync productBrowse(params: APIProductsBrowseQueryParams): Promise<APIProductsBrowseResult> {\n\t\tconst logger = this.#logger.getLogger(\"productBrowse\");\n\t\tlogger.debug(\"Browsing products with params:\", params);\n\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.category) queryParams.append(\"category\", params.category);\n\t\tif (params.collection) queryParams.append(\"collection\", params.collection);\n\t\tif (params.brand) queryParams.append(\"brand\", params.brand);\n\t\tif (params.priceMin !== undefined) queryParams.append(\"priceMin\", params.priceMin.toString());\n\t\tif (params.priceMax !== undefined) queryParams.append(\"priceMax\", params.priceMax.toString());\n\t\tif (params.vts) queryParams.append(\"vts\", params.vts);\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.orderBy) queryParams.append(\"orderBy\", params.orderBy);\n\t\tif (params.orderDirection) queryParams.append(\"orderDirection\", params.orderDirection);\n\t\t// Prices come back in this currency, with its own `…Gross` twins; `lang` picks the translation.\n\t\tif (params.currency) queryParams.append(\"currency\", params.currency);\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\t// Custom fields: `filter` narrows by their values (`product.custom.material:wool,silk;\n\t\t// variant.custom.weight:100..300`), `include` adds the values of every product and\n\t\t// variant to the list, `metafields: \"all\"` adds private fields (needs a key with\n\t\t// `catalog:write`; refused without a key).\n\t\tif (params.filter) queryParams.append(\"filter\", params.filter);\n\t\tif (params.include) queryParams.append(\"include\", params.include);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/products${searchParams}` as const;\n\t\tlogger.debug(\"Constructed pathname:\", pathname);\n\t\tconst result = await this.#restRequest<APIProductsBrowseResult>(pathname);\n\t\tlogger.debug(\"Received product browse result:\", { meta: result.meta });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Available storefront filter facets for the store: price bounds, variant\n\t * types/values, active categories, collections and brands, and the filterable custom\n\t * fields (`metafields`, present only when the store has any) with their options or\n\t * number range. Pair with `productBrowse`'s `collection`, `brand`, `priceMin`/`priceMax`,\n\t * `vts` and `filter` params to build a filter UI. `lang` translates field names and\n\t * option labels.\n\t */\n\tasync productFilters(params: APIProductFiltersQueryParams = {}): Promise<APIProductFiltersResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/products/filters${searchParams}` as const;\n\t\treturn this.#restRequest<APIProductFiltersResult>(pathname);\n\t}\n\n\t/**\n\t * A single product by id or slug. `lang` selects the translation (and resolves a translated\n\t * slug); `currency` prices the variants in that currency, twins included. The product and\n\t * its variants carry their custom fields under `metafields`; `metafields: \"all\"` adds the\n\t * private ones (needs a key with `catalog:write`; refused without a key).\n\t */\n\tasync productGet(\n\t\tparams: APIProductGetByIdParams & APIProductGetByIdQueryParams,\n\t): Promise<APIProductGetByIdResult | null> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tif (params.currency) queryParams.append(\"currency\", params.currency);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/products/${params.idOrSlug}${searchParams}` as const;\n\n\t\tconst result = await this.#restRequest<APIProductGetByIdResult>(pathname);\n\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync orderBrowse(params: APIOrdersBrowseQueryParams): Promise<APIOrdersBrowseResult> {\n\t\tconst logger = this.#logger.getLogger(\"orderBrowse\");\n\t\tlogger.debug(\"Browsing orders with params:\", params);\n\n\t\tconst queryParams = new URLSearchParams();\n\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/orders${searchParams}` as const;\n\t\tlogger.debug(\"Constructed pathname:\", pathname);\n\t\tconst result = await this.#restRequest<APIOrdersBrowseResult>(pathname);\n\t\tlogger.debug(\"Received orders browse result:\", { meta: result.meta });\n\t\treturn result;\n\t}\n\n\tasync orderGet(params: APIOrderGetByIdParams): Promise<APIOrderGetByIdResult | null> {\n\t\tconst pathname = `/orders/${params.id}` as const;\n\n\t\tconst result = await this.#restRequest<APIOrderGetByIdResult>(pathname);\n\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// @todo\n\t// async cartAdd(params: APICartAddBody): Promise<APICartAddResult> {\n\t// \tconst body = {\n\t// \t\tvariantId: params.variantId,\n\t// \t\tcartId: params.cartId,\n\t// \t\tquantity: params.quantity,\n\t// \t\tsubscriptionId: params.subscriptionId,\n\t// \t};\n\n\t// \tconst result = await this.#restRequest<APICartCreateResult>(\"/carts\", \"PATCH\", body);\n\t// \treturn result;\n\t// }\n\n\tasync cartUpsert(body: APICartCreateBody): Promise<APICartCreateResult> {\n\t\tconst result = await this.#restRequest<APICartCreateResult>(\"/carts\", \"POST\", body);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Add a configured bundle to the cart in one call. `selections` are the customer's per-group\n\t * choices; always-included (forced) items may be omitted — the server fills them in and\n\t * validates the rest against the bundle's groups. Omit `cartId` to start a new cart. The\n\t * returned cart prices the bundle line (componentTotal × (1 − discount)).\n\t */\n\tasync cartAddBundle(params: {\n\t\tbundleId: string;\n\t\tselections: NonNullable<APICartCreateBody[\"selections\"]>;\n\t\tcartId?: string;\n\t\tcurrency?: string;\n\t}): Promise<APICartCreateResult> {\n\t\tconst body: APICartCreateBody = {\n\t\t\tbundleId: params.bundleId,\n\t\t\tselections: params.selections,\n\t\t\t...(params.cartId ? { cartId: params.cartId } : {}),\n\t\t\t...(params.currency ? { currency: params.currency } : {}),\n\t\t};\n\t\tconst result = await this.#restRequest<APICartCreateResult>(\"/carts\", \"POST\", body);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Remove a variant from the cart. A variant can sit on several lines when they carry different\n\t * `properties` (personalisation); pass `lineItemId` to remove just that one line, otherwise all\n\t * of the variant's one-time lines go.\n\t */\n\tasync cartRemoveItem(params: {\n\t\tcartId: string;\n\t\tvariantId: string;\n\t\tlineItemId?: string;\n\t}): Promise<APICartGetResult> {\n\t\tconst searchParams = params.lineItemId\n\t\t\t? `?${new URLSearchParams({ lineItemId: params.lineItemId })}`\n\t\t\t: \"\";\n\t\tconst pathname = `/carts/${params.cartId}/line-items/${params.variantId}${searchParams}` as const;\n\t\treturn this.#restRequest<APICartGetResult>(pathname, \"DELETE\");\n\t}\n\n\tasync cartGet(params: { cartId: string }): Promise<APICartGetResult | null> {\n\t\tconst pathname = `/carts/${params.cartId}` as const;\n\t\tconst result = await this.#restRequest<APICartGetResult>(pathname);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Validate and attach a coupon to the cart. Failures surface as an ApiError with\n\t * status 422 and a machine-readable `reason` (couponNotFound, couponHasExpired,\n\t * couponMaxUsesReached, couponIsNotValidYet, couponMinProductCountNotMet,\n\t * couponMaxProductCountExceeded, couponIsNotApplicable). Returns the updated cart.\n\t */\n\tasync cartCouponApply(params: { cartId: string; code: string }): Promise<APICartCouponApplyResult> {\n\t\tconst pathname = `/carts/${params.cartId}/coupon` as const;\n\t\treturn this.#restRequest<APICartCouponApplyResult>(pathname, \"POST\", { code: params.code });\n\t}\n\n\t/** Detach the applied coupon from the cart, if any. */\n\tasync cartCouponRemove(params: { cartId: string }): Promise<APICartCouponRemoveResult> {\n\t\tconst pathname = `/carts/${params.cartId}/coupon` as const;\n\t\treturn this.#restRequest<APICartCouponRemoveResult>(pathname, \"DELETE\");\n\t}\n\n\tasync couponBrowse(params: APICouponsBrowseQueryParams = {}): Promise<APICouponsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/coupons${searchParams}` as const;\n\n\t\treturn this.#restRequest<APICouponsBrowseResult>(pathname);\n\t}\n\n\t/** Look up a coupon by its UUID or its code. Resolves to `null` when not found. */\n\tasync couponGet(params: APICouponGetByIdParams): Promise<APICouponGetByIdResult | null> {\n\t\tconst pathname = `/coupons/${params.idOrCode}` as const;\n\t\treturn this.#restRequestNullable<APICouponGetByIdResult>(pathname);\n\t}\n\n\tasync couponCreate(body: APICouponCreateBody): Promise<APICouponCreateResult> {\n\t\treturn this.#restRequest<APICouponCreateResult>(\"/coupons\", \"POST\", body);\n\t}\n\n\tasync couponUpdate(\n\t\tparams: APICouponGetByIdParams,\n\t\tbody: APICouponUpdateBody,\n\t): Promise<APICouponUpdateResult> {\n\t\tconst pathname = `/coupons/${params.idOrCode}` as const;\n\t\treturn this.#restRequest<APICouponUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync couponDelete(params: APICouponGetByIdParams): Promise<APICouponDeleteResult> {\n\t\tconst pathname = `/coupons/${params.idOrCode}` as const;\n\t\treturn this.#restRequest<APICouponDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t/** List the store's support cases (merchant ↔ YNS support), newest activity first. */\n\tasync supportCaseBrowse(\n\t\tparams: APISupportCasesBrowseQueryParams = {},\n\t): Promise<APISupportCasesBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.status) queryParams.append(\"status\", params.status);\n\t\tif (params.severity) queryParams.append(\"severity\", params.severity);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/support-cases${searchParams}` as const;\n\n\t\treturn this.#restRequest<APISupportCasesBrowseResult>(pathname);\n\t}\n\n\t/**\n\t * Look up a case with its message thread by UUID or case number (\"123\" or \"000123\").\n\t * Resolves to `null` when not found. Internal YNS notes are never included.\n\t */\n\tasync supportCaseGet(params: APISupportCaseGetParams): Promise<APISupportCaseGetResult | null> {\n\t\tconst pathname = `/support-cases/${params.idOrNumber}` as const;\n\t\treturn this.#restRequestNullable<APISupportCaseGetResult>(pathname);\n\t}\n\n\t/** Open a support case with the YNS team. Omit `subject` to have one generated from the description. */\n\tasync supportCaseCreate(body: APISupportCaseCreateBody): Promise<APISupportCaseCreateResult> {\n\t\treturn this.#restRequest<APISupportCaseCreateResult>(\"/support-cases\", \"POST\", body);\n\t}\n\n\t/** Close (`status: \"closed\"`) or reopen (`status: \"open\"`) a case. */\n\tasync supportCaseUpdate(\n\t\tparams: APISupportCaseGetParams,\n\t\tbody: APISupportCaseUpdateBody,\n\t): Promise<APISupportCaseUpdateResult> {\n\t\tconst pathname = `/support-cases/${params.idOrNumber}` as const;\n\t\treturn this.#restRequest<APISupportCaseUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t/** Add a merchant-side reply to the case thread; replying reopens a closed or answered case. */\n\tasync supportCaseReply(\n\t\tparams: APISupportCaseGetParams,\n\t\tbody: APISupportCaseMessageCreateBody,\n\t): Promise<APISupportCaseMessageCreateResult> {\n\t\tconst pathname = `/support-cases/${params.idOrNumber}/messages` as const;\n\t\treturn this.#restRequest<APISupportCaseMessageCreateResult>(pathname, \"POST\", body);\n\t}\n\n\tasync collectionGet(params: APICollectionGetByIdParams): Promise<APICollectionGetByIdResult | null> {\n\t\tconst pathname = `/collections/${params.idOrSlug}` as const;\n\n\t\tconst result = await this.#restRequest<APICollectionGetByIdResult>(pathname);\n\t\treturn result;\n\t}\n\n\tasync collectionBrowse(params: APICollectionsBrowseQueryParams): Promise<APICollectionsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.group) queryParams.append(\"group\", params.group);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/collections${searchParams}` as const;\n\n\t\tconst result = await this.#restRequest<APICollectionsBrowseResult>(pathname);\n\t\treturn result;\n\t}\n\n\tasync collectionCreate(body: APICollectionCreateBody): Promise<APICollectionCreateResult> {\n\t\treturn this.#restRequest<APICollectionCreateResult>(\"/collections\", \"POST\", body);\n\t}\n\n\tasync collectionUpdate(\n\t\tparams: APICollectionGetByIdParams,\n\t\tbody: APICollectionUpdateBody,\n\t): Promise<APICollectionUpdateResult> {\n\t\tconst pathname = `/collections/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICollectionUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync collectionDelete(params: APICollectionGetByIdParams): Promise<APICollectionDeleteResult> {\n\t\tconst pathname = `/collections/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICollectionDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync collectionImportMemberships(\n\t\tbody: APICollectionImportMembershipsBody,\n\t): Promise<APICollectionImportMembershipsResult> {\n\t\tconst formData = new FormData();\n\t\tformData.append(\"file\", body.file);\n\t\treturn this.#multipartRequest<APICollectionImportMembershipsResult>(\n\t\t\t\"/collections/import-memberships\",\n\t\t\tformData,\n\t\t);\n\t}\n\n\tasync categoryGet(params: APICategoryGetByIdParams): Promise<APICategoryGetByIdResult | null> {\n\t\tconst pathname = `/categories/${params.idOrSlug}` as const;\n\n\t\tconst result = await this.#restRequest<APICategoryGetByIdResult>(pathname);\n\t\treturn result;\n\t}\n\n\tasync categoriesBrowse(params: APICategoriesBrowseQueryParams): Promise<APICategoriesBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/categories${searchParams}` as const;\n\n\t\tconst result = await this.#restRequest<APICategoriesBrowseResult>(pathname);\n\t\treturn result;\n\t}\n\n\t// ============================================\n\t// Posts\n\t// ============================================\n\n\tasync postBrowse(params: APIPostsBrowseQueryParams = {}): Promise<APIPostsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\t\tif (params.tag) queryParams.append(\"tag\", params.tag);\n\t\tif (params.categoryId) queryParams.append(\"categoryId\", params.categoryId);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/posts${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIPostsBrowseResult>(pathname);\n\t}\n\n\tasync postGet(params: APIPostGetByIdParams): Promise<APIPostGetByIdResult | null> {\n\t\tconst pathname = `/posts/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIPostGetByIdResult>(pathname);\n\t}\n\n\tasync postCreate(body: APIPostCreateBody): Promise<APIPostCreateResult> {\n\t\treturn this.#restRequest<APIPostCreateResult>(\"/posts\", \"POST\", body);\n\t}\n\n\tasync postUpdate(params: APIPostGetByIdParams, body: APIPostUpdateBody): Promise<APIPostUpdateResult> {\n\t\tconst pathname = `/posts/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIPostUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync postDelete(params: APIPostGetByIdParams): Promise<APIPostDeleteResult> {\n\t\tconst pathname = `/posts/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIPostDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\tasync postCommentsBrowse(\n\t\tparams: APIPostGetByIdParams,\n\t\tqueryParams: APIPostCommentsBrowseQueryParams = {},\n\t): Promise<APIPostCommentsBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.offset) urlParams.append(\"offset\", queryParams.offset.toString());\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/posts/${params.idOrSlug}/comments${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIPostCommentsBrowseResult>(pathname);\n\t}\n\n\tasync postCommentCreate(\n\t\tparams: APIPostGetByIdParams,\n\t\tbody: APIPostCommentCreateBody,\n\t): Promise<APIPostCommentCreateResult> {\n\t\tconst pathname = `/posts/${params.idOrSlug}/comments` as const;\n\t\treturn this.#restRequest<APIPostCommentCreateResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Blog Categories\n\t// ============================================\n\n\tasync blogCategoryBrowse(\n\t\tparams: APIBlogCategoriesBrowseQueryParams = {},\n\t): Promise<APIBlogCategoriesBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.query) queryParams.append(\"query\", params.query);\n\t\tif (params.active !== undefined) queryParams.append(\"active\", params.active.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/blog-categories${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIBlogCategoriesBrowseResult>(pathname);\n\t}\n\n\tasync blogCategoryGet(params: APIBlogCategoryGetByIdParams): Promise<APIBlogCategoryGetByIdResult | null> {\n\t\tconst pathname = `/blog-categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBlogCategoryGetByIdResult>(pathname);\n\t}\n\n\tasync blogCategoryCreate(body: APIBlogCategoryCreateBody): Promise<APIBlogCategoryCreateResult> {\n\t\treturn this.#restRequest<APIBlogCategoryCreateResult>(\"/blog-categories\", \"POST\", body);\n\t}\n\n\tasync blogCategoryUpdate(\n\t\tparams: APIBlogCategoryGetByIdParams,\n\t\tbody: APIBlogCategoryUpdateBody,\n\t): Promise<APIBlogCategoryUpdateResult> {\n\t\tconst pathname = `/blog-categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBlogCategoryUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync blogCategoryDelete(params: APIBlogCategoryGetByIdParams): Promise<APIBlogCategoryDeleteResult> {\n\t\tconst pathname = `/blog-categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIBlogCategoryDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Customers\n\t// ============================================\n\n\tasync customerBrowse(params: APICustomersBrowseQueryParams = {}): Promise<APICustomersBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.offset) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.search) queryParams.append(\"search\", params.search);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/customers${searchParams}` as const;\n\n\t\treturn this.#restRequest<APICustomersBrowseResult>(pathname);\n\t}\n\n\tasync customerGet(params: APICustomerGetByIdParams): Promise<APICustomerGetByIdResult | null> {\n\t\tconst pathname = `/customers/${params.id}` as const;\n\t\treturn this.#restRequest<APICustomerGetByIdResult>(pathname);\n\t}\n\n\tasync customerUpdate(\n\t\tparams: APICustomerGetByIdParams,\n\t\tbody: APICustomerUpdateBody,\n\t): Promise<APICustomerUpdateResult> {\n\t\tconst pathname = `/customers/${params.id}` as const;\n\t\treturn this.#restRequest<APICustomerUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync customerAddressCreate(\n\t\tparams: APICustomerGetByIdParams,\n\t\tbody: APICustomerAddressCreateBody,\n\t): Promise<APICustomerAddressCreateResult> {\n\t\tconst pathname = `/customers/${params.id}/addresses` as const;\n\t\treturn this.#restRequest<APICustomerAddressCreateResult>(pathname, \"POST\", body);\n\t}\n\n\tasync customerAddressDelete(params: { customerId: string; addressId: string }): Promise<void> {\n\t\tconst pathname = `/customers/${params.customerId}/addresses/${params.addressId}` as const;\n\t\tawait this.#restRequest<unknown>(pathname, \"DELETE\");\n\t}\n\n\tasync customerOrdersBrowse(\n\t\tparams: APICustomerGetByIdParams,\n\t\tqueryParams: APICustomerOrdersBrowseQueryParams = {},\n\t): Promise<APICustomerOrdersBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.offset) urlParams.append(\"offset\", queryParams.offset.toString());\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/customers/${params.id}/orders${searchParams}` as const;\n\n\t\treturn this.#restRequest<APICustomerOrdersBrowseResult>(pathname);\n\t}\n\n\t// ============================================\n\t// Inventory\n\t// ============================================\n\n\tasync inventoryBrowse(params: APIInventoryBrowseQueryParams = {}): Promise<APIInventoryBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.limit) queryParams.append(\"limit\", params.limit.toString());\n\t\tif (params.cursor) queryParams.append(\"cursor\", params.cursor);\n\t\tif (params.lowStock !== undefined) queryParams.append(\"lowStock\", params.lowStock.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/inventory${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIInventoryBrowseResult>(pathname);\n\t}\n\n\tasync inventoryAdjust(sku: string, body: APIInventoryAdjustBody): Promise<APIInventoryAdjustResult> {\n\t\tconst pathname = `/inventory/${encodeURIComponent(sku)}/adjust` as const;\n\t\treturn this.#restRequest<APIInventoryAdjustResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Variants\n\t// ============================================\n\n\tasync variantGet(params: APIVariantGetByIdParams): Promise<APIVariantGetByIdResult | null> {\n\t\tconst pathname = `/variants/${params.idOrSku}` as const;\n\t\treturn this.#restRequest<APIVariantGetByIdResult>(pathname);\n\t}\n\n\tasync variantUpdate(\n\t\tparams: APIVariantGetByIdParams,\n\t\tbody: APIVariantUpdateBody,\n\t): Promise<APIVariantUpdateResult> {\n\t\tconst pathname = `/variants/${params.idOrSku}` as const;\n\t\treturn this.#restRequest<APIVariantUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync variantDelete(params: APIVariantGetByIdParams): Promise<void> {\n\t\tconst pathname = `/variants/${params.idOrSku}` as const;\n\t\tawait this.#restRequest<unknown>(pathname, \"DELETE\");\n\t}\n\n\tasync variantCreate(productId: string, body: APIVariantCreateBody): Promise<APIVariantCreateResult> {\n\t\tconst pathname = `/products/${productId}/variants` as const;\n\t\treturn this.#restRequest<APIVariantCreateResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Subscribers\n\t// ============================================\n\n\tasync subscriberCreate(body: APISubscriberCreateBody): Promise<APISubscriberCreateResult> {\n\t\treturn this.#restRequest<APISubscriberCreateResult>(\"/subscribers\", \"POST\", body);\n\t}\n\n\tasync subscriberDelete(email: string): Promise<APISubscriberDeleteResult> {\n\t\tconst pathname = `/subscribers?email=${encodeURIComponent(email)}` as const;\n\t\treturn this.#restRequest<APISubscriberDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Contact Messages\n\t// ============================================\n\n\tasync contactMessageCreate(body: APIContactMessageCreateBody): Promise<APIContactMessageCreateResult> {\n\t\treturn this.#restRequest<APIContactMessageCreateResult>(\"/contact-messages\", \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Product mutations\n\t// ============================================\n\n\tasync productCreate(body: APIProductCreateBody): Promise<APIProductCreateResult> {\n\t\treturn this.#restRequest<APIProductCreateResult>(\"/products\", \"POST\", body);\n\t}\n\n\tasync productUpdate(\n\t\tparams: APIProductGetByIdParams,\n\t\tbody: APIProductUpdateBody,\n\t): Promise<APIProductUpdateResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIProductUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync productDelete(params: APIProductGetByIdParams): Promise<APIProductDeleteResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIProductDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Custom fields (metafields)\n\t// ============================================\n\t//\n\t// A field is defined once per store (name, kind of value, products or variants) and each\n\t// product or variant then holds its own value under `metafields`. Values are written with\n\t// the product or variant (`productCreate`, `productUpdate`, `variantCreate`,\n\t// `variantUpdate`); the methods here manage the fields and their translations. Variant\n\t// `attributes` keep coming back, derived from the variant's fields.\n\n\t/** The store's fields, in display order. Archived ones only with `includeArchived: \"true\"`. */\n\tasync metafieldDefinitionBrowse(\n\t\tparams: APIMetafieldDefinitionsBrowseQueryParams = {},\n\t): Promise<APIMetafieldDefinitionsBrowseResult> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.ownerType) queryParams.append(\"ownerType\", params.ownerType);\n\t\tif (params.includeArchived) queryParams.append(\"includeArchived\", params.includeArchived);\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/metafield-definitions${searchParams}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionsBrowseResult>(pathname);\n\t}\n\n\t/** One field, by id or by its address `<ownerType>.<namespace>.<key>`, e.g. `product.custom.material`. */\n\tasync metafieldDefinitionGet(\n\t\tparams: APIMetafieldDefinitionParams & APIMetafieldDefinitionGetQueryParams,\n\t): Promise<APIMetafieldDefinitionGetResult | null> {\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.lang) queryParams.append(\"lang\", params.lang);\n\t\tif (params.metafields) queryParams.append(\"metafields\", params.metafields);\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}${searchParams}` as const;\n\t\treturn this.#restRequestNullable<APIMetafieldDefinitionGetResult>(pathname);\n\t}\n\n\tasync metafieldDefinitionCreate(\n\t\tbody: APIMetafieldDefinitionCreateBody,\n\t): Promise<APIMetafieldDefinitionCreateResult> {\n\t\treturn this.#restRequest<APIMetafieldDefinitionCreateResult>(\"/metafield-definitions\", \"POST\", body);\n\t}\n\n\t/** Name, description, switches, options, limits. The kind of value cannot change here. */\n\tasync metafieldDefinitionUpdate(\n\t\tparams: APIMetafieldDefinitionParams,\n\t\tbody: APIMetafieldDefinitionUpdateBody,\n\t): Promise<APIMetafieldDefinitionUpdateResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t/**\n\t * Archive: the field leaves the admin, the storefront and the API, every value is kept.\n\t * `metafieldDefinitionRestore` brings it back; `metafieldDefinitionDelete` removes it for good.\n\t */\n\tasync metafieldDefinitionArchive(\n\t\tparams: APIMetafieldDefinitionParams,\n\t): Promise<APIMetafieldDefinitionArchiveResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionArchiveResult>(pathname, \"DELETE\");\n\t}\n\n\tasync metafieldDefinitionRestore(\n\t\tparams: APIMetafieldDefinitionParams,\n\t): Promise<APIMetafieldDefinitionRestoreResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/restore` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionRestoreResult>(pathname, \"POST\");\n\t}\n\n\t/**\n\t * Delete an ARCHIVED field for good, with every value and translation it holds. `confirm`\n\t * repeats the field's key and `expectedValueCount` the number of values it holds (a 409\n\t * tells the real count); both guard against deleting the wrong field.\n\t */\n\tasync metafieldDefinitionDelete(\n\t\tparams: APIMetafieldDefinitionParams,\n\t\tbody: APIMetafieldDefinitionDeleteBody,\n\t): Promise<APIMetafieldDefinitionDeleteResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/purge` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionDeleteResult>(pathname, \"POST\", body);\n\t}\n\n\t/**\n\t * What turning a text field into a choice would do: every distinct value in use and a\n\t * suggested grouping into options. Hand the groups and the `planHash` to\n\t * `metafieldDefinitionConvertToChoice`.\n\t */\n\tasync metafieldDefinitionConversionPreview(\n\t\tparams: APIMetafieldDefinitionParams,\n\t): Promise<APIMetafieldDefinitionConversionPreviewResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/convert-to-choice` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionConversionPreviewResult>(pathname);\n\t}\n\n\t/** In place: the field keeps its key and id, each value becomes the option of its group. */\n\tasync metafieldDefinitionConvertToChoice(\n\t\tparams: APIMetafieldDefinitionParams,\n\t\tbody: APIMetafieldDefinitionConvertBody,\n\t): Promise<APIMetafieldDefinitionConvertResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/convert-to-choice` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionConvertResult>(pathname, \"POST\", body);\n\t}\n\n\t/** The field's name, description and option labels in one language. `null` clears a part. */\n\tasync metafieldDefinitionTranslationPut(\n\t\tparams: APIMetafieldDefinitionTranslationParams,\n\t\tbody: APIMetafieldDefinitionTranslationPutBody,\n\t): Promise<APIMetafieldDefinitionTranslationPutResult> {\n\t\tconst pathname = `/metafield-definitions/${params.idOrKey}/translations/${params.locale}` as const;\n\t\treturn this.#restRequest<APIMetafieldDefinitionTranslationPutResult>(pathname, \"PUT\", body);\n\t}\n\n\t/** Translated values of a product's fields in one language. `value: null` removes one. */\n\tasync productMetafieldTranslationsPut(\n\t\tparams: APIProductMetafieldTranslationsPutParams,\n\t\tbody: APIMetafieldTranslationsPutBody,\n\t): Promise<APIProductMetafieldTranslationsPutResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}/metafields/translations/${params.locale}` as const;\n\t\treturn this.#restRequest<APIProductMetafieldTranslationsPutResult>(pathname, \"PUT\", body);\n\t}\n\n\t/** Translated values of a variant's fields in one language. `value: null` removes one. */\n\tasync variantMetafieldTranslationsPut(\n\t\tparams: APIVariantMetafieldTranslationsPutParams,\n\t\tbody: APIMetafieldTranslationsPutBody,\n\t): Promise<APIVariantMetafieldTranslationsPutResult> {\n\t\tconst pathname = `/variants/${params.idOrSku}/metafields/translations/${params.locale}` as const;\n\t\treturn this.#restRequest<APIVariantMetafieldTranslationsPutResult>(pathname, \"PUT\", body);\n\t}\n\n\t/**\n\t * Machine-translate the field values that have no translation yet. Translations a person\n\t * wrote are never replaced. With `productIds` it runs right away and returns what it wrote;\n\t * without, it starts a background run over the whole catalogue (answered 202 with a `runId`).\n\t */\n\tasync metafieldsTranslateMissing(\n\t\tbody: APIMetafieldsTranslateMissingBody = {},\n\t): Promise<APIMetafieldsTranslateMissingResult> {\n\t\treturn this.#restRequest<APIMetafieldsTranslateMissingResult>(\n\t\t\t\"/metafields/translate-missing\",\n\t\t\t\"POST\",\n\t\t\tbody,\n\t\t);\n\t}\n\n\t// ============================================\n\t// Product Reviews\n\t// ============================================\n\n\tasync productReviewsBrowse(\n\t\tparams: APIProductGetByIdParams,\n\t\tqueryParams: APIProductReviewsBrowseQueryParams = {},\n\t): Promise<APIProductReviewsBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.offset) urlParams.append(\"offset\", queryParams.offset.toString());\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/products/${params.idOrSlug}/reviews${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIProductReviewsBrowseResult>(pathname);\n\t}\n\n\tasync productReviewCreate(\n\t\tparams: APIProductGetByIdParams,\n\t\tbody: APIProductReviewCreateBody,\n\t): Promise<APIProductReviewCreateResult> {\n\t\tconst pathname = `/products/${params.idOrSlug}/reviews` as const;\n\t\treturn this.#restRequest<APIProductReviewCreateResult>(pathname, \"POST\", body);\n\t}\n\n\t// ============================================\n\t// Events (products flagged `flags.event` with a single non-shippable ticket variant)\n\t// ============================================\n\n\tasync eventBrowse(params: APIEventsBrowseQueryParams = {}): Promise<APIEventsBrowseResult> {\n\t\tconst logger = this.#logger.getLogger(\"eventBrowse\");\n\t\tconst queryParams = new URLSearchParams();\n\t\tif (params.offset !== undefined) queryParams.append(\"offset\", params.offset.toString());\n\t\tif (params.limit !== undefined) queryParams.append(\"limit\", params.limit.toString());\n\n\t\tconst searchParams = queryParams.size ? `?${queryParams}` : \"\";\n\t\tconst pathname = `/events${searchParams}` as const;\n\t\tlogger.debug(\"Browsing events:\", pathname);\n\t\treturn this.#restRequest<APIEventsBrowseResult>(pathname);\n\t}\n\n\tasync eventGet(params: APIEventGetByIdParams): Promise<APIEventGetByIdResult> {\n\t\tconst pathname = `/events/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIEventGetByIdResult>(pathname);\n\t}\n\n\tasync eventCreate(body: APIEventCreateBody): Promise<APIEventCreateResult> {\n\t\treturn this.#restRequest<APIEventCreateResult>(\"/events\", \"POST\", body);\n\t}\n\n\tasync eventUpdate(params: APIEventGetByIdParams, body: APIEventUpdateBody): Promise<APIEventUpdateResult> {\n\t\tconst pathname = `/events/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APIEventUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync eventAttendeesBrowse(params: APIEventGetByIdParams): Promise<APIEventAttendeesBrowseResult> {\n\t\tconst pathname = `/events/${params.idOrSlug}/attendees` as const;\n\t\treturn this.#restRequest<APIEventAttendeesBrowseResult>(pathname);\n\t}\n\n\t// ============================================\n\t// Tickets (no-login buyer/attendee access to purchased event tickets)\n\t// ============================================\n\n\t/**\n\t * Buyer ticket lookup: the order's 6-character access code plus the purchase email.\n\t * Resolves to `null` on mismatch — the API answers a uniform 404 for an unknown code,\n\t * an email that doesn't match, or an order without tickets.\n\t */\n\tasync ticketsGet(params: { code: string; email: string }): Promise<APITicketsGetResult | null> {\n\t\tconst logger = this.#logger.getLogger(\"ticketsGet\");\n\t\tconst queryParams = new URLSearchParams({ email: params.email });\n\t\tconst pathname = `/tickets/${encodeURIComponent(params.code)}?${queryParams}` as const;\n\t\tlogger.debug(\"Fetching ticket bundle:\", pathname);\n\t\treturn this.#restRequestNullable<APITicketsGetResult>(pathname);\n\t}\n\n\t/**\n\t * Buyer bulk-edit of attendee names/emails. The body carries the purchase email; seat\n\t * tokens not belonging to the order are silently ignored. Throws on code/email mismatch\n\t * (404) or when the order is cancelled/refunded (409).\n\t */\n\tasync ticketsUpdate(params: { code: string }, body: APITicketsUpdateBody): Promise<APITicketsUpdateResult> {\n\t\tconst pathname = `/tickets/${encodeURIComponent(params.code)}` as const;\n\t\treturn this.#restRequest<APITicketsUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t/**\n\t * View-only attendee ticket by per-seat token (the capability embedded in the attendee\n\t * link/QR). Resolves to `null` for an unknown token. Attendee details can only be edited\n\t * by the buyer via {@link ticketsUpdate} — attendee links must not escalate.\n\t */\n\tasync ticketAttendeeGet(params: { token: string }): Promise<APITicketAttendeeGetResult | null> {\n\t\tconst pathname = `/tickets/attendee/${encodeURIComponent(params.token)}` as const;\n\t\treturn this.#restRequestNullable<APITicketAttendeeGetResult>(pathname);\n\t}\n\n\t// ============================================\n\t// Category mutations\n\t// ============================================\n\n\tasync categoryCreate(body: APICategoryCreateBody): Promise<APICategoryCreateResult> {\n\t\treturn this.#restRequest<APICategoryCreateResult>(\"/categories\", \"POST\", body);\n\t}\n\n\tasync categoryUpdate(\n\t\tparams: APICategoryGetByIdParams,\n\t\tbody: APICategoryUpdateBody,\n\t): Promise<APICategoryUpdateResult> {\n\t\tconst pathname = `/categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICategoryUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\tasync categoryDelete(params: APICategoryGetByIdParams): Promise<APICategoryDeleteResult> {\n\t\tconst pathname = `/categories/${params.idOrSlug}` as const;\n\t\treturn this.#restRequest<APICategoryDeleteResult>(pathname, \"DELETE\");\n\t}\n\n\t// ============================================\n\t// Order mutations\n\t// ============================================\n\n\tasync orderUpdate(params: APIOrderGetByIdParams, body: APIOrderUpdateBody): Promise<APIOrderUpdateResult> {\n\t\tconst pathname = `/orders/${params.id}` as const;\n\t\treturn this.#restRequest<APIOrderUpdateResult>(pathname, \"PATCH\", body);\n\t}\n\n\t// ============================================\n\t// Legal Pages\n\t// ============================================\n\n\tasync legalPageBrowse(\n\t\tqueryParams: APILegalPagesBrowseQueryParams = {},\n\t): Promise<APILegalPagesBrowseResult> {\n\t\treturn this.request<APILegalPagesBrowseResult>(\"/legal-pages\", {\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync legalPageGet(\n\t\tkey: string,\n\t\tqueryParams: APILegalPageGetByPathQueryParams = {},\n\t): Promise<APILegalPageGetByPathResult> {\n\t\tconst normalized = key.startsWith(\"/\") ? key.slice(1) : key;\n\t\tconst pathname = `/legal-pages/${encodeURIComponent(normalized)}` as const;\n\t\treturn this.request<APILegalPageGetByPathResult>(pathname, {\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync legalPageCreate(\n\t\tbody: APILegalPageCreateBody,\n\t\tqueryParams: APILegalPageCreateQueryParams = {},\n\t): Promise<APILegalPageCreateResult> {\n\t\treturn this.request<APILegalPageCreateResult, APILegalPageCreateBody>(\"/legal-pages\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody,\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync legalPageUpdate(\n\t\tkey: string,\n\t\tbody: APILegalPageUpdateBody,\n\t\tqueryParams: APILegalPageUpdateQueryParams = {},\n\t): Promise<APILegalPageUpdateResult> {\n\t\tconst normalized = key.startsWith(\"/\") ? key.slice(1) : key;\n\t\tconst pathname = `/legal-pages/${encodeURIComponent(normalized)}` as const;\n\t\treturn this.request<APILegalPageUpdateResult, APILegalPageUpdateBody>(pathname, {\n\t\t\tmethod: \"PATCH\",\n\t\t\tbody,\n\t\t\tquery: queryParams,\n\t\t});\n\t}\n\n\tasync search(params: APISearchQueryParams): Promise<APISearchResult> {\n\t\treturn this.request<APISearchResult>(\"/search\", {\n\t\t\tquery: params,\n\t\t});\n\t}\n\n\t// ============================================\n\t// Instaview\n\t// ============================================\n\n\tasync instaviewImagesBrowse(\n\t\tparams: APIInstaviewImagesBrowseParams,\n\t\tqueryParams: APIInstaviewImagesBrowseQueryParams = {},\n\t): Promise<APIInstaviewImagesBrowseResult> {\n\t\tconst urlParams = new URLSearchParams();\n\t\tif (queryParams.limit) urlParams.append(\"limit\", queryParams.limit.toString());\n\t\tif (queryParams.cursor) urlParams.append(\"cursor\", queryParams.cursor);\n\n\t\tconst searchParams = urlParams.size ? `?${urlParams}` : \"\";\n\t\tconst pathname = `/instaview/accounts/${params.handle}/images${searchParams}` as const;\n\n\t\treturn this.#restRequest<APIInstaviewImagesBrowseResult>(pathname);\n\t}\n\n\t/**\n\t * Make a raw API request to any endpoint.\n\t * Use this for new API features not yet supported by typed methods.\n\t *\n\t * @example\n\t * // GET request (default method)\n\t * const webhooks = await provider.request<Webhook[]>('/webhooks');\n\t *\n\t * // POST with typed body\n\t * const webhook = await provider.request<Webhook, CreateWebhookBody>('/webhooks', {\n\t * method: 'POST',\n\t * body: { url: 'https://...' }\n\t * });\n\t *\n\t * // GET with query parameters\n\t * const products = await provider.request<Product[]>('/products', {\n\t * query: { limit: 10, category: 'shoes' }\n\t * });\n\t *\n\t * // Path parameters via template literals\n\t * const product = await provider.request<Product>(`/products/${id}`);\n\t */\n\tasync request<TResponse = unknown, TBody = unknown>(\n\t\tpathname: `/${string}`,\n\t\toptions?: {\n\t\t\tmethod?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n\t\t\tbody?: TBody;\n\t\t\tquery?: Record<string, string | number | boolean | null | undefined>;\n\t\t},\n\t) {\n\t\tconst queryEntries = options?.query\n\t\t\t? Object.entries(options.query).filter((entry): entry is [string, string | number | boolean] => {\n\t\t\t\t\tconst [, value] = entry;\n\t\t\t\t\treturn value !== null && value !== undefined;\n\t\t\t\t})\n\t\t\t: [];\n\t\tconst queryString =\n\t\t\tqueryEntries.length > 0 ? `?${new URLSearchParams(queryEntries.map(([k, v]) => [k, String(v)]))}` : \"\";\n\n\t\treturn this.#restRequest<TResponse>(`${pathname}${queryString}`, options?.method ?? \"GET\", options?.body);\n\t}\n}\n","import { YNSProvider } from \"./providers/yns\";\nimport type { CommerceConfig } from \"./types\";\n\nexport function Commerce(config: CommerceConfig = {}): YNSProvider {\n\treturn new YNSProvider(config);\n}\n"],"mappings":"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","names":["YNS_API_KEY","YNS_STORE_ID","env","KEYLESS_LISTS","KEYLESS_SINGLETONS","KEYLESS_DETAILS","NOT_A_RESOURCE","isKeylessPath","path","query","resource","idOrSlug","child","rest","keylessPathname","pathname","storeId","search","active","privateFields","sorted","a","aValue","b","bValue","keyless","LogLevel","strLogLevel","valueLogLevel","RESET","BLUE","GREEN","YELLOW","RED","TIME","DEBUG","OK","WARN","ERROR","PREFIX_TIME","PREFIX_DEBUG","PREFIX_OK","PREFIX_WARN","PREFIX_ERROR","getLogger","groupLabel","PREFIX","subGroupLabel","label","args","item","options","logger","KEYLESS_REFUSALS","YNSProvider","#config","#logger","getLogger","#storeId","config","token","env","isStaging","endpoint","#restRequest","pathname","method","body","response","#fetchJson","#parseResponse","#restRequestNullable","#resolveStoreId","configured","known","#fetchKeyed","me","storeId","keyless","keylessPathname","logger","contentType","errorMessage","errorData","error","errorText","#multipartRequest","formData","result","params","queryParams","searchParams","urlParams","sku","productId","email","key","normalized","options","queryEntries","entry","value","queryString","k","v","Commerce","config","YNSProvider"]}
|
package/dist/uploads.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/uploads.ts
|
|
6
|
+
import { put } from "@vercel/blob/client";
|
|
7
|
+
var LINE_ITEM_UPLOAD_ENDPOINT = "/checkout/api/line-item-uploads";
|
|
8
|
+
var MAX_LINE_ITEM_UPLOAD_BYTES = 20 * 1024 * 1024;
|
|
9
|
+
var TYPE_BY_EXTENSION = {
|
|
10
|
+
jpg: "image/jpeg",
|
|
11
|
+
jpeg: "image/jpeg",
|
|
12
|
+
png: "image/png",
|
|
13
|
+
webp: "image/webp",
|
|
14
|
+
gif: "image/gif",
|
|
15
|
+
heic: "image/heic",
|
|
16
|
+
heif: "image/heif",
|
|
17
|
+
avif: "image/avif",
|
|
18
|
+
tif: "image/tiff",
|
|
19
|
+
tiff: "image/tiff",
|
|
20
|
+
pdf: "application/pdf"
|
|
21
|
+
};
|
|
22
|
+
var ACCEPTED_LINE_ITEM_UPLOAD_TYPES = [...new Set(Object.values(TYPE_BY_EXTENSION))].join(",");
|
|
23
|
+
var LineItemUploadError = class extends Error {
|
|
24
|
+
constructor(message, status) {
|
|
25
|
+
super(message);
|
|
26
|
+
__publicField(this, "status");
|
|
27
|
+
this.name = "LineItemUploadError";
|
|
28
|
+
this.status = status;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var contentTypeOf = (file) => file.type || TYPE_BY_EXTENSION[file.name.split(".").pop()?.toLowerCase() ?? ""] || "";
|
|
32
|
+
var isTokenResponse = (value) => typeof value === "object" && value !== null && "uploadId" in value && typeof value.uploadId === "string" && "pathname" in value && typeof value.pathname === "string" && "clientToken" in value && typeof value.clientToken === "string";
|
|
33
|
+
var errorMessageOf = (value) => typeof value === "object" && value !== null && "error" in value && typeof value.error === "string" ? value.error : null;
|
|
34
|
+
async function uploadLineItemFile(file, options) {
|
|
35
|
+
const contentType = contentTypeOf(file);
|
|
36
|
+
if (!contentType) {
|
|
37
|
+
throw new LineItemUploadError("This file type can't be uploaded.", 400);
|
|
38
|
+
}
|
|
39
|
+
if (file.size > MAX_LINE_ITEM_UPLOAD_BYTES) {
|
|
40
|
+
throw new LineItemUploadError("The file is larger than 20 MB.", 400);
|
|
41
|
+
}
|
|
42
|
+
const response = await fetch(options.endpoint ?? LINE_ITEM_UPLOAD_ENDPOINT, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: { "Content-Type": "application/json" },
|
|
45
|
+
credentials: "same-origin",
|
|
46
|
+
body: JSON.stringify({ variantId: options.variantId, filename: file.name, contentType, size: file.size }),
|
|
47
|
+
...options.abortSignal ? { signal: options.abortSignal } : {}
|
|
48
|
+
});
|
|
49
|
+
const body = await response.json().catch(() => null);
|
|
50
|
+
if (!response.ok || !isTokenResponse(body)) {
|
|
51
|
+
throw new LineItemUploadError(errorMessageOf(body) ?? "The upload could not start.", response.status);
|
|
52
|
+
}
|
|
53
|
+
await put(body.pathname, file, {
|
|
54
|
+
access: "private",
|
|
55
|
+
token: body.clientToken,
|
|
56
|
+
contentType,
|
|
57
|
+
multipart: file.size > 8 * 1024 * 1024,
|
|
58
|
+
...options.onUploadProgress ? { onUploadProgress: options.onUploadProgress } : {},
|
|
59
|
+
...options.abortSignal ? { abortSignal: options.abortSignal } : {}
|
|
60
|
+
});
|
|
61
|
+
return { uploadId: body.uploadId };
|
|
62
|
+
}
|
|
63
|
+
var lineItemFileProperty = ({
|
|
64
|
+
key,
|
|
65
|
+
label,
|
|
66
|
+
uploadId
|
|
67
|
+
}) => ({
|
|
68
|
+
key,
|
|
69
|
+
...label !== void 0 ? { label } : {},
|
|
70
|
+
type: "file",
|
|
71
|
+
value: uploadId
|
|
72
|
+
});
|
|
73
|
+
export {
|
|
74
|
+
ACCEPTED_LINE_ITEM_UPLOAD_TYPES,
|
|
75
|
+
LINE_ITEM_UPLOAD_ENDPOINT,
|
|
76
|
+
LineItemUploadError,
|
|
77
|
+
MAX_LINE_ITEM_UPLOAD_BYTES,
|
|
78
|
+
lineItemFileProperty,
|
|
79
|
+
uploadLineItemFile
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=uploads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/uploads.ts"],"sourcesContent":["import { put } from \"@vercel/blob/client\";\n\n/**\n * Shopper file uploads for personalised products (a photo for a portrait, a print-ready PDF).\n *\n * Browser-only. The storefront calls `uploadLineItemFile(file, { variantId })` from its product\n * page; the platform hands out a short-lived token for exactly one file (its `/checkout/api/**`\n * endpoint is already forwarded by every tenant's proxy, so the storefront needs no route of its\n * own and no API key in the browser), and the file goes straight into the store's private storage.\n * The returned `uploadId` is what a cart line's file property carries:\n *\n * ```ts\n * const { uploadId } = await uploadLineItemFile(file, { variantId });\n * await cartUpsert({ variantId, quantity: 1, properties: [lineItemFileProperty({ key: \"photo\", label: \"Photo\", uploadId })] });\n * ```\n *\n * Requires the store's Customer Uploads module. Images (JPEG, PNG, WebP, GIF, HEIC/HEIF, AVIF,\n * TIFF) and PDF, up to 20 MB.\n */\n\nexport const LINE_ITEM_UPLOAD_ENDPOINT = \"/checkout/api/line-item-uploads\";\nexport const MAX_LINE_ITEM_UPLOAD_BYTES = 20 * 1024 * 1024;\n\n/** Some browsers report HEIC/HEIF (and the occasional other image) with an empty type. */\nconst TYPE_BY_EXTENSION: Record<string, string> = {\n\tjpg: \"image/jpeg\",\n\tjpeg: \"image/jpeg\",\n\tpng: \"image/png\",\n\twebp: \"image/webp\",\n\tgif: \"image/gif\",\n\theic: \"image/heic\",\n\theif: \"image/heif\",\n\tavif: \"image/avif\",\n\ttif: \"image/tiff\",\n\ttiff: \"image/tiff\",\n\tpdf: \"application/pdf\",\n};\n\nexport const ACCEPTED_LINE_ITEM_UPLOAD_TYPES = [...new Set(Object.values(TYPE_BY_EXTENSION))].join(\",\");\n\nexport class LineItemUploadError extends Error {\n\treadonly status: number;\n\tconstructor(message: string, status: number) {\n\t\tsuper(message);\n\t\tthis.name = \"LineItemUploadError\";\n\t\tthis.status = status;\n\t}\n}\n\nconst contentTypeOf = (file: File): string =>\n\tfile.type || TYPE_BY_EXTENSION[file.name.split(\".\").pop()?.toLowerCase() ?? \"\"] || \"\";\n\nconst isTokenResponse = (\n\tvalue: unknown,\n): value is { uploadId: string; pathname: string; clientToken: string } =>\n\ttypeof value === \"object\" &&\n\tvalue !== null &&\n\t\"uploadId\" in value &&\n\ttypeof value.uploadId === \"string\" &&\n\t\"pathname\" in value &&\n\ttypeof value.pathname === \"string\" &&\n\t\"clientToken\" in value &&\n\ttypeof value.clientToken === \"string\";\n\nconst errorMessageOf = (value: unknown): string | null =>\n\ttypeof value === \"object\" && value !== null && \"error\" in value && typeof value.error === \"string\"\n\t\t? value.error\n\t\t: null;\n\n/**\n * Upload one file for a cart line. Throws `LineItemUploadError` with the platform's message and\n * HTTP status (400 unsupported file, 404 uploads off for this store, 429 too many uploads).\n */\nexport async function uploadLineItemFile(\n\tfile: File,\n\toptions: {\n\t\tvariantId: string;\n\t\t/** Defaults to the platform endpoint every tenant proxy forwards. */\n\t\tendpoint?: string;\n\t\tonUploadProgress?: (event: { loaded: number; total: number; percentage: number }) => void;\n\t\tabortSignal?: AbortSignal;\n\t},\n): Promise<{ uploadId: string }> {\n\tconst contentType = contentTypeOf(file);\n\tif (!contentType) {\n\t\tthrow new LineItemUploadError(\"This file type can't be uploaded.\", 400);\n\t}\n\tif (file.size > MAX_LINE_ITEM_UPLOAD_BYTES) {\n\t\tthrow new LineItemUploadError(\"The file is larger than 20 MB.\", 400);\n\t}\n\n\tconst response = await fetch(options.endpoint ?? LINE_ITEM_UPLOAD_ENDPOINT, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tcredentials: \"same-origin\",\n\t\tbody: JSON.stringify({ variantId: options.variantId, filename: file.name, contentType, size: file.size }),\n\t\t...(options.abortSignal ? { signal: options.abortSignal } : {}),\n\t});\n\tconst body: unknown = await response.json().catch(() => null);\n\tif (!response.ok || !isTokenResponse(body)) {\n\t\tthrow new LineItemUploadError(errorMessageOf(body) ?? \"The upload could not start.\", response.status);\n\t}\n\n\tawait put(body.pathname, file, {\n\t\taccess: \"private\",\n\t\ttoken: body.clientToken,\n\t\tcontentType,\n\t\tmultipart: file.size > 8 * 1024 * 1024,\n\t\t...(options.onUploadProgress ? { onUploadProgress: options.onUploadProgress } : {}),\n\t\t...(options.abortSignal ? { abortSignal: options.abortSignal } : {}),\n\t});\n\treturn { uploadId: body.uploadId };\n}\n\n/** The cart line property that attaches an uploaded file. */\nexport const lineItemFileProperty = ({\n\tkey,\n\tlabel,\n\tuploadId,\n}: {\n\tkey: string;\n\tlabel?: string;\n\tuploadId: string;\n}): { key: string; label?: string; type: \"file\"; value: string } => ({\n\tkey,\n\t...(label !== undefined ? { label } : {}),\n\ttype: \"file\",\n\tvalue: uploadId,\n});\n"],"mappings":";;;;;AAAA,SAAS,WAAW;AAoBb,IAAM,4BAA4B;AAClC,IAAM,6BAA6B,KAAK,OAAO;AAGtD,IAAM,oBAA4C;AAAA,EACjD,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AACN;AAEO,IAAM,kCAAkC,CAAC,GAAG,IAAI,IAAI,OAAO,OAAO,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG;AAE/F,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAE9C,YAAY,SAAiB,QAAgB;AAC5C,UAAM,OAAO;AAFd,wBAAS;AAGR,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EACf;AACD;AAEA,IAAM,gBAAgB,CAAC,SACtB,KAAK,QAAQ,kBAAkB,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK,EAAE,KAAK;AAEpF,IAAM,kBAAkB,CACvB,UAEA,OAAO,UAAU,YACjB,UAAU,QACV,cAAc,SACd,OAAO,MAAM,aAAa,YAC1B,cAAc,SACd,OAAO,MAAM,aAAa,YAC1B,iBAAiB,SACjB,OAAO,MAAM,gBAAgB;AAE9B,IAAM,iBAAiB,CAAC,UACvB,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW,SAAS,OAAO,MAAM,UAAU,WACvF,MAAM,QACN;AAMJ,eAAsB,mBACrB,MACA,SAOgC;AAChC,QAAM,cAAc,cAAc,IAAI;AACtC,MAAI,CAAC,aAAa;AACjB,UAAM,IAAI,oBAAoB,qCAAqC,GAAG;AAAA,EACvE;AACA,MAAI,KAAK,OAAO,4BAA4B;AAC3C,UAAM,IAAI,oBAAoB,kCAAkC,GAAG;AAAA,EACpE;AAEA,QAAM,WAAW,MAAM,MAAM,QAAQ,YAAY,2BAA2B;AAAA,IAC3E,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,aAAa;AAAA,IACb,MAAM,KAAK,UAAU,EAAE,WAAW,QAAQ,WAAW,UAAU,KAAK,MAAM,aAAa,MAAM,KAAK,KAAK,CAAC;AAAA,IACxG,GAAI,QAAQ,cAAc,EAAE,QAAQ,QAAQ,YAAY,IAAI,CAAC;AAAA,EAC9D,CAAC;AACD,QAAM,OAAgB,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,IAAI;AAC5D,MAAI,CAAC,SAAS,MAAM,CAAC,gBAAgB,IAAI,GAAG;AAC3C,UAAM,IAAI,oBAAoB,eAAe,IAAI,KAAK,+BAA+B,SAAS,MAAM;AAAA,EACrG;AAEA,QAAM,IAAI,KAAK,UAAU,MAAM;AAAA,IAC9B,QAAQ;AAAA,IACR,OAAO,KAAK;AAAA,IACZ;AAAA,IACA,WAAW,KAAK,OAAO,IAAI,OAAO;AAAA,IAClC,GAAI,QAAQ,mBAAmB,EAAE,kBAAkB,QAAQ,iBAAiB,IAAI,CAAC;AAAA,IACjF,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,EACnE,CAAC;AACD,SAAO,EAAE,UAAU,KAAK,SAAS;AAClC;AAGO,IAAM,uBAAuB,CAAC;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACD,OAIqE;AAAA,EACpE;AAAA,EACA,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,EACvC,MAAM;AAAA,EACN,OAAO;AACR;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "commerce-kit",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.67.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
7
7
|
"keywords": [
|
|
@@ -34,6 +34,11 @@
|
|
|
34
34
|
"types": "./dist/payment-icons.d.ts",
|
|
35
35
|
"default": "./dist/payment-icons.js"
|
|
36
36
|
},
|
|
37
|
+
"./uploads": {
|
|
38
|
+
"import": "./dist/uploads.js",
|
|
39
|
+
"types": "./dist/uploads.d.ts",
|
|
40
|
+
"default": "./dist/uploads.js"
|
|
41
|
+
},
|
|
37
42
|
"./sandbox-inspectors": {
|
|
38
43
|
"import": "./dist/sandbox-inspectors.js",
|
|
39
44
|
"types": "./dist/sandbox-inspectors.d.ts",
|
|
@@ -103,5 +108,8 @@
|
|
|
103
108
|
"*": [
|
|
104
109
|
"bun biome check --write --unsafe --staged --no-errors-on-unmatched --files-ignore-unknown=true"
|
|
105
110
|
]
|
|
111
|
+
},
|
|
112
|
+
"dependencies": {
|
|
113
|
+
"@vercel/blob": "^2.8.0"
|
|
106
114
|
}
|
|
107
115
|
}
|