@jytextiles/medusa-plugin-faire-store-sync 0.2.5 → 0.2.7

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.
@@ -16,6 +16,27 @@ const productDisplayUrl = (product) => {
16
16
  return null;
17
17
  return `https://www.faire.com/brand/products/${product.product_token}`;
18
18
  };
19
+ /**
20
+ * Faire variant prices are geo-scoped (`geo_constraint`). Derive a sensible
21
+ * default from the brand's currency (and country when known). Eurozone brands
22
+ * map to the EUROPEAN_UNION country_group; otherwise scope to a single country.
23
+ */
24
+ const geoForCurrency = (currency, country) => {
25
+ switch (currency) {
26
+ case "EUR":
27
+ return { country_group: "EUROPEAN_UNION" };
28
+ case "GBP":
29
+ return { country: "GB" };
30
+ case "USD":
31
+ return { country: "US" };
32
+ case "CAD":
33
+ return { country: "CA" };
34
+ case "AUD":
35
+ return { country: "AU" };
36
+ default:
37
+ return country ? { country } : { country_group: "EUROPEAN_UNION" };
38
+ }
39
+ };
19
40
  // ── Step 1: resolve account (fresh token) + settings ─────────────────────
20
41
  const resolveFaireConfigStep = (0, workflows_sdk_1.createStep)("faire-resolve-config-step", async (_, { container }) => {
21
42
  const service = container.resolve(faire_sync_1.FAIRE_SYNC_MODULE);
@@ -27,6 +48,7 @@ const resolveFaireConfigStep = (0, workflows_sdk_1.createStep)("faire-resolve-co
27
48
  access_token: account.access_token,
28
49
  auth_mode: account.auth_mode ?? "oauth",
29
50
  currency: account.currency ?? null,
51
+ country: account.country ?? null,
30
52
  settings,
31
53
  });
32
54
  });
@@ -46,6 +68,8 @@ const prepareProductStep = (0, workflows_sdk_1.createStep)("faire-prepare-produc
46
68
  "tags.*",
47
69
  "variants.*",
48
70
  "variants.prices.*",
71
+ "variants.options.*",
72
+ "variants.options.option.*",
49
73
  "variants.inventory_items.*",
50
74
  "images.*",
51
75
  "variants.sku",
@@ -54,7 +78,7 @@ const prepareProductStep = (0, workflows_sdk_1.createStep)("faire-prepare-produc
54
78
  });
55
79
  const product = products?.[0];
56
80
  if (!product) {
57
- throw new Error(`Product ${input.product_id} not found`);
81
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, `Product ${input.product_id} not found`);
58
82
  }
59
83
  // Resolve existing Faire product (from link)
60
84
  let existing_product_token = null;
@@ -75,53 +99,94 @@ const prepareProductStep = (0, workflows_sdk_1.createStep)("faire-prepare-produc
75
99
  const settings = input.settings;
76
100
  const metadata = product.metadata || {};
77
101
  const variants = product.variants || [];
78
- // Medusa v2 stores money as a whole decimal in the price's currency (NOT
79
- // minor units). Faire wants integer cents, so round to cents.
80
- const toCents = (amount) => Math.round(Number(amount || 0) * 100);
102
+ // ── Currency + geo constraint (Faire prices are geo-scoped) ────────────
103
+ // Prefer the brand's own currency; fall back to the price currency Medusa
104
+ // stored, then EUR. Currency picks the price row + drives the geo default.
105
+ const currency = String(metadata.faire_currency ||
106
+ input.currency ||
107
+ (variants.flatMap((v) => v.prices || [])[0]?.currency_code ?? "EUR")).toUpperCase();
108
+ const geoConstraint = metadata.faire_geo_constraint && typeof metadata.faire_geo_constraint === "object"
109
+ ? metadata.faire_geo_constraint
110
+ : geoForCurrency(currency, input.country);
111
+ // Medusa v2 stores money as a whole decimal in the price's currency; Faire
112
+ // wants integer minor units (cents), so round.
113
+ const toMinor = (amount) => Math.round(Number(amount || 0) * 100);
81
114
  const markupPercent = Number(metadata.faire_wholesale_markup_percent ?? settings.default_wholesale_markup_percent) ||
82
115
  0;
83
- const buildVariant = (v) => {
84
- const prices = v.prices || [];
85
- const retail = prices[0] ?? prices.find(Boolean);
86
- const retailCents = retail ? toCents(retail.amount) : 0;
87
- const wholesaleCents = markupPercent > 0
88
- ? Math.round((retailCents * (100 - markupPercent)) / 100)
89
- : retailCents;
116
+ // Pick the price row matching the chosen currency (fall back to first).
117
+ const pickPrice = (prices) => prices.find((p) => String(p.currency_code || "").toUpperCase() === currency) ??
118
+ prices[0] ??
119
+ null;
120
+ const buildVariant = (v, idx) => {
121
+ const retail = pickPrice(v.prices || []);
122
+ const retailMinor = retail ? toMinor(retail.amount) : 0;
123
+ const wholesaleMinor = markupPercent > 0
124
+ ? Math.round((retailMinor * (100 - markupPercent)) / 100)
125
+ : retailMinor;
126
+ const sku = v.sku || v.id;
127
+ const options = (v.options || [])
128
+ .map((o) => ({
129
+ name: String(o.option?.title || o.title || "Option"),
130
+ value: String(o.value ?? ""),
131
+ }))
132
+ .filter((o) => o.value) || [];
90
133
  return {
91
- sku: v.sku || v.id,
92
- name: v.title || undefined,
93
- retail_price_cents: retailCents || undefined,
94
- wholesale_price_cents: wholesaleCents || undefined,
95
- inventory_count: Number(v.inventory_quantity) || 0,
134
+ sku,
135
+ name: v.title || sku,
136
+ idempotence_token: `${product.id}:${v.id || sku}`,
137
+ options: options.length ? options : undefined,
138
+ available_quantity: Number(v.inventory_quantity) || 0,
139
+ prices: retailMinor > 0
140
+ ? [
141
+ {
142
+ geo_constraint: geoConstraint,
143
+ wholesale_price: { amount_minor: wholesaleMinor, currency },
144
+ retail_price: { amount_minor: retailMinor, currency },
145
+ },
146
+ ]
147
+ : undefined,
96
148
  };
97
149
  };
98
- // Aggregate retail/wholesale from min-variant for the product-level price.
99
- const allPrices = variants.flatMap((v) => v.prices || []);
100
- const minRetail = allPrices
101
- .map((p) => toCents(p.amount))
102
- .filter((a) => a > 0)
103
- .sort((a, b) => a - b)[0] ?? 0;
104
- const minWholesale = markupPercent > 0
105
- ? Math.round((minRetail * (100 - markupPercent)) / 100)
106
- : minRetail;
107
- const tags = (product.tags || [])
108
- .map((t) => t.value)
109
- .filter(Boolean);
110
150
  const images = (product.images || [])
111
151
  .map((img) => ({ url: img.url }))
112
152
  .filter((i) => i.url);
153
+ // Resolve taxonomy_type.id — REQUIRED by Faire create. Priority:
154
+ // product.metadata.faire_taxonomy_type_id (tt_… or a category name)
155
+ // → settings.default_category (id or name) → error.
156
+ const client = service.getClient(input.auth_mode);
157
+ const categoryHint = metadata.faire_taxonomy_type_id ||
158
+ metadata.faire_category ||
159
+ settings.default_category ||
160
+ "";
161
+ const taxonomyTypeId = await client.resolveTaxonomyTypeId(input.access_token, String(categoryHint));
162
+ if (!taxonomyTypeId) {
163
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Faire requires a product category (taxonomy_type). Set a Faire " +
164
+ "category in sync settings (default_category) or on the product " +
165
+ "(metadata.faire_taxonomy_type_id — a `tt_…` id or a category name).");
166
+ }
167
+ const lifecycle_state = settings.follow_product_status !== false && product.status === "published"
168
+ ? "PUBLISHED"
169
+ : "DRAFT";
170
+ const builtVariants = (variants.length ? variants : [null]).map((v, i) => v
171
+ ? buildVariant(v, i)
172
+ : {
173
+ // Single-variant fallback for products with no explicit variants.
174
+ sku: product.id,
175
+ name: product.title || "Default",
176
+ idempotence_token: `${product.id}:default`,
177
+ available_quantity: 0,
178
+ });
113
179
  const product_input = {
114
- brand_id: input.brand_id,
115
180
  name: (product.title || "Untitled Product").slice(0, 140),
181
+ idempotence_token: product.id,
182
+ lifecycle_state,
183
+ taxonomy_type: { id: taxonomyTypeId },
116
184
  description: product.description || "",
117
- wholesale_price_cents: minWholesale || undefined,
118
- retail_price_cents: minRetail || undefined,
119
- images,
120
- variants: variants.length ? variants.map(buildVariant) : undefined,
121
- tags,
122
185
  short_description: typeof metadata.faire_short_description === "string"
123
186
  ? metadata.faire_short_description
124
187
  : undefined,
188
+ images,
189
+ variants: builtVariants,
125
190
  };
126
191
  return new workflows_sdk_1.StepResponse({
127
192
  product_id: input.product_id,
@@ -144,9 +209,11 @@ const syncProductStep = (0, workflows_sdk_1.createStep)("faire-sync-product-step
144
209
  product = await client.updateProduct(access_token, existing_product_token, {
145
210
  name: product_input.name,
146
211
  description: product_input.description,
212
+ short_description: product_input.short_description,
213
+ lifecycle_state: product_input.lifecycle_state,
214
+ taxonomy_type: product_input.taxonomy_type,
147
215
  images: product_input.images,
148
216
  variants: product_input.variants,
149
- tags: product_input.tags,
150
217
  });
151
218
  }
152
219
  else {
@@ -163,7 +230,7 @@ const syncProductStep = (0, workflows_sdk_1.createStep)("faire-sync-product-step
163
230
  try {
164
231
  const levels = product_input.variants.map((v) => ({
165
232
  sku: v.sku,
166
- current_count: v.inventory_count ?? 0,
233
+ on_hand_quantity: v.available_quantity ?? 0,
167
234
  }));
168
235
  await client.updateInventory(access_token, levels);
169
236
  }
@@ -242,6 +309,10 @@ exports.syncProductToFaireWorkflow = (0, workflows_sdk_1.createWorkflow)(exports
242
309
  product_id: data.input.product_id,
243
310
  settings: data.config.settings,
244
311
  brand_id: data.config.brand_id,
312
+ currency: data.config.currency,
313
+ country: data.config.country,
314
+ access_token: data.config.access_token,
315
+ auth_mode: data.config.auth_mode,
245
316
  })));
246
317
  const result = syncProductStep((0, workflows_sdk_1.transform)({ config, prepared }, (data) => ({
247
318
  config: data.config,
@@ -260,4 +331,4 @@ exports.syncProductToFaireWorkflow = (0, workflows_sdk_1.createWorkflow)(exports
260
331
  warnings: result.warnings,
261
332
  });
262
333
  });
263
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wcm9kdWN0LXRvLWZhaXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9zeW5jLXByb2R1Y3QtdG8tZmFpcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBTzBDO0FBQzFDLHFEQUE4RTtBQUc5RSxzREFBeUQ7QUFPNUMsUUFBQSxxQkFBcUIsR0FBRyxvQkFBb0IsQ0FBQTtBQTZCekQ7OztHQUdHO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLE9BQXdCLEVBQWlCLEVBQUU7SUFDcEUsSUFBSSxPQUFPLENBQUMsR0FBRztRQUFFLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQTtJQUNuQyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWE7UUFBRSxPQUFPLElBQUksQ0FBQTtJQUN2QyxPQUFPLHdDQUF3QyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUE7QUFDeEUsQ0FBQyxDQUFBO0FBRUQsNEVBQTRFO0FBRTVFLE1BQU0sc0JBQXNCLEdBQUcsSUFBQSwwQkFBVSxFQUN2QywyQkFBMkIsRUFDM0IsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUF5QyxFQUFFO0lBQ2hFLE1BQU0sT0FBTyxHQUFxQixTQUFTLENBQUMsT0FBTyxDQUFDLDhCQUFpQixDQUFDLENBQUE7SUFDdEUsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtJQUNoRCxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUM1QyxPQUFPLElBQUksNEJBQVksQ0FBQztRQUN0QixVQUFVLEVBQUUsT0FBTyxDQUFDLEVBQUU7UUFDdEIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1FBQzFCLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtRQUNsQyxTQUFTLEVBQUcsT0FBTyxDQUFDLFNBQWdDLElBQUksT0FBTztRQUMvRCxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsSUFBSSxJQUFJO1FBQ2xDLFFBQVE7S0FDVCxDQUFDLENBQUE7QUFDSixDQUFDLENBQ0YsQ0FBQTtBQUVELDRFQUE0RTtBQUU1RSxNQUFNLGtCQUFrQixHQUFHLElBQUEsMEJBQVUsRUFDbkMsNEJBQTRCLEVBQzVCLEtBQUssRUFDSCxLQUE4RCxFQUM5RCxFQUFFLFNBQVMsRUFBRSxFQUMyQixFQUFFO0lBQzFDLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQzdCLGlDQUF5QixDQUFDLEtBQUssQ0FDSyxDQUFBO0lBQ3RDLE1BQU0sVUFBVSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsSUFBSSxDQUFTLENBQUE7SUFDNUUsTUFBTSxPQUFPLEdBQXFCLFNBQVMsQ0FBQyxPQUFPLENBQUMsOEJBQWlCLENBQUMsQ0FBQTtJQUV0RSxNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQztRQUMzQyxNQUFNLEVBQUUsU0FBUztRQUNqQixNQUFNLEVBQUU7WUFDTixJQUFJO1lBQ0osT0FBTztZQUNQLGFBQWE7WUFDYixRQUFRO1lBQ1IsVUFBVTtZQUNWLFFBQVE7WUFDUixZQUFZO1lBQ1osbUJBQW1CO1lBQ25CLDRCQUE0QjtZQUM1QixVQUFVO1lBQ1YsY0FBYztTQUNmO1FBQ0QsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxVQUFVLEVBQUU7S0FDbEMsQ0FBQyxDQUFBO0lBRUYsTUFBTSxPQUFPLEdBQVEsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDbEMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssQ0FBQyxVQUFVLFlBQVksQ0FBQyxDQUFBO0lBQzFELENBQUM7SUFFRCw2Q0FBNkM7SUFDN0MsSUFBSSxzQkFBc0IsR0FBa0IsSUFBSSxDQUFBO0lBQ2hELE1BQU0sT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDLGdCQUFnQixFQUFFLENBQUE7SUFDaEQsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUNaLElBQUksQ0FBQztZQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sVUFBVSxDQUFDLElBQUksQ0FBQztnQkFDckMsQ0FBQyxlQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVUsRUFBRTtnQkFDbkQsQ0FBQyw4QkFBaUIsQ0FBQyxFQUFFLEVBQUUscUJBQXFCLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRTthQUMzRCxDQUFDLENBQUE7WUFDRixNQUFNLEdBQUcsR0FBUyxRQUFrQixFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUE7WUFDekMsc0JBQXNCLEdBQUcsR0FBRyxFQUFFLG1CQUFtQixJQUFJLElBQUksQ0FBQTtRQUMzRCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsY0FBYztRQUNoQixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUE7SUFDL0IsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUE7SUFDdkMsTUFBTSxRQUFRLEdBQVUsT0FBTyxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUE7SUFFOUMseUVBQXlFO0lBQ3pFLDhEQUE4RDtJQUM5RCxNQUFNLE9BQU8sR0FBRyxDQUFDLE1BQVcsRUFBVSxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFBO0lBRTlFLE1BQU0sYUFBYSxHQUNqQixNQUFNLENBQUMsUUFBUSxDQUFDLDhCQUE4QixJQUFJLFFBQVEsQ0FBQyxnQ0FBZ0MsQ0FBQztRQUM1RixDQUFDLENBQUE7SUFFSCxNQUFNLFlBQVksR0FBRyxDQUFDLENBQU0sRUFBRSxFQUFFO1FBQzlCLE1BQU0sTUFBTSxHQUFVLENBQUMsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFBO1FBQ3BDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ2hELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ3ZELE1BQU0sY0FBYyxHQUNsQixhQUFhLEdBQUcsQ0FBQztZQUNmLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsV0FBVyxHQUFHLENBQUMsR0FBRyxHQUFHLGFBQWEsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDO1lBQ3pELENBQUMsQ0FBQyxXQUFXLENBQUE7UUFDakIsT0FBTztZQUNMLEdBQUcsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxFQUFFO1lBQ2xCLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxJQUFJLFNBQVM7WUFDMUIsa0JBQWtCLEVBQUUsV0FBVyxJQUFJLFNBQVM7WUFDNUMscUJBQXFCLEVBQUUsY0FBYyxJQUFJLFNBQVM7WUFDbEQsZUFBZSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDO1NBQ25ELENBQUE7SUFDSCxDQUFDLENBQUE7SUFFRCwyRUFBMkU7SUFDM0UsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUN6RCxNQUFNLFNBQVMsR0FDYixTQUFTO1NBQ04sR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1NBQzdCLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNwQixJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQ2xDLE1BQU0sWUFBWSxHQUNoQixhQUFhLEdBQUcsQ0FBQztRQUNmLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxHQUFHLENBQUMsR0FBRyxHQUFHLGFBQWEsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDO1FBQ3ZELENBQUMsQ0FBQyxTQUFTLENBQUE7SUFFZixNQUFNLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1NBQzlCLEdBQUcsQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztTQUN4QixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7SUFFbEIsTUFBTSxNQUFNLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztTQUNsQyxHQUFHLENBQUMsQ0FBQyxHQUFRLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7U0FDckMsTUFBTSxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUE7SUFFNUIsTUFBTSxhQUFhLEdBQXVCO1FBQ3hDLFFBQVEsRUFBRSxLQUFLLENBQUMsUUFBUTtRQUN4QixJQUFJLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxJQUFJLGtCQUFrQixDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUM7UUFDekQsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXLElBQUksRUFBRTtRQUN0QyxxQkFBcUIsRUFBRSxZQUFZLElBQUksU0FBUztRQUNoRCxrQkFBa0IsRUFBRSxTQUFTLElBQUksU0FBUztRQUMxQyxNQUFNO1FBQ04sUUFBUSxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVM7UUFDbEUsSUFBSTtRQUNKLGlCQUFpQixFQUNmLE9BQU8sUUFBUSxDQUFDLHVCQUF1QixLQUFLLFFBQVE7WUFDbEQsQ0FBQyxDQUFDLFFBQVEsQ0FBQyx1QkFBdUI7WUFDbEMsQ0FBQyxDQUFDLFNBQVM7S0FDaEIsQ0FBQTtJQUVELE9BQU8sSUFBSSw0QkFBWSxDQUFDO1FBQ3RCLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtRQUM1QixhQUFhLEVBQUUsT0FBTyxDQUFDLEtBQUs7UUFDNUIsY0FBYyxFQUFFLE9BQU8sQ0FBQyxNQUFNO1FBQzlCLGFBQWE7UUFDYixzQkFBc0I7S0FDdkIsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUNGLENBQUE7QUFFRCw0RUFBNEU7QUFFNUUsTUFBTSxlQUFlLEdBQUcsSUFBQSwwQkFBVSxFQUNoQyx5QkFBeUIsRUFDekIsS0FBSyxFQUNILEtBR0MsRUFDRCxFQUFFLFNBQVMsRUFBRSxFQUNzQixFQUFFO0lBQ3JDLE1BQU0sT0FBTyxHQUFxQixTQUFTLENBQUMsT0FBTyxDQUFDLDhCQUFpQixDQUFDLENBQUE7SUFDdEUsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQ3hELE1BQU0sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQTtJQUMvQyxNQUFNLEVBQUUsYUFBYSxFQUFFLHNCQUFzQixFQUFFLGNBQWMsRUFBRSxHQUM3RCxLQUFLLENBQUMsUUFBUSxDQUFBO0lBRWhCLE1BQU0sUUFBUSxHQUFhLEVBQUUsQ0FBQTtJQUM3QixJQUFJLE9BQXdCLENBQUE7SUFFNUIsSUFBSSxDQUFDO1FBQ0gsSUFBSSxzQkFBc0IsRUFBRSxDQUFDO1lBQzNCLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLHNCQUFzQixFQUFFO2dCQUN6RSxJQUFJLEVBQUUsYUFBYSxDQUFDLElBQUk7Z0JBQ3hCLFdBQVcsRUFBRSxhQUFhLENBQUMsV0FBVztnQkFDdEMsTUFBTSxFQUFFLGFBQWEsQ0FBQyxNQUFNO2dCQUM1QixRQUFRLEVBQUUsYUFBYSxDQUFDLFFBQVE7Z0JBQ2hDLElBQUksRUFBRSxhQUFhLENBQUMsSUFBSTthQUN6QixDQUFDLENBQUE7UUFDSixDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sR0FBRyxNQUFNLE1BQU0sQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLGFBQWEsQ0FBQyxDQUFBO1FBQ25FLENBQUM7SUFDSCxDQUFDO0lBQUMsT0FBTyxHQUFRLEVBQUUsQ0FBQztRQUNsQiw4REFBOEQ7UUFDOUQsUUFBUSxDQUFDLElBQUksQ0FBQyxpQ0FBaUMsR0FBRyxFQUFFLE9BQU8sSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFBO1FBQ3JFLE1BQU0sR0FBRyxDQUFBO0lBQ1gsQ0FBQztJQUVELDBDQUEwQztJQUMxQyxJQUFJLGFBQWEsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsYUFBYSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ2hELEdBQUcsRUFBRSxDQUFDLENBQUMsR0FBRztnQkFDVixhQUFhLEVBQUUsQ0FBQyxDQUFDLGVBQWUsSUFBSSxDQUFDO2FBQ3RDLENBQUMsQ0FBQyxDQUFBO1lBQ0gsTUFBTSxNQUFNLENBQUMsZUFBZSxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQTtRQUNwRCxDQUFDO1FBQUMsT0FBTyxHQUFRLEVBQUUsQ0FBQztZQUNsQixRQUFRLENBQUMsSUFBSSxDQUFDLDBCQUEwQixHQUFHLEVBQUUsT0FBTyxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUE7UUFDaEUsQ0FBQztJQUNILENBQUM7SUFFRCwyQ0FBMkM7SUFDM0MsTUFBTSxhQUFhLEdBQ2pCLFFBQVEsQ0FBQyxxQkFBcUIsS0FBSyxLQUFLLElBQUksY0FBYyxLQUFLLFdBQVcsQ0FBQTtJQUM1RSxNQUFNLFNBQVMsR0FBRyxhQUFhLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxRQUFRLENBQUE7SUFFN0QsT0FBTyxJQUFJLDRCQUFZLENBQUM7UUFDdEIsT0FBTztRQUNQLFNBQVM7UUFDVCxRQUFRO0tBQ1QsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxFQUNELEtBQUssSUFBSSxFQUFFLEdBQUUsQ0FBQyxDQUNmLENBQUE7QUFFRCw0RUFBNEU7QUFFNUUsTUFBTSxxQkFBcUIsR0FBRyxJQUFBLDBCQUFVLEVBQ3RDLGdDQUFnQyxFQUNoQyxLQUFLLEVBQ0gsS0FJQyxFQUNELEVBQUUsU0FBUyxFQUFFLEVBQ2dCLEVBQUU7SUFDL0IsTUFBTSxPQUFPLEdBQXFCLFNBQVMsQ0FBQyxPQUFPLENBQUMsOEJBQWlCLENBQUMsQ0FBQTtJQUN0RSxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLElBQUksQ0FBUyxDQUFBO0lBRTVFLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQTtJQUMxQyxNQUFNLE1BQU0sR0FBd0IsTUFBTSxDQUFDLFNBQVM7UUFDbEQsQ0FBQyxDQUFDLFNBQVM7UUFDWCxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEtBQUssT0FBTztZQUNoQyxDQUFDLENBQUMsT0FBTztZQUNULENBQUMsQ0FBQyxTQUFTLENBQUE7SUFFZixNQUFNLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztRQUM3QixVQUFVLEVBQUUsUUFBUSxDQUFDLFVBQVU7UUFDL0IsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO1FBQzdCLGFBQWEsRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWE7UUFDM0MsV0FBVyxFQUFFLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDOUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSztRQUNuQyxNQUFNLEVBQUUsUUFBUSxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVE7UUFDN0QsTUFBTTtRQUNOLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztRQUMzQixhQUFhLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJO1FBQzFFLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtRQUN6QixRQUFRLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLGFBQWEsRUFBRTtRQUMzQyxTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUU7S0FDZixDQUFDLENBQUE7SUFFVCxJQUFJLENBQUM7UUFDSCxNQUFNLFVBQVUsQ0FBQyxPQUFPLENBQUM7WUFDdkI7Z0JBQ0UsQ0FBQyxlQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsUUFBUSxDQUFDLFVBQVUsRUFBRTtnQkFDdEQsQ0FBQyw4QkFBaUIsQ0FBQyxFQUFFLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRTthQUNsRTtTQUNGLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCx3QkFBd0I7SUFDMUIsQ0FBQztJQUVELE1BQU0sVUFBVSxDQUFDLE1BQU0sQ0FBQztRQUN0QjtZQUNFLENBQUMsZUFBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLEVBQUU7WUFDdEQsQ0FBQyw4QkFBaUIsQ0FBQyxFQUFFLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUNqRSxJQUFJLEVBQUU7Z0JBQ0osbUJBQW1CLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhO2dCQUNqRCxTQUFTLEVBQUUsaUJBQWlCLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQztnQkFDNUMsV0FBVyxFQUFFLFFBQVE7Z0JBQ3JCLGNBQWMsRUFBRSxJQUFJLElBQUksRUFBRTtnQkFDMUIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSTtnQkFDdkUsUUFBUSxFQUFFO29CQUNSLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztvQkFDM0IsS0FBSyxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSztvQkFDM0IsY0FBYyxFQUFFLFFBQVEsQ0FBQyxjQUFjO2lCQUN4QzthQUNGO1NBQ0Y7S0FDRixDQUFDLENBQUE7SUFFRixPQUFPLElBQUksNEJBQVksRUFBRSxDQUFBO0FBQzNCLENBQUMsQ0FDRixDQUFBO0FBRUQsNEVBQTRFO0FBRS9ELFFBQUEsMEJBQTBCLEdBQUcsSUFBQSw4QkFBYyxFQUN0RCw2QkFBcUIsRUFDckIsQ0FBQyxLQUE0QyxFQUFFLEVBQUU7SUFDL0MsTUFBTSxNQUFNLEdBQUcsc0JBQXNCLEVBQUUsQ0FBQTtJQUN2QyxNQUFNLFFBQVEsR0FBRyxrQkFBa0IsQ0FDakMsSUFBQSx5QkFBUyxFQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3RDLFVBQVUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVU7UUFDakMsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUTtRQUM5QixRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRO0tBQy9CLENBQUMsQ0FBQyxDQUNKLENBQUE7SUFFRCxNQUFNLE1BQU0sR0FBRyxlQUFlLENBQzVCLElBQUEseUJBQVMsRUFBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN6QyxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07UUFDbkIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO0tBQ3hCLENBQUMsQ0FBQyxDQUNKLENBQUE7SUFFRCxxQkFBcUIsQ0FDbkIsSUFBQSx5QkFBUyxFQUFDLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqRCxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07UUFDbkIsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1FBQ3ZCLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtLQUNwQixDQUFDLENBQUMsQ0FDSixDQUFBO0lBRUQsT0FBTyxJQUFJLGdDQUFnQixDQUFDO1FBQzFCLGFBQWEsRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLGFBQWE7UUFDM0MsV0FBVyxFQUFFLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUM7UUFDOUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTO1FBQzNCLEtBQUssRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUs7UUFDM0IsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRO0tBQzFCLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FDRixDQUFBIn0=
334
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wcm9kdWN0LXRvLWZhaXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9zeW5jLXByb2R1Y3QtdG8tZmFpcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBTzBDO0FBQzFDLHFEQUEyRjtBQUczRixzREFBeUQ7QUFPNUMsUUFBQSxxQkFBcUIsR0FBRyxvQkFBb0IsQ0FBQTtBQThCekQ7OztHQUdHO0FBQ0gsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLE9BQXdCLEVBQWlCLEVBQUU7SUFDcEUsSUFBSSxPQUFPLENBQUMsR0FBRztRQUFFLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQTtJQUNuQyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWE7UUFBRSxPQUFPLElBQUksQ0FBQTtJQUN2QyxPQUFPLHdDQUF3QyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUE7QUFDeEUsQ0FBQyxDQUFBO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sY0FBYyxHQUFHLENBQ3JCLFFBQWdCLEVBQ2hCLE9BQXNCLEVBQ3dCLEVBQUU7SUFDaEQsUUFBUSxRQUFRLEVBQUUsQ0FBQztRQUNqQixLQUFLLEtBQUs7WUFDUixPQUFPLEVBQUUsYUFBYSxFQUFFLGdCQUFnQixFQUFFLENBQUE7UUFDNUMsS0FBSyxLQUFLO1lBQ1IsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQTtRQUMxQixLQUFLLEtBQUs7WUFDUixPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFBO1FBQzFCLEtBQUssS0FBSztZQUNSLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUE7UUFDMUIsS0FBSyxLQUFLO1lBQ1IsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQTtRQUMxQjtZQUNFLE9BQU8sT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLGFB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jytextiles/medusa-plugin-faire-store-sync",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -15,6 +15,15 @@ const fetchMock = jest.fn(async (url: string, init: any) => {
15
15
  } as any
16
16
  })
17
17
 
18
+ // Shared taxonomy types fixture (matches the shape Faire returns).
19
+ const taxonomyTypes = [
20
+ { id: "tt_1", name: "Apparel" },
21
+ { id: "tt_2", name: "Accessories" },
22
+ { id: "tt_3", name: "Home & Living" },
23
+ { id: "tt_4", name: "Dresses" },
24
+ { id: "tt_5", name: "Address Book" },
25
+ ]
26
+
18
27
  ;(global as any).fetch = fetchMock
19
28
 
20
29
  const oauthOpts = {
@@ -30,7 +39,7 @@ describe("FaireClient — issue #952 corrections", () => {
30
39
  it("uses the verified base / auth / token URLs by default", () => {
31
40
  const c = new FaireClient({})
32
41
  // defaults are exported from types and consumed verbatim
33
- expect(DEFAULT_API_BASE).toBe("https://faire.com/external-api/v2")
42
+ expect(DEFAULT_API_BASE).toBe("https://www.faire.com/external-api/v2")
34
43
  expect(DEFAULT_AUTH_URL).toBe("https://faire.com/oauth2/authorize")
35
44
  expect(DEFAULT_TOKEN_URL).toBe("https://www.faire.com/api/external-api-oauth2/token")
36
45
  })
@@ -94,23 +103,45 @@ describe("FaireClient — issue #952 corrections", () => {
94
103
 
95
104
  it("pushes inventory via PATCH /product-inventory/by-skus (not GET /inventory)", async () => {
96
105
  const c = new FaireClient(oauthOpts)
97
- await c.updateInventory("t", [{ sku: "S1", current_count: 7 }])
106
+ await c.updateInventory("t", [{ sku: "S1", on_hand_quantity: 7 }])
98
107
  expect(lastInit.method).toBe("PATCH")
99
108
  expect(lastUrl).toBe(`${DEFAULT_API_BASE}/product-inventory/by-skus`)
100
109
  expect(JSON.parse(lastInit.body)).toEqual({
101
- inventories: [{ sku: "S1", current_count: 7 }],
110
+ inventories: [{ sku: "S1", on_hand_quantity: 7 }],
102
111
  })
103
112
  })
104
113
 
105
- it("lists orders with cursor page + updated_at_min", async () => {
114
+ it("lists orders with numeric page + updated_at_min", async () => {
106
115
  const c = new FaireClient(oauthOpts)
107
- await c.listOrders("t", { page: "cursor-xyz", updated_at_min: "2026-01-01T00:00:00Z" })
116
+ await c.listOrders("t", { page: "2", updated_at_min: "2026-01-01T00:00:00Z" })
108
117
  const url = new URL(lastUrl)
109
118
  expect(url.pathname).toBe("/external-api/v2/orders")
110
- expect(url.searchParams.get("page")).toBe("cursor-xyz")
119
+ expect(url.searchParams.get("page")).toBe("2")
111
120
  expect(url.searchParams.get("updated_at_min")).toBe("2026-01-01T00:00:00Z")
112
121
  })
113
122
 
123
+ it("derives next_page from numeric page (Faire returns no cursor)", async () => {
124
+ const c = new FaireClient(oauthOpts)
125
+ const page = (rows: number) => ({
126
+ ok: true,
127
+ status: 200,
128
+ headers: new Map(),
129
+ text: async () =>
130
+ JSON.stringify({
131
+ page: undefined,
132
+ orders: Array.from({ length: rows }, (_, i) => ({ id: `bo_${i}` })),
133
+ }),
134
+ })
135
+ // A full page (rows === limit) → there may be more → next_page = current+1.
136
+ fetchMock.mockImplementationOnce(async () => page(2) as any)
137
+ const full = await c.listOrders("t", { limit: 2, page: "1" })
138
+ expect(full.next_page).toBe("2")
139
+ // A short page → last page → no next_page.
140
+ fetchMock.mockImplementationOnce(async () => page(1) as any)
141
+ const short = await c.listOrders("t", { limit: 2, page: "2" })
142
+ expect(short.next_page).toBeUndefined()
143
+ })
144
+
114
145
  it("posts order processing (PUT) and shipments (POST) on the right paths", async () => {
115
146
  const c = new FaireClient(oauthOpts)
116
147
  await c.setOrderProcessing("t", "o_1", { accepted: true })
@@ -136,3 +167,101 @@ describe("FaireClient — issue #952 corrections", () => {
136
167
  })
137
168
  })
138
169
  })
170
+
171
+ describe("FaireClient.resolveTaxonomyTypeId", () => {
172
+ beforeEach(() => {
173
+ fetchMock.mockClear()
174
+ // Reset the cache on each test by creating a fresh client.
175
+ })
176
+
177
+ it("passes a tt_ id straight through without an API call", async () => {
178
+ const c = new FaireClient(oauthOpts)
179
+ const result = await c.resolveTaxonomyTypeId("tok", "tt_abc123")
180
+ expect(result).toBe("tt_abc123")
181
+ expect(fetchMock).not.toHaveBeenCalled()
182
+ })
183
+
184
+ it("returns null for empty / falsy input", async () => {
185
+ const c = new FaireClient(oauthOpts)
186
+ await expect(c.resolveTaxonomyTypeId("tok", "")).resolves.toBeNull()
187
+ await expect(c.resolveTaxonomyTypeId("tok", "")).resolves.toBeNull()
188
+ expect(fetchMock).not.toHaveBeenCalled()
189
+ })
190
+
191
+ it("fetches taxonomy types on first call, caches, and resolves by exact name", async () => {
192
+ fetchMock.mockImplementationOnce(async () => ({
193
+ ok: true,
194
+ status: 200,
195
+ headers: new Map(),
196
+ text: async () => JSON.stringify({ taxonomy_types: taxonomyTypes }),
197
+ } as any))
198
+ const c = new FaireClient(oauthOpts)
199
+ const result = await c.resolveTaxonomyTypeId("tok", "Dresses")
200
+ expect(result).toBe("tt_4")
201
+ expect(fetchMock).toHaveBeenCalledTimes(1)
202
+ const callUrl = fetchMock.mock.calls[0][0] as string
203
+ expect(callUrl).toContain("/products/types")
204
+
205
+ // Second call uses the cache — no additional fetch.
206
+ const cached = await c.resolveTaxonomyTypeId("tok", "Accessories")
207
+ expect(cached).toBe("tt_2")
208
+ expect(fetchMock).toHaveBeenCalledTimes(1)
209
+ })
210
+
211
+ it("prefers whole-word match over loose substring (Dress vs Address Book)", async () => {
212
+ fetchMock.mockImplementationOnce(async () => ({
213
+ ok: true,
214
+ status: 200,
215
+ headers: new Map(),
216
+ text: async () => JSON.stringify({ taxonomy_types: taxonomyTypes }),
217
+ } as any))
218
+ const c = new FaireClient(oauthOpts)
219
+ // "Dress" should match "Dresses" (word-boundary) not "Address Book".
220
+ const result = await c.resolveTaxonomyTypeId("tok", "Dress")
221
+ expect(result).toBe("tt_4")
222
+ })
223
+
224
+ it("falls back to substring match when whole-word finds nothing", async () => {
225
+ fetchMock.mockImplementationOnce(async () => ({
226
+ ok: true,
227
+ status: 200,
228
+ headers: new Map(),
229
+ text: async () => JSON.stringify({ taxonomy_types: taxonomyTypes }),
230
+ } as any))
231
+ const c = new FaireClient(oauthOpts)
232
+ // "ccessori" is not a whole word but a substring of "Accessories".
233
+ const result = await c.resolveTaxonomyTypeId("tok", "ccessori")
234
+ expect(result).toBe("tt_2")
235
+ })
236
+
237
+ it("returns null when no taxonomy type matches — the condition that triggers the MedusaError", async () => {
238
+ fetchMock.mockImplementationOnce(async () => ({
239
+ ok: true,
240
+ status: 200,
241
+ headers: new Map(),
242
+ text: async () => JSON.stringify({ taxonomy_types: taxonomyTypes }),
243
+ } as any))
244
+ const c = new FaireClient(oauthOpts)
245
+ const result = await c.resolveTaxonomyTypeId("tok", "NonExistentCategory")
246
+ expect(result).toBeNull()
247
+ })
248
+
249
+ it("handles alternate response shapes (product_types / types / results)", async () => {
250
+ for (const key of ["product_types", "types", "results"]) {
251
+ fetchMock.mockImplementationOnce(async () => ({
252
+ ok: true,
253
+ status: 200,
254
+ headers: new Map(),
255
+ text: async () => JSON.stringify({ [key]: taxonomyTypes }),
256
+ } as any))
257
+ }
258
+ const c = new FaireClient(oauthOpts)
259
+ // Each call should reset the cache because we used a fresh client.
260
+ const c1 = new FaireClient(oauthOpts)
261
+ expect(await c1.resolveTaxonomyTypeId("tok", "Apparel")).toBe("tt_1")
262
+ const c2 = new FaireClient(oauthOpts)
263
+ expect(await c2.resolveTaxonomyTypeId("tok", "Accessories")).toBe("tt_2")
264
+ const c3 = new FaireClient(oauthOpts)
265
+ expect(await c3.resolveTaxonomyTypeId("tok", "Home & Living")).toBe("tt_3")
266
+ })
267
+ })
@@ -66,6 +66,69 @@ describe("mapFaireOrderToOrder", () => {
66
66
  expect(mapped.items).toEqual([])
67
67
  })
68
68
 
69
+ it("maps a real ExternalOrderV2 (customer/address/item.price, no top-level total)", () => {
70
+ const order = {
71
+ id: "bo_bxdmjbwxid",
72
+ state: "NEW",
73
+ customer: { first_name: "John", last_name: "Smith" },
74
+ address: {
75
+ name: "John Smith",
76
+ company_name: "Faire Wholesale, Inc",
77
+ address1: "41 King Street West",
78
+ address2: "3rd Floor",
79
+ city: "Kitchener",
80
+ state: "Ontario",
81
+ state_code: "ON",
82
+ postal_code: "N2G 1A1",
83
+ country: "Canada",
84
+ country_code: "CAN",
85
+ phone_number: "555-123-4567",
86
+ },
87
+ items: [
88
+ {
89
+ id: "oi_bq425ju5vh",
90
+ product_id: "p_fccaefnahr",
91
+ variant_id: "po_3745tjzrpc",
92
+ sku: "goldenretriever",
93
+ quantity: 2,
94
+ product_name: "Golden Dog",
95
+ price: { amount_minor: 4999, currency: "USD" },
96
+ },
97
+ ],
98
+ payout_costs: { total_payout: { amount_minor: 8000, currency: "USD" } },
99
+ }
100
+
101
+ const mapped = mapFaireOrderToOrder(order)
102
+
103
+ expect(mapped.order_token).toBe("bo_bxdmjbwxid")
104
+ expect(mapped.currency_code).toBe("usd")
105
+ // no order-level total → sum of line values: 49.99 × 2
106
+ expect(mapped.total).toBe(99.98)
107
+ expect(mapped.buyer_name).toBe("John Smith")
108
+ expect(mapped.shipping_address).toMatchObject({
109
+ first_name: "John",
110
+ last_name: "Smith",
111
+ company: "Faire Wholesale, Inc",
112
+ address_1: "41 King Street West",
113
+ address_2: "3rd Floor",
114
+ city: "Kitchener",
115
+ province: "ON",
116
+ postal_code: "N2G 1A1",
117
+ country_code: "ca", // ISO-3 CAN → ISO-2 ca
118
+ phone: "555-123-4567",
119
+ })
120
+ expect(mapped.items[0]).toMatchObject({
121
+ title: "Golden Dog",
122
+ quantity: 2,
123
+ unit_price: 49.99,
124
+ })
125
+ expect(mapped.items[0].metadata).toMatchObject({
126
+ faire_product_token: "p_fccaefnahr",
127
+ faire_variant_id: "po_3745tjzrpc",
128
+ faire_sku: "goldenretriever",
129
+ })
130
+ })
131
+
69
132
  it("uses buyer email when provided", () => {
70
133
  const mapped = mapFaireOrderToOrder({
71
134
  order_token: "o_2",
@@ -84,6 +84,10 @@ export const faireApi = {
84
84
  retrySync: (id: string) =>
85
85
  sdk.client.fetch(`/admin/faire/syncs/${id}`, { method: "POST" }),
86
86
  brand: () => sdk.client.fetch("/admin/faire/brand"),
87
+ taxonomy: () =>
88
+ sdk.client.fetch<{ taxonomy: Array<{ id: string; name: string }> }>(
89
+ "/admin/faire/taxonomy"
90
+ ),
87
91
  products: (opts: { limit?: number; page?: string; updated_at_min?: string } = {}) => {
88
92
  const query: Record<string, string> = {}
89
93
  if (opts.limit !== undefined) query.limit = String(opts.limit)