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 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
@@ -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"]}
@@ -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.66.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
  }