@thorprovider/adapters 4.1.0 → 4.2.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/CHANGELOG.md +17 -0
- package/README.md +36 -2
- package/dist/index.d.mts +171 -2
- package/dist/index.d.ts +171 -2
- package/dist/index.js +2102 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2098 -0
- package/dist/index.mjs.map +1 -1
- package/docs/capabilities-system.md +30 -0
- package/docs/getting-started.md +32 -11
- package/docs/providers-overview.md +23 -3
- package/docs/services-overview.md +16 -0
- package/package.json +10 -6
- package/quick-reference.md +1 -0
- package/src/factory/index.ts +8 -0
- package/src/index.ts +6 -0
- package/src/providers/index.ts +6 -0
- package/src/providers/mock/index.ts +427 -0
- package/src/providers/mock/mock.ts +917 -0
- package/src/providers/stelorder/client.test-helpers.ts +3 -0
- package/src/providers/stelorder/client.test.ts +58 -0
- package/src/providers/stelorder/client.ts +326 -0
- package/src/providers/stelorder/index.test.ts +48 -0
- package/src/providers/stelorder/index.ts +685 -0
- package/src/providers/stelorder/live-smoke.test.ts +54 -0
- package/src/providers/stelorder/transforms.test.ts +103 -0
- package/src/providers/stelorder/transforms.ts +631 -0
- package/src/types/capabilities.types.ts +84 -0
- package/vitest.config.ts +13 -0
- package/vitest.setup.ts +6 -0
- package/.turbo/turbo-build.log +0 -18
- package/.turbo/turbo-test.log +0 -1
- package/.turbo/turbo-type-check.log +0 -0
- package/dist/.tsbuildinfo +0 -1
- package/publish.log +0 -93
package/dist/index.js
CHANGED
|
@@ -44,17 +44,21 @@ __export(src_exports, {
|
|
|
44
44
|
ConfigurationError: () => ConfigurationError,
|
|
45
45
|
MAGENTO_CAPABILITIES: () => MAGENTO_CAPABILITIES,
|
|
46
46
|
MEDUSA_CAPABILITIES: () => MEDUSA_CAPABILITIES,
|
|
47
|
+
MOCK_CAPABILITIES: () => MOCK_CAPABILITIES,
|
|
47
48
|
MagentoProvider: () => MagentoProvider,
|
|
48
49
|
MedusaMetadataAdapter: () => MedusaMetadataAdapter,
|
|
49
50
|
MedusaProvider: () => MedusaProvider,
|
|
50
51
|
MetricsService: () => MetricsService,
|
|
52
|
+
MockProvider: () => MockProvider,
|
|
51
53
|
ProviderAPIError: () => ProviderAPIError,
|
|
52
54
|
ProviderNotFoundError: () => ProviderNotFoundError,
|
|
53
55
|
ResourceNotFoundError: () => ResourceNotFoundError,
|
|
54
56
|
SHOPIFY_CAPABILITIES: () => SHOPIFY_CAPABILITIES,
|
|
55
57
|
SPREE_CAPABILITIES: () => SPREE_CAPABILITIES,
|
|
58
|
+
STELORDER_CAPABILITIES: () => STELORDER_CAPABILITIES,
|
|
56
59
|
ShopifyProvider: () => ShopifyProvider,
|
|
57
60
|
SpreeProvider: () => SpreeProvider,
|
|
61
|
+
StelOrderProvider: () => StelOrderProvider,
|
|
58
62
|
StorefrontConfigError: () => import_types2.StorefrontConfigError,
|
|
59
63
|
WOOCOMMERCE_CAPABILITIES: () => WOOCOMMERCE_CAPABILITIES,
|
|
60
64
|
WooCommerceProvider: () => WooCommerceProvider,
|
|
@@ -94,6 +98,31 @@ module.exports = __toCommonJS(src_exports);
|
|
|
94
98
|
var import_types2 = require("@thorprovider/types");
|
|
95
99
|
|
|
96
100
|
// src/types/capabilities.types.ts
|
|
101
|
+
var MOCK_CAPABILITIES = {
|
|
102
|
+
updateProfile: false,
|
|
103
|
+
updateEmail: false,
|
|
104
|
+
changePasswordDirect: false,
|
|
105
|
+
changePasswordViaEmail: false,
|
|
106
|
+
deleteAccount: false,
|
|
107
|
+
uploadAvatar: false,
|
|
108
|
+
avatarViaMetadata: false,
|
|
109
|
+
customAttributes: false,
|
|
110
|
+
fetchOrders: true,
|
|
111
|
+
cancelOrder: true,
|
|
112
|
+
manageAddresses: false,
|
|
113
|
+
defaultAddress: false,
|
|
114
|
+
applyDiscounts: true,
|
|
115
|
+
shippingCalculation: true,
|
|
116
|
+
guestCheckout: true,
|
|
117
|
+
savedPaymentMethods: false,
|
|
118
|
+
listPaymentProviders: true,
|
|
119
|
+
regionSpecificPayments: true,
|
|
120
|
+
wishlist: false,
|
|
121
|
+
advancedSearch: false,
|
|
122
|
+
facetedFilters: false,
|
|
123
|
+
productReviews: false,
|
|
124
|
+
loyaltyProgram: false
|
|
125
|
+
};
|
|
97
126
|
var MEDUSA_CAPABILITIES = {
|
|
98
127
|
// Profile Management
|
|
99
128
|
updateProfile: true,
|
|
@@ -136,6 +165,41 @@ var MEDUSA_CAPABILITIES = {
|
|
|
136
165
|
loyaltyProgram: false
|
|
137
166
|
// Requires custom implementation
|
|
138
167
|
};
|
|
168
|
+
var STELORDER_CAPABILITIES = {
|
|
169
|
+
// Profile Management
|
|
170
|
+
updateProfile: false,
|
|
171
|
+
updateEmail: false,
|
|
172
|
+
changePasswordDirect: false,
|
|
173
|
+
changePasswordViaEmail: false,
|
|
174
|
+
deleteAccount: false,
|
|
175
|
+
// Avatar
|
|
176
|
+
uploadAvatar: false,
|
|
177
|
+
avatarViaMetadata: false,
|
|
178
|
+
// Custom Attributes
|
|
179
|
+
customAttributes: false,
|
|
180
|
+
// Orders
|
|
181
|
+
fetchOrders: true,
|
|
182
|
+
cancelOrder: false,
|
|
183
|
+
// Addresses
|
|
184
|
+
manageAddresses: true,
|
|
185
|
+
defaultAddress: false,
|
|
186
|
+
// Cart/Checkout
|
|
187
|
+
applyDiscounts: false,
|
|
188
|
+
shippingCalculation: false,
|
|
189
|
+
guestCheckout: false,
|
|
190
|
+
savedPaymentMethods: false,
|
|
191
|
+
listPaymentProviders: true,
|
|
192
|
+
regionSpecificPayments: false,
|
|
193
|
+
// Wishlist
|
|
194
|
+
wishlist: false,
|
|
195
|
+
// Search
|
|
196
|
+
advancedSearch: false,
|
|
197
|
+
facetedFilters: false,
|
|
198
|
+
// Reviews
|
|
199
|
+
productReviews: false,
|
|
200
|
+
// Loyalty
|
|
201
|
+
loyaltyProgram: false
|
|
202
|
+
};
|
|
139
203
|
var SHOPIFY_CAPABILITIES = {
|
|
140
204
|
// Profile Management
|
|
141
205
|
updateProfile: true,
|
|
@@ -8042,6 +8106,2036 @@ var MagentoProvider = class {
|
|
|
8042
8106
|
}
|
|
8043
8107
|
};
|
|
8044
8108
|
|
|
8109
|
+
// src/providers/stelorder/transforms.ts
|
|
8110
|
+
function normalizeStelCollection(payload) {
|
|
8111
|
+
if (!payload) {
|
|
8112
|
+
return [];
|
|
8113
|
+
}
|
|
8114
|
+
return Array.isArray(payload) ? payload : [payload];
|
|
8115
|
+
}
|
|
8116
|
+
function normalizeStelEntity(payload) {
|
|
8117
|
+
if (!payload) {
|
|
8118
|
+
return void 0;
|
|
8119
|
+
}
|
|
8120
|
+
return Array.isArray(payload) ? payload[0] : payload;
|
|
8121
|
+
}
|
|
8122
|
+
function transformStelMoney(amount, currencyCode = "USD") {
|
|
8123
|
+
const normalizedAmount = typeof amount === "string" ? Number.parseFloat(amount) : amount ?? 0;
|
|
8124
|
+
return {
|
|
8125
|
+
amount: Number.isFinite(normalizedAmount) ? normalizedAmount.toFixed(2) : "0.00",
|
|
8126
|
+
currencyCode: currencyCode.toUpperCase()
|
|
8127
|
+
};
|
|
8128
|
+
}
|
|
8129
|
+
function transformStelImage(url, altText = "") {
|
|
8130
|
+
const normalizedUrl = url?.trim();
|
|
8131
|
+
if (!normalizedUrl) {
|
|
8132
|
+
return void 0;
|
|
8133
|
+
}
|
|
8134
|
+
return {
|
|
8135
|
+
url: normalizedUrl,
|
|
8136
|
+
altText,
|
|
8137
|
+
width: 800,
|
|
8138
|
+
height: 800
|
|
8139
|
+
};
|
|
8140
|
+
}
|
|
8141
|
+
function normalizeStelDate(value) {
|
|
8142
|
+
if (!value) {
|
|
8143
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
8144
|
+
}
|
|
8145
|
+
const parsed = new Date(value);
|
|
8146
|
+
return Number.isNaN(parsed.getTime()) ? (/* @__PURE__ */ new Date()).toISOString() : parsed.toISOString();
|
|
8147
|
+
}
|
|
8148
|
+
function toStelStringId(value) {
|
|
8149
|
+
if (value === null || value === void 0) {
|
|
8150
|
+
return "";
|
|
8151
|
+
}
|
|
8152
|
+
return String(value);
|
|
8153
|
+
}
|
|
8154
|
+
function slugify(value) {
|
|
8155
|
+
return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
8156
|
+
}
|
|
8157
|
+
function buildStelHandle(...candidates) {
|
|
8158
|
+
for (const candidate of candidates) {
|
|
8159
|
+
if (candidate === null || candidate === void 0) {
|
|
8160
|
+
continue;
|
|
8161
|
+
}
|
|
8162
|
+
const normalized = slugify(String(candidate).trim());
|
|
8163
|
+
if (normalized) {
|
|
8164
|
+
return normalized;
|
|
8165
|
+
}
|
|
8166
|
+
}
|
|
8167
|
+
return "stel-item";
|
|
8168
|
+
}
|
|
8169
|
+
function transformStelProductImages(product) {
|
|
8170
|
+
const images = [];
|
|
8171
|
+
if (!product["item-images"]) {
|
|
8172
|
+
return images;
|
|
8173
|
+
}
|
|
8174
|
+
const sorted = [...product["item-images"]].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
8175
|
+
for (const img of sorted) {
|
|
8176
|
+
const transformed = transformStelImage(img["item-image-path"], product.name ?? "");
|
|
8177
|
+
if (transformed) {
|
|
8178
|
+
images.push(transformed);
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
return images;
|
|
8182
|
+
}
|
|
8183
|
+
function deriveStelStockStatus(product) {
|
|
8184
|
+
if (!product["stock-enabled"]) {
|
|
8185
|
+
return "in_stock";
|
|
8186
|
+
}
|
|
8187
|
+
const realStock = product["real-stock"] ?? 0;
|
|
8188
|
+
const minimumStock = product["minimum-stock"] ?? 0;
|
|
8189
|
+
if (realStock <= 0) {
|
|
8190
|
+
return "out_of_stock";
|
|
8191
|
+
}
|
|
8192
|
+
if (realStock <= minimumStock) {
|
|
8193
|
+
return "low_stock";
|
|
8194
|
+
}
|
|
8195
|
+
return "in_stock";
|
|
8196
|
+
}
|
|
8197
|
+
function buildSyntheticVariant(product, currencyCode) {
|
|
8198
|
+
const price = transformStelMoney(product["sales-price"], currencyCode);
|
|
8199
|
+
const stockStatus = deriveStelStockStatus(product);
|
|
8200
|
+
const quantityAvailable = product["stock-enabled"] ? product["real-stock"] ?? 0 : void 0;
|
|
8201
|
+
const image = product["item-images"]?.[0] ? transformStelImage(product["item-images"][0]["item-image-path"], product.name ?? "") : void 0;
|
|
8202
|
+
return {
|
|
8203
|
+
id: toStelStringId(product.id),
|
|
8204
|
+
title: "Default",
|
|
8205
|
+
sku: product.barcode ?? product["full-reference"] ?? void 0,
|
|
8206
|
+
availableForSale: stockStatus !== "out_of_stock",
|
|
8207
|
+
selectedOptions: [],
|
|
8208
|
+
price,
|
|
8209
|
+
compareAtPrice: void 0,
|
|
8210
|
+
quantityAvailable,
|
|
8211
|
+
stockStatus,
|
|
8212
|
+
image
|
|
8213
|
+
};
|
|
8214
|
+
}
|
|
8215
|
+
function transformStelProduct(raw, currencyCode) {
|
|
8216
|
+
const id = toStelStringId(raw.id);
|
|
8217
|
+
const handle = buildStelHandle(raw["full-reference"], raw.reference, raw.name, raw.id);
|
|
8218
|
+
const price = transformStelMoney(raw["sales-price"], currencyCode);
|
|
8219
|
+
const images = transformStelProductImages(raw);
|
|
8220
|
+
const variant = buildSyntheticVariant(raw, currencyCode);
|
|
8221
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8222
|
+
return {
|
|
8223
|
+
id,
|
|
8224
|
+
handle,
|
|
8225
|
+
title: raw.name ?? "",
|
|
8226
|
+
description: raw.description ?? "",
|
|
8227
|
+
availableForSale: variant.availableForSale,
|
|
8228
|
+
options: [],
|
|
8229
|
+
variants: [variant],
|
|
8230
|
+
featuredImage: images[0],
|
|
8231
|
+
images,
|
|
8232
|
+
priceRange: {
|
|
8233
|
+
minVariantPrice: price,
|
|
8234
|
+
maxVariantPrice: price
|
|
8235
|
+
},
|
|
8236
|
+
productType: void 0,
|
|
8237
|
+
vendor: void 0,
|
|
8238
|
+
tags: raw.promotional ? ["promotional"] : [],
|
|
8239
|
+
createdAt: normalizeStelDate(raw["creation-date"]),
|
|
8240
|
+
updatedAt: normalizeStelDate(raw["utc-last-modification-date"]) || now,
|
|
8241
|
+
metadata: {
|
|
8242
|
+
stelFullReference: raw["full-reference"],
|
|
8243
|
+
stelReference: raw.reference,
|
|
8244
|
+
stelBarcode: raw.barcode,
|
|
8245
|
+
stelCategoryId: raw["product-category-id"],
|
|
8246
|
+
stelInactive: raw.inactive,
|
|
8247
|
+
stelPromotional: raw.promotional,
|
|
8248
|
+
stelPurchasePrice: raw["purchase-price"]
|
|
8249
|
+
}
|
|
8250
|
+
};
|
|
8251
|
+
}
|
|
8252
|
+
function transformStelCategory(raw) {
|
|
8253
|
+
const id = toStelStringId(raw.id);
|
|
8254
|
+
const handle = buildStelHandle(raw.slug, raw.name, raw.id);
|
|
8255
|
+
return {
|
|
8256
|
+
id,
|
|
8257
|
+
name: raw.name ?? "",
|
|
8258
|
+
handle,
|
|
8259
|
+
description: raw.description ?? void 0,
|
|
8260
|
+
parentCategoryId: raw["parent-category-id"] ? toStelStringId(raw["parent-category-id"]) : void 0,
|
|
8261
|
+
metadata: {
|
|
8262
|
+
stelSlug: raw.slug
|
|
8263
|
+
}
|
|
8264
|
+
};
|
|
8265
|
+
}
|
|
8266
|
+
function transformStelCategoryToCollection(raw) {
|
|
8267
|
+
const id = toStelStringId(raw.id);
|
|
8268
|
+
const handle = buildStelHandle(raw.slug, raw.name, raw.id);
|
|
8269
|
+
return {
|
|
8270
|
+
id,
|
|
8271
|
+
handle,
|
|
8272
|
+
title: raw.name ?? "",
|
|
8273
|
+
description: raw.description ?? "",
|
|
8274
|
+
path: `/collections/${handle}`,
|
|
8275
|
+
updatedAt: normalizeStelDate(raw["utc-last-modification-date"])
|
|
8276
|
+
};
|
|
8277
|
+
}
|
|
8278
|
+
function transformStelWarehouseToStockLocation(raw) {
|
|
8279
|
+
return {
|
|
8280
|
+
id: toStelStringId(raw.id),
|
|
8281
|
+
name: raw.name ?? "Warehouse"
|
|
8282
|
+
};
|
|
8283
|
+
}
|
|
8284
|
+
function transformStelProductWarehouseToInventoryLevel(pw) {
|
|
8285
|
+
return {
|
|
8286
|
+
locationId: toStelStringId(pw["warehouse-id"]),
|
|
8287
|
+
locationName: pw["warehouse-path"] ?? `Warehouse ${pw["warehouse-id"] ?? "unknown"}`,
|
|
8288
|
+
availableQuantity: pw["real-stock"] ?? 0,
|
|
8289
|
+
reservedQuantity: Math.max(0, (pw["virtual-stock"] ?? 0) - (pw["real-stock"] ?? 0)),
|
|
8290
|
+
stockedQuantity: pw["virtual-stock"] ?? pw["real-stock"] ?? 0
|
|
8291
|
+
};
|
|
8292
|
+
}
|
|
8293
|
+
function splitStelName(fullName) {
|
|
8294
|
+
if (!fullName?.trim()) {
|
|
8295
|
+
return { firstName: "", lastName: "" };
|
|
8296
|
+
}
|
|
8297
|
+
const parts = fullName.trim().split(/\s+/);
|
|
8298
|
+
const firstName = parts[0] ?? "";
|
|
8299
|
+
const lastName = parts.length > 1 ? parts.slice(1).join(" ") : "";
|
|
8300
|
+
return { firstName, lastName };
|
|
8301
|
+
}
|
|
8302
|
+
function transformStelClient(raw) {
|
|
8303
|
+
const { firstName, lastName } = splitStelName(raw.name ?? raw["business-name"]);
|
|
8304
|
+
return {
|
|
8305
|
+
id: toStelStringId(raw.id),
|
|
8306
|
+
email: raw.email ?? "",
|
|
8307
|
+
firstName: firstName || null,
|
|
8308
|
+
lastName: lastName || null,
|
|
8309
|
+
phone: raw.phone ?? raw.mobile ?? null,
|
|
8310
|
+
hasAccount: true,
|
|
8311
|
+
createdAt: normalizeStelDate(raw["utc-last-modification-date"]),
|
|
8312
|
+
updatedAt: normalizeStelDate(raw["utc-last-modification-date"]),
|
|
8313
|
+
metadata: {
|
|
8314
|
+
stelBusinessName: raw["business-name"],
|
|
8315
|
+
stelRateId: raw["rate-id"],
|
|
8316
|
+
stelPaymentOptionId: raw["payment-option-id"],
|
|
8317
|
+
stelPaymentTermId: raw["payment-term-id"],
|
|
8318
|
+
stelDeliveryOptionId: raw["delivery-option-id"]
|
|
8319
|
+
}
|
|
8320
|
+
};
|
|
8321
|
+
}
|
|
8322
|
+
function deriveStelOrderStatus(raw) {
|
|
8323
|
+
if (raw.deleted) {
|
|
8324
|
+
return "cancelled";
|
|
8325
|
+
}
|
|
8326
|
+
const status = (raw.status ?? "").toLowerCase();
|
|
8327
|
+
if (status.includes("cancel") || status.includes("anulad")) {
|
|
8328
|
+
return "cancelled";
|
|
8329
|
+
}
|
|
8330
|
+
if (status.includes("complet") || status.includes("cerrad") || status.includes("settled")) {
|
|
8331
|
+
return "completed";
|
|
8332
|
+
}
|
|
8333
|
+
if (status.includes("process") || status.includes("confirm")) {
|
|
8334
|
+
return "processing";
|
|
8335
|
+
}
|
|
8336
|
+
return "pending";
|
|
8337
|
+
}
|
|
8338
|
+
function deriveStelPaymentStatus(raw) {
|
|
8339
|
+
const orderStatus = deriveStelOrderStatus(raw);
|
|
8340
|
+
if (orderStatus === "completed") {
|
|
8341
|
+
return "paid";
|
|
8342
|
+
}
|
|
8343
|
+
if (orderStatus === "cancelled") {
|
|
8344
|
+
return "pending";
|
|
8345
|
+
}
|
|
8346
|
+
return "pending";
|
|
8347
|
+
}
|
|
8348
|
+
function deriveStelFulfillmentStatus(raw) {
|
|
8349
|
+
const orderStatus = deriveStelOrderStatus(raw);
|
|
8350
|
+
if (orderStatus === "completed") {
|
|
8351
|
+
return "fulfilled";
|
|
8352
|
+
}
|
|
8353
|
+
return "unfulfilled";
|
|
8354
|
+
}
|
|
8355
|
+
function transformStelDocumentLine(line, index, currencyCode) {
|
|
8356
|
+
const unitPrice = line["item-base-price"] ?? 0;
|
|
8357
|
+
const quantity = line.units ?? 1;
|
|
8358
|
+
const lineTotal = unitPrice * quantity;
|
|
8359
|
+
return {
|
|
8360
|
+
id: toStelStringId(line["item-id"] ?? index),
|
|
8361
|
+
title: line["item-name"] ?? "",
|
|
8362
|
+
variantTitle: void 0,
|
|
8363
|
+
quantity,
|
|
8364
|
+
price: transformStelMoney(unitPrice, currencyCode),
|
|
8365
|
+
total: transformStelMoney(lineTotal, currencyCode),
|
|
8366
|
+
sku: void 0,
|
|
8367
|
+
productId: line["item-id"] ? toStelStringId(line["item-id"]) : void 0
|
|
8368
|
+
};
|
|
8369
|
+
}
|
|
8370
|
+
function transformStelSalesOrder(raw, currencyCode) {
|
|
8371
|
+
const id = toStelStringId(raw.id);
|
|
8372
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8373
|
+
const items = (raw["document-lines"] ?? []).filter((line) => line["line-type"] === "ITEM" || !line["line-type"]).map((line, i) => transformStelDocumentLine(line, i, currencyCode));
|
|
8374
|
+
const status = deriveStelOrderStatus(raw);
|
|
8375
|
+
return {
|
|
8376
|
+
id,
|
|
8377
|
+
orderNumber: raw.reference ?? id,
|
|
8378
|
+
email: raw.email ?? "",
|
|
8379
|
+
status,
|
|
8380
|
+
paymentStatus: deriveStelPaymentStatus(raw),
|
|
8381
|
+
fulfillmentStatus: deriveStelFulfillmentStatus(raw),
|
|
8382
|
+
customerId: raw["client-id"] ? toStelStringId(raw["client-id"]) : void 0,
|
|
8383
|
+
items,
|
|
8384
|
+
subtotal: transformStelMoney(raw["total-base"], currencyCode),
|
|
8385
|
+
total: transformStelMoney(raw.total, currencyCode),
|
|
8386
|
+
tax: raw["total-tax"] != null ? transformStelMoney(raw["total-tax"], currencyCode) : void 0,
|
|
8387
|
+
createdAt: normalizeStelDate(raw["creation-date"]),
|
|
8388
|
+
updatedAt: normalizeStelDate(raw["utc-last-modification-date"]) || now,
|
|
8389
|
+
cancelledAt: status === "cancelled" ? normalizeStelDate(raw["utc-last-modification-date"]) : void 0,
|
|
8390
|
+
completedAt: status === "completed" ? normalizeStelDate(raw["utc-last-modification-date"]) : void 0,
|
|
8391
|
+
metadata: {
|
|
8392
|
+
stelReference: raw.reference,
|
|
8393
|
+
stelStatus: raw.status,
|
|
8394
|
+
stelPaymentOptionId: raw["payment-option-id"],
|
|
8395
|
+
stelPaymentTermId: raw["payment-term-id"],
|
|
8396
|
+
stelDeliveryOptionId: raw["delivery-option-id"]
|
|
8397
|
+
}
|
|
8398
|
+
};
|
|
8399
|
+
}
|
|
8400
|
+
function inferPaymentMethodType(name) {
|
|
8401
|
+
if (!name) {
|
|
8402
|
+
return "other";
|
|
8403
|
+
}
|
|
8404
|
+
const lower = name.toLowerCase();
|
|
8405
|
+
if (lower.includes("transfer") || lower.includes("bank") || lower.includes("sepa") || lower.includes("iban")) {
|
|
8406
|
+
return "bank_transfer";
|
|
8407
|
+
}
|
|
8408
|
+
if (lower.includes("card") || lower.includes("tarjeta") || lower.includes("visa") || lower.includes("master")) {
|
|
8409
|
+
return "card";
|
|
8410
|
+
}
|
|
8411
|
+
if (lower.includes("paypal") || lower.includes("wallet") || lower.includes("apple") || lower.includes("google")) {
|
|
8412
|
+
return "wallet";
|
|
8413
|
+
}
|
|
8414
|
+
if (lower.includes("cash") || lower.includes("contrar") || lower.includes("efectivo") || lower.includes("cod")) {
|
|
8415
|
+
return "cash_on_delivery";
|
|
8416
|
+
}
|
|
8417
|
+
if (lower.includes("crypto") || lower.includes("bitcoin")) {
|
|
8418
|
+
return "crypto";
|
|
8419
|
+
}
|
|
8420
|
+
return "other";
|
|
8421
|
+
}
|
|
8422
|
+
function transformStelPaymentOption(raw) {
|
|
8423
|
+
return {
|
|
8424
|
+
id: toStelStringId(raw.id),
|
|
8425
|
+
name: raw.name ?? "Payment Option",
|
|
8426
|
+
type: inferPaymentMethodType(raw.name),
|
|
8427
|
+
isEnabled: !raw.deleted,
|
|
8428
|
+
requiresSetup: false,
|
|
8429
|
+
description: raw.description ?? void 0,
|
|
8430
|
+
metadata: {
|
|
8431
|
+
stelPath: raw.path,
|
|
8432
|
+
source: "paymentOption"
|
|
8433
|
+
}
|
|
8434
|
+
};
|
|
8435
|
+
}
|
|
8436
|
+
function transformStelDeliveryOption(raw, currencyCode) {
|
|
8437
|
+
return {
|
|
8438
|
+
id: toStelStringId(raw.id),
|
|
8439
|
+
name: raw.name ?? "Delivery Option",
|
|
8440
|
+
price: transformStelMoney(0, currencyCode),
|
|
8441
|
+
description: raw.description ?? void 0
|
|
8442
|
+
};
|
|
8443
|
+
}
|
|
8444
|
+
|
|
8445
|
+
// src/providers/stelorder/client.ts
|
|
8446
|
+
var DEFAULT_RETRY_CONFIG2 = {
|
|
8447
|
+
maxRetries: 2,
|
|
8448
|
+
initialDelayMs: 300,
|
|
8449
|
+
backoffMultiplier: 2,
|
|
8450
|
+
maxDelayMs: 5e3,
|
|
8451
|
+
timeoutMs: 1e4,
|
|
8452
|
+
retryableStatusCodes: [408, 429, 500, 502, 503, 504]
|
|
8453
|
+
};
|
|
8454
|
+
function sleep2(ms) {
|
|
8455
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8456
|
+
}
|
|
8457
|
+
function calculateDelay2(attempt, retryConfig) {
|
|
8458
|
+
const delay = retryConfig.initialDelayMs * Math.pow(retryConfig.backoffMultiplier, attempt);
|
|
8459
|
+
return Math.min(delay, retryConfig.maxDelayMs);
|
|
8460
|
+
}
|
|
8461
|
+
function isRetryableError2(error, retryConfig) {
|
|
8462
|
+
if (error instanceof ProviderAPIError) {
|
|
8463
|
+
return typeof error.status === "number" && retryConfig.retryableStatusCodes.includes(error.status);
|
|
8464
|
+
}
|
|
8465
|
+
if (!(error instanceof Error)) {
|
|
8466
|
+
return false;
|
|
8467
|
+
}
|
|
8468
|
+
const message = error.message.toLowerCase();
|
|
8469
|
+
return error.name === "AbortError" || error.name === "TimeoutError" || message.includes("fetch failed") || message.includes("timeout") || message.includes("econnrefused") || message.includes("etimedout");
|
|
8470
|
+
}
|
|
8471
|
+
function createRetryingFetch(fetchImplementation, retryConfig, logger2) {
|
|
8472
|
+
return async (url, init) => {
|
|
8473
|
+
let lastError = new Error("Unknown STEL Order request error");
|
|
8474
|
+
for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt += 1) {
|
|
8475
|
+
const controller = new AbortController();
|
|
8476
|
+
const timeoutId = setTimeout(() => controller.abort(), retryConfig.timeoutMs);
|
|
8477
|
+
try {
|
|
8478
|
+
const response = await fetchImplementation(url, {
|
|
8479
|
+
...init,
|
|
8480
|
+
signal: controller.signal
|
|
8481
|
+
});
|
|
8482
|
+
clearTimeout(timeoutId);
|
|
8483
|
+
if (!response.ok && retryConfig.retryableStatusCodes.includes(response.status)) {
|
|
8484
|
+
throw new ProviderAPIError(
|
|
8485
|
+
`STEL Order API error: ${response.status} ${response.statusText}`,
|
|
8486
|
+
"stelorder",
|
|
8487
|
+
response.status
|
|
8488
|
+
);
|
|
8489
|
+
}
|
|
8490
|
+
return response;
|
|
8491
|
+
} catch (error) {
|
|
8492
|
+
clearTimeout(timeoutId);
|
|
8493
|
+
lastError = error;
|
|
8494
|
+
if (attempt >= retryConfig.maxRetries || !isRetryableError2(error, retryConfig)) {
|
|
8495
|
+
throw error;
|
|
8496
|
+
}
|
|
8497
|
+
const delay = calculateDelay2(attempt, retryConfig);
|
|
8498
|
+
logger2.warn("STEL request failed, retrying.", {
|
|
8499
|
+
url,
|
|
8500
|
+
attempt: attempt + 1,
|
|
8501
|
+
maxAttempts: retryConfig.maxRetries + 1,
|
|
8502
|
+
nextRetryIn: delay,
|
|
8503
|
+
error: extractErrorMessage(error)
|
|
8504
|
+
});
|
|
8505
|
+
await sleep2(delay);
|
|
8506
|
+
}
|
|
8507
|
+
}
|
|
8508
|
+
throw lastError;
|
|
8509
|
+
};
|
|
8510
|
+
}
|
|
8511
|
+
async function parseErrorResponse(response) {
|
|
8512
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
8513
|
+
try {
|
|
8514
|
+
if (contentType.includes("application/json")) {
|
|
8515
|
+
const body = await response.json();
|
|
8516
|
+
const message = extractErrorMessage(body);
|
|
8517
|
+
if (message && message !== "An unknown error occurred") {
|
|
8518
|
+
return message;
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
} catch {
|
|
8522
|
+
}
|
|
8523
|
+
try {
|
|
8524
|
+
const text = await response.text();
|
|
8525
|
+
if (text.trim()) {
|
|
8526
|
+
return text.trim();
|
|
8527
|
+
}
|
|
8528
|
+
} catch {
|
|
8529
|
+
}
|
|
8530
|
+
return `STEL Order API error: ${response.status} ${response.statusText}`;
|
|
8531
|
+
}
|
|
8532
|
+
function normalizeStelApiBaseUrl(baseUrl) {
|
|
8533
|
+
const trimmed = baseUrl.trim();
|
|
8534
|
+
if (!trimmed) {
|
|
8535
|
+
throw new ConfigurationError("Stel Order baseUrl is required.");
|
|
8536
|
+
}
|
|
8537
|
+
const normalized = trimmed.replace(/\/api\/openapi\.json$/i, "").replace(/\/+$/, "");
|
|
8538
|
+
return normalized.endsWith("/app") ? normalized : `${normalized}/app`;
|
|
8539
|
+
}
|
|
8540
|
+
var StelOrderClient = class {
|
|
8541
|
+
apiBaseUrl;
|
|
8542
|
+
apiKey;
|
|
8543
|
+
logger;
|
|
8544
|
+
retryConfig;
|
|
8545
|
+
fetchImplementation;
|
|
8546
|
+
constructor(config) {
|
|
8547
|
+
const apiKey = config.apiKey ?? config.publishableKey;
|
|
8548
|
+
if (!apiKey) {
|
|
8549
|
+
throw new ConfigurationError(
|
|
8550
|
+
"Stel Order API key is required. Pass `apiKey` or `publishableKey` to createProvider()."
|
|
8551
|
+
);
|
|
8552
|
+
}
|
|
8553
|
+
this.apiBaseUrl = normalizeStelApiBaseUrl(config.baseUrl);
|
|
8554
|
+
this.apiKey = apiKey;
|
|
8555
|
+
this.logger = createLogger("StelOrderClient", config.debug);
|
|
8556
|
+
this.retryConfig = {
|
|
8557
|
+
...DEFAULT_RETRY_CONFIG2,
|
|
8558
|
+
...config.retry
|
|
8559
|
+
};
|
|
8560
|
+
this.fetchImplementation = config.customFetch ? createRetryingFetch(config.customFetch, this.retryConfig, this.logger) : void 0;
|
|
8561
|
+
this.logger.info("Initializing Stel Order client", {
|
|
8562
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
8563
|
+
retryConfig: this.retryConfig
|
|
8564
|
+
});
|
|
8565
|
+
}
|
|
8566
|
+
async list(resource, query) {
|
|
8567
|
+
const payload = await this.request({
|
|
8568
|
+
method: "GET",
|
|
8569
|
+
path: resource,
|
|
8570
|
+
query
|
|
8571
|
+
});
|
|
8572
|
+
return normalizeStelCollection(payload);
|
|
8573
|
+
}
|
|
8574
|
+
async getOne(resource, id, query) {
|
|
8575
|
+
const payload = await this.request({
|
|
8576
|
+
method: "GET",
|
|
8577
|
+
path: `${resource}/${id}`,
|
|
8578
|
+
query
|
|
8579
|
+
});
|
|
8580
|
+
return normalizeStelEntity(payload);
|
|
8581
|
+
}
|
|
8582
|
+
async create(resource, body) {
|
|
8583
|
+
return this.request({
|
|
8584
|
+
method: "POST",
|
|
8585
|
+
path: resource,
|
|
8586
|
+
body
|
|
8587
|
+
});
|
|
8588
|
+
}
|
|
8589
|
+
async update(resource, id, body) {
|
|
8590
|
+
return this.request({
|
|
8591
|
+
method: "PUT",
|
|
8592
|
+
path: `${resource}/${id}`,
|
|
8593
|
+
body
|
|
8594
|
+
});
|
|
8595
|
+
}
|
|
8596
|
+
async remove(resource, id) {
|
|
8597
|
+
await this.request({
|
|
8598
|
+
method: "DELETE",
|
|
8599
|
+
path: `${resource}/${id}`
|
|
8600
|
+
});
|
|
8601
|
+
}
|
|
8602
|
+
buildUrl(path, query) {
|
|
8603
|
+
const normalizedPath = path.replace(/^\/+/, "");
|
|
8604
|
+
const url = new URL(`${this.apiBaseUrl}/${normalizedPath}`);
|
|
8605
|
+
if (!query) {
|
|
8606
|
+
return url.toString();
|
|
8607
|
+
}
|
|
8608
|
+
for (const [key, value] of Object.entries(query)) {
|
|
8609
|
+
if (value === void 0 || value === null || value === "") {
|
|
8610
|
+
continue;
|
|
8611
|
+
}
|
|
8612
|
+
if (Array.isArray(value)) {
|
|
8613
|
+
url.searchParams.set(key, value.map(String).join(","));
|
|
8614
|
+
continue;
|
|
8615
|
+
}
|
|
8616
|
+
url.searchParams.set(key, String(value));
|
|
8617
|
+
}
|
|
8618
|
+
return url.toString();
|
|
8619
|
+
}
|
|
8620
|
+
buildHeaders(headers, hasBody = false) {
|
|
8621
|
+
const normalizedHeaders = new Headers(headers);
|
|
8622
|
+
normalizedHeaders.set("Accept", "application/json");
|
|
8623
|
+
normalizedHeaders.set("APIKEY", this.apiKey);
|
|
8624
|
+
if (hasBody && !normalizedHeaders.has("Content-Type")) {
|
|
8625
|
+
normalizedHeaders.set("Content-Type", "application/json");
|
|
8626
|
+
}
|
|
8627
|
+
return normalizedHeaders;
|
|
8628
|
+
}
|
|
8629
|
+
async executeFetch(url, init) {
|
|
8630
|
+
if (this.fetchImplementation) {
|
|
8631
|
+
return this.fetchImplementation(url, init);
|
|
8632
|
+
}
|
|
8633
|
+
return fetchWithRetry(url, init, this.retryConfig);
|
|
8634
|
+
}
|
|
8635
|
+
async request(options) {
|
|
8636
|
+
const url = this.buildUrl(options.path, options.query);
|
|
8637
|
+
const hasBody = options.body !== void 0;
|
|
8638
|
+
this.logger.debug("STEL request", {
|
|
8639
|
+
method: options.method,
|
|
8640
|
+
url
|
|
8641
|
+
});
|
|
8642
|
+
const response = await this.executeFetch(url, {
|
|
8643
|
+
method: options.method,
|
|
8644
|
+
headers: this.buildHeaders(options.headers, hasBody),
|
|
8645
|
+
body: hasBody ? JSON.stringify(options.body) : void 0
|
|
8646
|
+
});
|
|
8647
|
+
if (!response.ok) {
|
|
8648
|
+
const message = await parseErrorResponse(response);
|
|
8649
|
+
throw new ProviderAPIError(message, "stelorder", response.status);
|
|
8650
|
+
}
|
|
8651
|
+
if (response.status === 204) {
|
|
8652
|
+
return void 0;
|
|
8653
|
+
}
|
|
8654
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
8655
|
+
if (contentType.includes("application/json")) {
|
|
8656
|
+
return await response.json();
|
|
8657
|
+
}
|
|
8658
|
+
return await response.text();
|
|
8659
|
+
}
|
|
8660
|
+
};
|
|
8661
|
+
|
|
8662
|
+
// src/providers/stelorder/index.ts
|
|
8663
|
+
var StelOrderProvider = class {
|
|
8664
|
+
name = "stelorder";
|
|
8665
|
+
version = "1.0.0";
|
|
8666
|
+
capabilities = STELORDER_CAPABILITIES;
|
|
8667
|
+
client;
|
|
8668
|
+
logger;
|
|
8669
|
+
currencyCode;
|
|
8670
|
+
storefrontId;
|
|
8671
|
+
companyName;
|
|
8672
|
+
constructor(config) {
|
|
8673
|
+
this.client = new StelOrderClient(config);
|
|
8674
|
+
this.logger = createLogger("StelOrderProvider", config.debug);
|
|
8675
|
+
this.currencyCode = config.currencyCode ?? "USD";
|
|
8676
|
+
this.storefrontId = config.storefrontId ?? "stelorder-primary";
|
|
8677
|
+
this.companyName = config.companyName ?? "Stel Order";
|
|
8678
|
+
this.logger.info("Initializing Stel Order provider", {
|
|
8679
|
+
storefrontId: this.storefrontId,
|
|
8680
|
+
companyName: this.companyName,
|
|
8681
|
+
currencyCode: this.currencyCode
|
|
8682
|
+
});
|
|
8683
|
+
}
|
|
8684
|
+
// ============================================
|
|
8685
|
+
// Product Operations
|
|
8686
|
+
// ============================================
|
|
8687
|
+
async getProduct(handle, _options) {
|
|
8688
|
+
this.logger.debug("getProduct", { handle });
|
|
8689
|
+
try {
|
|
8690
|
+
if (/^\d+$/.test(handle)) {
|
|
8691
|
+
const raw = await this.client.getOne("products", handle);
|
|
8692
|
+
return raw ? transformStelProduct(raw, this.currencyCode) : void 0;
|
|
8693
|
+
}
|
|
8694
|
+
const rawProducts = await this.client.list("products", { limit: 100 });
|
|
8695
|
+
for (const raw of rawProducts) {
|
|
8696
|
+
const productHandle = buildStelHandle(raw["full-reference"], raw.reference, raw.name, raw.id);
|
|
8697
|
+
if (productHandle === handle) {
|
|
8698
|
+
return transformStelProduct(raw, this.currencyCode);
|
|
8699
|
+
}
|
|
8700
|
+
}
|
|
8701
|
+
return void 0;
|
|
8702
|
+
} catch (error) {
|
|
8703
|
+
this.logger.error("getProduct failed", { handle, error });
|
|
8704
|
+
throw this.wrapError("getProduct", error);
|
|
8705
|
+
}
|
|
8706
|
+
}
|
|
8707
|
+
async getProducts(options) {
|
|
8708
|
+
this.logger.debug("getProducts", { options });
|
|
8709
|
+
try {
|
|
8710
|
+
const query = {};
|
|
8711
|
+
if (options?.first) {
|
|
8712
|
+
query.limit = options.first;
|
|
8713
|
+
}
|
|
8714
|
+
if (options?.skip) {
|
|
8715
|
+
query.start = options.skip;
|
|
8716
|
+
}
|
|
8717
|
+
if (typeof options?.after === "number") {
|
|
8718
|
+
query.start = options.after;
|
|
8719
|
+
}
|
|
8720
|
+
if (options?.sortKey) {
|
|
8721
|
+
query.sort = options.reverse ? `-${options.sortKey}` : options.sortKey;
|
|
8722
|
+
}
|
|
8723
|
+
if (options?.categoryIds?.length) {
|
|
8724
|
+
query["product-category-id"] = `in:${options.categoryIds.join(",")}`;
|
|
8725
|
+
}
|
|
8726
|
+
const rawProducts = await this.client.list("products", query);
|
|
8727
|
+
let products = rawProducts.filter((p) => !p.deleted && !p.inactive).map((p) => transformStelProduct(p, this.currencyCode));
|
|
8728
|
+
if (options?.query) {
|
|
8729
|
+
const needle = options.query.toLowerCase();
|
|
8730
|
+
products = products.filter(
|
|
8731
|
+
(p) => p.title.toLowerCase().includes(needle) || p.description.toLowerCase().includes(needle) || p.handle.includes(needle)
|
|
8732
|
+
);
|
|
8733
|
+
}
|
|
8734
|
+
return products;
|
|
8735
|
+
} catch (error) {
|
|
8736
|
+
this.logger.error("getProducts failed", { options, error });
|
|
8737
|
+
throw this.wrapError("getProducts", error);
|
|
8738
|
+
}
|
|
8739
|
+
}
|
|
8740
|
+
async getProductRecommendations(_productId) {
|
|
8741
|
+
return [];
|
|
8742
|
+
}
|
|
8743
|
+
// ============================================
|
|
8744
|
+
// Category Operations
|
|
8745
|
+
// ============================================
|
|
8746
|
+
async getCategory(idOrHandle) {
|
|
8747
|
+
this.logger.debug("getCategory", { idOrHandle });
|
|
8748
|
+
try {
|
|
8749
|
+
if (/^\d+$/.test(idOrHandle)) {
|
|
8750
|
+
const raw = await this.client.getOne("productCategories", idOrHandle);
|
|
8751
|
+
return raw ? transformStelCategory(raw) : void 0;
|
|
8752
|
+
}
|
|
8753
|
+
const rawCategories = await this.client.list("productCategories");
|
|
8754
|
+
for (const raw of rawCategories) {
|
|
8755
|
+
const catHandle = buildStelHandle(raw.slug, raw.name, raw.id);
|
|
8756
|
+
if (catHandle === idOrHandle) {
|
|
8757
|
+
return transformStelCategory(raw);
|
|
8758
|
+
}
|
|
8759
|
+
}
|
|
8760
|
+
return void 0;
|
|
8761
|
+
} catch (error) {
|
|
8762
|
+
this.logger.error("getCategory failed", { idOrHandle, error });
|
|
8763
|
+
throw this.wrapError("getCategory", error);
|
|
8764
|
+
}
|
|
8765
|
+
}
|
|
8766
|
+
async getCategories(options) {
|
|
8767
|
+
this.logger.debug("getCategories", { options });
|
|
8768
|
+
try {
|
|
8769
|
+
if (options?.customFetcher) {
|
|
8770
|
+
return options.customFetcher(options);
|
|
8771
|
+
}
|
|
8772
|
+
const query = {};
|
|
8773
|
+
if (options?.limit) {
|
|
8774
|
+
query.limit = options.limit;
|
|
8775
|
+
}
|
|
8776
|
+
if (options?.parentCategoryId) {
|
|
8777
|
+
query["parent-category-id"] = options.parentCategoryId;
|
|
8778
|
+
}
|
|
8779
|
+
const rawCategories = await this.client.list("productCategories", query);
|
|
8780
|
+
let categories = rawCategories.filter((c) => !c.deleted).map(transformStelCategory);
|
|
8781
|
+
if (options?.query) {
|
|
8782
|
+
const needle = options.query.toLowerCase();
|
|
8783
|
+
categories = categories.filter(
|
|
8784
|
+
(c) => c.name.toLowerCase().includes(needle) || c.handle.includes(needle)
|
|
8785
|
+
);
|
|
8786
|
+
}
|
|
8787
|
+
return categories;
|
|
8788
|
+
} catch (error) {
|
|
8789
|
+
this.logger.error("getCategories failed", { options, error });
|
|
8790
|
+
throw this.wrapError("getCategories", error);
|
|
8791
|
+
}
|
|
8792
|
+
}
|
|
8793
|
+
async getCategoryProducts(handle, options) {
|
|
8794
|
+
this.logger.debug("getCategoryProducts", { handle, options });
|
|
8795
|
+
try {
|
|
8796
|
+
const category = await this.getCategory(handle);
|
|
8797
|
+
if (!category) {
|
|
8798
|
+
return [];
|
|
8799
|
+
}
|
|
8800
|
+
return this.getProducts({
|
|
8801
|
+
categoryIds: [category.id],
|
|
8802
|
+
first: options?.first,
|
|
8803
|
+
sortKey: options?.sortKey,
|
|
8804
|
+
reverse: options?.reverse,
|
|
8805
|
+
after: options?.after
|
|
8806
|
+
});
|
|
8807
|
+
} catch (error) {
|
|
8808
|
+
this.logger.error("getCategoryProducts failed", { handle, error });
|
|
8809
|
+
throw this.wrapError("getCategoryProducts", error);
|
|
8810
|
+
}
|
|
8811
|
+
}
|
|
8812
|
+
// ============================================
|
|
8813
|
+
// Collection Operations (alias categories)
|
|
8814
|
+
// ============================================
|
|
8815
|
+
async getCollection(handle) {
|
|
8816
|
+
this.logger.debug("getCollection", { handle });
|
|
8817
|
+
try {
|
|
8818
|
+
if (/^\d+$/.test(handle)) {
|
|
8819
|
+
const raw = await this.client.getOne("productCategories", handle);
|
|
8820
|
+
return raw ? transformStelCategoryToCollection(raw) : void 0;
|
|
8821
|
+
}
|
|
8822
|
+
const rawCategories = await this.client.list("productCategories");
|
|
8823
|
+
for (const raw of rawCategories) {
|
|
8824
|
+
const catHandle = buildStelHandle(raw.slug, raw.name, raw.id);
|
|
8825
|
+
if (catHandle === handle) {
|
|
8826
|
+
return transformStelCategoryToCollection(raw);
|
|
8827
|
+
}
|
|
8828
|
+
}
|
|
8829
|
+
return void 0;
|
|
8830
|
+
} catch (error) {
|
|
8831
|
+
this.logger.error("getCollection failed", { handle, error });
|
|
8832
|
+
throw this.wrapError("getCollection", error);
|
|
8833
|
+
}
|
|
8834
|
+
}
|
|
8835
|
+
async getCollections(options) {
|
|
8836
|
+
this.logger.debug("getCollections", { options });
|
|
8837
|
+
try {
|
|
8838
|
+
const query = {};
|
|
8839
|
+
if (options?.limit) {
|
|
8840
|
+
query.limit = options.limit;
|
|
8841
|
+
}
|
|
8842
|
+
const rawCategories = await this.client.list("productCategories", query);
|
|
8843
|
+
let collections = rawCategories.filter((c) => !c.deleted).map(transformStelCategoryToCollection);
|
|
8844
|
+
if (options?.query) {
|
|
8845
|
+
const needle = options.query.toLowerCase();
|
|
8846
|
+
collections = collections.filter(
|
|
8847
|
+
(c) => c.title.toLowerCase().includes(needle) || c.handle.includes(needle)
|
|
8848
|
+
);
|
|
8849
|
+
}
|
|
8850
|
+
return collections;
|
|
8851
|
+
} catch (error) {
|
|
8852
|
+
this.logger.error("getCollections failed", { options, error });
|
|
8853
|
+
throw this.wrapError("getCollections", error);
|
|
8854
|
+
}
|
|
8855
|
+
}
|
|
8856
|
+
async getCollectionProducts(handle, options) {
|
|
8857
|
+
return this.getCategoryProducts(handle, options);
|
|
8858
|
+
}
|
|
8859
|
+
// ============================================
|
|
8860
|
+
// Inventory Operations
|
|
8861
|
+
// ============================================
|
|
8862
|
+
async getStockLocations(_params) {
|
|
8863
|
+
this.logger.debug("getStockLocations");
|
|
8864
|
+
try {
|
|
8865
|
+
const rawWarehouses = await this.client.list("warehouses");
|
|
8866
|
+
return rawWarehouses.filter((w) => !w.deleted).map(transformStelWarehouseToStockLocation);
|
|
8867
|
+
} catch (error) {
|
|
8868
|
+
this.logger.error("getStockLocations failed", { error });
|
|
8869
|
+
throw this.wrapError("getStockLocations", error);
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
async checkInventoryLevels(variantId, _salesChannelId) {
|
|
8873
|
+
this.logger.debug("checkInventoryLevels", { variantId });
|
|
8874
|
+
try {
|
|
8875
|
+
const raw = await this.client.getOne("products", variantId);
|
|
8876
|
+
if (!raw?.["product-warehouses"]?.length) {
|
|
8877
|
+
return [];
|
|
8878
|
+
}
|
|
8879
|
+
return raw["product-warehouses"].map(transformStelProductWarehouseToInventoryLevel);
|
|
8880
|
+
} catch (error) {
|
|
8881
|
+
this.logger.error("checkInventoryLevels failed", { variantId, error });
|
|
8882
|
+
throw this.wrapError("checkInventoryLevels", error);
|
|
8883
|
+
}
|
|
8884
|
+
}
|
|
8885
|
+
validateCartStock(_cartId) {
|
|
8886
|
+
return this.notSupported("validateCartStock");
|
|
8887
|
+
}
|
|
8888
|
+
getFulfillmentOptions(_cartId, _salesChannelId) {
|
|
8889
|
+
return this.notSupported("getFulfillmentOptions");
|
|
8890
|
+
}
|
|
8891
|
+
// ============================================
|
|
8892
|
+
// Cart Operations (unsupported — STEL is ERP, not storefront)
|
|
8893
|
+
// ============================================
|
|
8894
|
+
createCart(_options) {
|
|
8895
|
+
return this.notSupported("createCart");
|
|
8896
|
+
}
|
|
8897
|
+
getCart(_cartId) {
|
|
8898
|
+
return this.notSupported("getCart");
|
|
8899
|
+
}
|
|
8900
|
+
addToCart(_cartId, _lines) {
|
|
8901
|
+
return this.notSupported("addToCart");
|
|
8902
|
+
}
|
|
8903
|
+
removeFromCart(_cartId, _lineIds) {
|
|
8904
|
+
return this.notSupported("removeFromCart");
|
|
8905
|
+
}
|
|
8906
|
+
updateCart(_cartId, _lines) {
|
|
8907
|
+
return this.notSupported("updateCart");
|
|
8908
|
+
}
|
|
8909
|
+
// ============================================
|
|
8910
|
+
// Checkout Operations (unsupported)
|
|
8911
|
+
// ============================================
|
|
8912
|
+
completeCheckout(_cartId) {
|
|
8913
|
+
return this.notSupported("completeCheckout");
|
|
8914
|
+
}
|
|
8915
|
+
getRegionCountries(_regionId) {
|
|
8916
|
+
return this.notSupported("getRegionCountries");
|
|
8917
|
+
}
|
|
8918
|
+
addShippingMethod(_cartId, _methodId) {
|
|
8919
|
+
return this.notSupported("addShippingMethod");
|
|
8920
|
+
}
|
|
8921
|
+
initiatePaymentSession(_cartId, _providerId) {
|
|
8922
|
+
return this.notSupported("initiatePaymentSession");
|
|
8923
|
+
}
|
|
8924
|
+
applyDiscountCode(_cartId, _code) {
|
|
8925
|
+
return this.notSupported("applyDiscountCode");
|
|
8926
|
+
}
|
|
8927
|
+
removeDiscountCode(_cartId, _code) {
|
|
8928
|
+
return this.notSupported("removeDiscountCode");
|
|
8929
|
+
}
|
|
8930
|
+
// ============================================
|
|
8931
|
+
// Payment Methods
|
|
8932
|
+
// ============================================
|
|
8933
|
+
async getPaymentMethods(_options) {
|
|
8934
|
+
this.logger.debug("getPaymentMethods");
|
|
8935
|
+
try {
|
|
8936
|
+
const rawOptions = await this.client.list("paymentOptions");
|
|
8937
|
+
return rawOptions.filter((o) => !o.deleted).map(transformStelPaymentOption);
|
|
8938
|
+
} catch (error) {
|
|
8939
|
+
this.logger.error("getPaymentMethods failed", { error });
|
|
8940
|
+
throw this.wrapError("getPaymentMethods", error);
|
|
8941
|
+
}
|
|
8942
|
+
}
|
|
8943
|
+
// ============================================
|
|
8944
|
+
// Shipping / Delivery Methods
|
|
8945
|
+
// ============================================
|
|
8946
|
+
async getShippingMethods(_cartId) {
|
|
8947
|
+
this.logger.debug("getShippingMethods (delivery options listing)");
|
|
8948
|
+
try {
|
|
8949
|
+
const rawOptions = await this.client.list("deliveryOptions");
|
|
8950
|
+
return rawOptions.filter((o) => !o.deleted).map((o) => transformStelDeliveryOption(o, this.currencyCode));
|
|
8951
|
+
} catch (error) {
|
|
8952
|
+
this.logger.error("getShippingMethods failed", { error });
|
|
8953
|
+
throw this.wrapError("getShippingMethods", error);
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
// ============================================
|
|
8957
|
+
// Customer Operations (optional)
|
|
8958
|
+
// ============================================
|
|
8959
|
+
async getCustomer(customerId) {
|
|
8960
|
+
this.logger.debug("getCustomer", { customerId });
|
|
8961
|
+
try {
|
|
8962
|
+
const raw = await this.client.getOne("clients", customerId);
|
|
8963
|
+
return raw ? transformStelClient(raw) : void 0;
|
|
8964
|
+
} catch (error) {
|
|
8965
|
+
this.logger.error("getCustomer failed", { customerId, error });
|
|
8966
|
+
throw this.wrapError("getCustomer", error);
|
|
8967
|
+
}
|
|
8968
|
+
}
|
|
8969
|
+
async getCustomers(options) {
|
|
8970
|
+
this.logger.debug("getCustomers", { options });
|
|
8971
|
+
try {
|
|
8972
|
+
if (options?.customFetcher) {
|
|
8973
|
+
return options.customFetcher(options);
|
|
8974
|
+
}
|
|
8975
|
+
const query = {};
|
|
8976
|
+
if (options?.limit) {
|
|
8977
|
+
query.limit = options.limit;
|
|
8978
|
+
}
|
|
8979
|
+
if (options?.offset) {
|
|
8980
|
+
query.start = options.offset;
|
|
8981
|
+
}
|
|
8982
|
+
const rawClients = await this.client.list("clients", query);
|
|
8983
|
+
let customers = rawClients.filter((c) => !c.deleted).map(transformStelClient);
|
|
8984
|
+
if (options?.search) {
|
|
8985
|
+
const needle = options.search.toLowerCase();
|
|
8986
|
+
customers = customers.filter(
|
|
8987
|
+
(c) => c.email.toLowerCase().includes(needle) || (c.firstName ?? "").toLowerCase().includes(needle) || (c.lastName ?? "").toLowerCase().includes(needle)
|
|
8988
|
+
);
|
|
8989
|
+
}
|
|
8990
|
+
return customers;
|
|
8991
|
+
} catch (error) {
|
|
8992
|
+
this.logger.error("getCustomers failed", { options, error });
|
|
8993
|
+
throw this.wrapError("getCustomers", error);
|
|
8994
|
+
}
|
|
8995
|
+
}
|
|
8996
|
+
async updateCustomer(customerId, data) {
|
|
8997
|
+
this.logger.debug("updateCustomer", { customerId, data });
|
|
8998
|
+
try {
|
|
8999
|
+
const stelPayload = {};
|
|
9000
|
+
if (data.firstName || data.lastName) {
|
|
9001
|
+
stelPayload.name = [data.firstName, data.lastName].filter(Boolean).join(" ");
|
|
9002
|
+
}
|
|
9003
|
+
if (data.email) {
|
|
9004
|
+
stelPayload.email = data.email;
|
|
9005
|
+
}
|
|
9006
|
+
if (data.phone) {
|
|
9007
|
+
stelPayload.phone = data.phone;
|
|
9008
|
+
}
|
|
9009
|
+
const raw = await this.client.update("clients", customerId, stelPayload);
|
|
9010
|
+
return transformStelClient(raw);
|
|
9011
|
+
} catch (error) {
|
|
9012
|
+
this.logger.error("updateCustomer failed", { customerId, error });
|
|
9013
|
+
throw this.wrapError("updateCustomer", error);
|
|
9014
|
+
}
|
|
9015
|
+
}
|
|
9016
|
+
// ============================================
|
|
9017
|
+
// Order Operations (optional)
|
|
9018
|
+
// ============================================
|
|
9019
|
+
async getOrder(orderId) {
|
|
9020
|
+
this.logger.debug("getOrder", { orderId });
|
|
9021
|
+
try {
|
|
9022
|
+
const raw = await this.client.getOne("salesOrders", orderId);
|
|
9023
|
+
return raw ? transformStelSalesOrder(raw, this.currencyCode) : void 0;
|
|
9024
|
+
} catch (error) {
|
|
9025
|
+
this.logger.error("getOrder failed", { orderId, error });
|
|
9026
|
+
throw this.wrapError("getOrder", error);
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
async getOrders(options) {
|
|
9030
|
+
this.logger.debug("getOrders", { options });
|
|
9031
|
+
try {
|
|
9032
|
+
if (options?.customFetcher) {
|
|
9033
|
+
return options.customFetcher(options);
|
|
9034
|
+
}
|
|
9035
|
+
const query = {};
|
|
9036
|
+
if (options?.limit) {
|
|
9037
|
+
query.limit = options.limit;
|
|
9038
|
+
}
|
|
9039
|
+
if (options?.offset) {
|
|
9040
|
+
query.start = options.offset;
|
|
9041
|
+
}
|
|
9042
|
+
if (options?.customerId) {
|
|
9043
|
+
query["client-id"] = options.customerId;
|
|
9044
|
+
}
|
|
9045
|
+
const rawOrders = await this.client.list("salesOrders", query);
|
|
9046
|
+
return rawOrders.filter((o) => !o.deleted).map((o) => transformStelSalesOrder(o, this.currencyCode));
|
|
9047
|
+
} catch (error) {
|
|
9048
|
+
this.logger.error("getOrders failed", { options, error });
|
|
9049
|
+
throw this.wrapError("getOrders", error);
|
|
9050
|
+
}
|
|
9051
|
+
}
|
|
9052
|
+
async getAdminOrders(options) {
|
|
9053
|
+
this.logger.debug("getAdminOrders", { options });
|
|
9054
|
+
try {
|
|
9055
|
+
const query = {};
|
|
9056
|
+
if (options?.limit) {
|
|
9057
|
+
query.limit = options.limit;
|
|
9058
|
+
}
|
|
9059
|
+
if (options?.offset) {
|
|
9060
|
+
query.start = options.offset;
|
|
9061
|
+
}
|
|
9062
|
+
const rawOrders = await this.client.list("salesOrders", query);
|
|
9063
|
+
let orders = rawOrders.filter((o) => !o.deleted).map((o) => transformStelSalesOrder(o, this.currencyCode));
|
|
9064
|
+
if (options?.search) {
|
|
9065
|
+
const needle = options.search.toLowerCase();
|
|
9066
|
+
orders = orders.filter(
|
|
9067
|
+
(o) => o.orderNumber.toLowerCase().includes(needle) || o.email.toLowerCase().includes(needle)
|
|
9068
|
+
);
|
|
9069
|
+
}
|
|
9070
|
+
if (options?.status) {
|
|
9071
|
+
const statuses = Array.isArray(options.status) ? options.status : [options.status];
|
|
9072
|
+
orders = orders.filter((o) => statuses.includes(o.status));
|
|
9073
|
+
}
|
|
9074
|
+
return { orders, count: orders.length };
|
|
9075
|
+
} catch (error) {
|
|
9076
|
+
this.logger.error("getAdminOrders failed", { options, error });
|
|
9077
|
+
throw this.wrapError("getAdminOrders", error);
|
|
9078
|
+
}
|
|
9079
|
+
}
|
|
9080
|
+
cancelOrder(_orderId) {
|
|
9081
|
+
return this.notSupported("cancelOrder");
|
|
9082
|
+
}
|
|
9083
|
+
createFulfillment(_orderId, _items) {
|
|
9084
|
+
return this.notSupported("createFulfillment");
|
|
9085
|
+
}
|
|
9086
|
+
createRefund(_orderId, _amount, _reason) {
|
|
9087
|
+
return this.notSupported("createRefund");
|
|
9088
|
+
}
|
|
9089
|
+
// ============================================
|
|
9090
|
+
// Storefront Context
|
|
9091
|
+
// ============================================
|
|
9092
|
+
async getStorefrontContext() {
|
|
9093
|
+
return {
|
|
9094
|
+
id: this.storefrontId,
|
|
9095
|
+
name: this.companyName,
|
|
9096
|
+
platformType: "stelorder",
|
|
9097
|
+
requiresProductScoping: false,
|
|
9098
|
+
currencyCode: this.currencyCode,
|
|
9099
|
+
metadata: {
|
|
9100
|
+
apiBaseUrl: this.client.apiBaseUrl,
|
|
9101
|
+
singleCompany: true,
|
|
9102
|
+
providerVersion: this.version
|
|
9103
|
+
}
|
|
9104
|
+
};
|
|
9105
|
+
}
|
|
9106
|
+
isStorefrontRequired() {
|
|
9107
|
+
return false;
|
|
9108
|
+
}
|
|
9109
|
+
// ============================================
|
|
9110
|
+
// Internal helpers
|
|
9111
|
+
// ============================================
|
|
9112
|
+
notSupported(operation) {
|
|
9113
|
+
return Promise.reject(
|
|
9114
|
+
new ProviderAPIError(
|
|
9115
|
+
`Stel Order does not support \`${operation}\`. STEL is an ERP adapter without cart/checkout/auth capabilities.`,
|
|
9116
|
+
"stelorder",
|
|
9117
|
+
501
|
|
9118
|
+
)
|
|
9119
|
+
);
|
|
9120
|
+
}
|
|
9121
|
+
wrapError(operation, error) {
|
|
9122
|
+
if (error instanceof ProviderAPIError) {
|
|
9123
|
+
return error;
|
|
9124
|
+
}
|
|
9125
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9126
|
+
return new ProviderAPIError(
|
|
9127
|
+
`Stel Order \`${operation}\` failed: ${message}`,
|
|
9128
|
+
"stelorder",
|
|
9129
|
+
500
|
|
9130
|
+
);
|
|
9131
|
+
}
|
|
9132
|
+
};
|
|
9133
|
+
|
|
9134
|
+
// src/providers/mock/mock.ts
|
|
9135
|
+
var FIXTURE_TIMESTAMP = "2026-01-01T00:00:00.000Z";
|
|
9136
|
+
var DEFAULT_SITE_URL = "https://mock.thorcommerce.local";
|
|
9137
|
+
var regionFixtures = [
|
|
9138
|
+
{
|
|
9139
|
+
id: "mock-region-us",
|
|
9140
|
+
name: "United States",
|
|
9141
|
+
currencyCode: "USD",
|
|
9142
|
+
locale: "en-US",
|
|
9143
|
+
taxRate: 0.08,
|
|
9144
|
+
countries: [{ code: "US", name: "United States" }]
|
|
9145
|
+
},
|
|
9146
|
+
{
|
|
9147
|
+
id: "mock-region-eu",
|
|
9148
|
+
name: "Europe",
|
|
9149
|
+
currencyCode: "EUR",
|
|
9150
|
+
locale: "en-ES",
|
|
9151
|
+
taxRate: 0.21,
|
|
9152
|
+
countries: [
|
|
9153
|
+
{ code: "ES", name: "Spain" },
|
|
9154
|
+
{ code: "FR", name: "France" },
|
|
9155
|
+
{ code: "DE", name: "Germany" }
|
|
9156
|
+
]
|
|
9157
|
+
}
|
|
9158
|
+
];
|
|
9159
|
+
var collectionFixtures = [
|
|
9160
|
+
{
|
|
9161
|
+
id: "mock-collection-new-arrivals",
|
|
9162
|
+
handle: "new-arrivals",
|
|
9163
|
+
title: "New Arrivals",
|
|
9164
|
+
description: "Fresh mock catalog items for layout and merchandising flows."
|
|
9165
|
+
},
|
|
9166
|
+
{
|
|
9167
|
+
id: "mock-collection-best-sellers",
|
|
9168
|
+
handle: "best-sellers",
|
|
9169
|
+
title: "Best Sellers",
|
|
9170
|
+
description: "High-performing mock products used to design hero grids and featured sections."
|
|
9171
|
+
},
|
|
9172
|
+
{
|
|
9173
|
+
id: "mock-collection-studio-essentials",
|
|
9174
|
+
handle: "studio-essentials",
|
|
9175
|
+
title: "Studio Essentials",
|
|
9176
|
+
description: "A balanced fixture set for mock storefront navigation and detail pages."
|
|
9177
|
+
}
|
|
9178
|
+
];
|
|
9179
|
+
var categoryFixtures = [
|
|
9180
|
+
{
|
|
9181
|
+
id: "mock-category-jackets",
|
|
9182
|
+
handle: "jackets",
|
|
9183
|
+
name: "Jackets",
|
|
9184
|
+
description: "Outerwear and layering pieces."
|
|
9185
|
+
},
|
|
9186
|
+
{
|
|
9187
|
+
id: "mock-category-dresses",
|
|
9188
|
+
handle: "dresses",
|
|
9189
|
+
name: "Dresses",
|
|
9190
|
+
description: "Editorial silhouettes for seasonal collections."
|
|
9191
|
+
},
|
|
9192
|
+
{
|
|
9193
|
+
id: "mock-category-home",
|
|
9194
|
+
handle: "home",
|
|
9195
|
+
name: "Home",
|
|
9196
|
+
description: "Decor and living objects for lifestyle layouts."
|
|
9197
|
+
},
|
|
9198
|
+
{
|
|
9199
|
+
id: "mock-category-accessories",
|
|
9200
|
+
handle: "accessories",
|
|
9201
|
+
name: "Accessories",
|
|
9202
|
+
description: "Complementary products for cart and bundle flows."
|
|
9203
|
+
}
|
|
9204
|
+
];
|
|
9205
|
+
var productFixtures = [
|
|
9206
|
+
{
|
|
9207
|
+
id: "mock-product-aurora-jacket",
|
|
9208
|
+
handle: "aurora-jacket",
|
|
9209
|
+
title: "Aurora Quilted Jacket",
|
|
9210
|
+
description: "Lightweight quilted outerwear with tonal hardware and a soft structured collar.",
|
|
9211
|
+
imageLabel: "Aurora Jacket",
|
|
9212
|
+
imageHue: 222,
|
|
9213
|
+
collectionHandles: ["new-arrivals", "best-sellers"],
|
|
9214
|
+
categoryHandle: "jackets",
|
|
9215
|
+
productType: "outerwear",
|
|
9216
|
+
vendor: "Thor Atelier",
|
|
9217
|
+
tags: ["outerwear", "quilted", "winter"],
|
|
9218
|
+
options: [
|
|
9219
|
+
{ id: "aurora-size", name: "Size", values: ["S", "M", "L"] },
|
|
9220
|
+
{ id: "aurora-color", name: "Color", values: ["Midnight"] }
|
|
9221
|
+
],
|
|
9222
|
+
variants: [
|
|
9223
|
+
{
|
|
9224
|
+
id: "mock-variant-aurora-s",
|
|
9225
|
+
title: "S / Midnight",
|
|
9226
|
+
price: 129,
|
|
9227
|
+
compareAtPrice: 159,
|
|
9228
|
+
quantityAvailable: 8,
|
|
9229
|
+
selectedOptions: [
|
|
9230
|
+
{ name: "Size", value: "S" },
|
|
9231
|
+
{ name: "Color", value: "Midnight" }
|
|
9232
|
+
]
|
|
9233
|
+
},
|
|
9234
|
+
{
|
|
9235
|
+
id: "mock-variant-aurora-m",
|
|
9236
|
+
title: "M / Midnight",
|
|
9237
|
+
price: 129,
|
|
9238
|
+
compareAtPrice: 159,
|
|
9239
|
+
quantityAvailable: 12,
|
|
9240
|
+
selectedOptions: [
|
|
9241
|
+
{ name: "Size", value: "M" },
|
|
9242
|
+
{ name: "Color", value: "Midnight" }
|
|
9243
|
+
]
|
|
9244
|
+
}
|
|
9245
|
+
]
|
|
9246
|
+
},
|
|
9247
|
+
{
|
|
9248
|
+
id: "mock-product-solis-dress",
|
|
9249
|
+
handle: "solis-dress",
|
|
9250
|
+
title: "Solis Pleated Dress",
|
|
9251
|
+
description: "A fluid pleated dress with a clean neckline designed for hero storytelling.",
|
|
9252
|
+
imageLabel: "Solis Dress",
|
|
9253
|
+
imageHue: 18,
|
|
9254
|
+
collectionHandles: ["new-arrivals", "studio-essentials"],
|
|
9255
|
+
categoryHandle: "dresses",
|
|
9256
|
+
productType: "dress",
|
|
9257
|
+
vendor: "Thor Atelier",
|
|
9258
|
+
tags: ["dress", "occasion", "pleated"],
|
|
9259
|
+
options: [
|
|
9260
|
+
{ id: "solis-size", name: "Size", values: ["XS", "S", "M"] },
|
|
9261
|
+
{ id: "solis-color", name: "Color", values: ["Clay"] }
|
|
9262
|
+
],
|
|
9263
|
+
variants: [
|
|
9264
|
+
{
|
|
9265
|
+
id: "mock-variant-solis-xs",
|
|
9266
|
+
title: "XS / Clay",
|
|
9267
|
+
price: 164,
|
|
9268
|
+
quantityAvailable: 4,
|
|
9269
|
+
selectedOptions: [
|
|
9270
|
+
{ name: "Size", value: "XS" },
|
|
9271
|
+
{ name: "Color", value: "Clay" }
|
|
9272
|
+
]
|
|
9273
|
+
},
|
|
9274
|
+
{
|
|
9275
|
+
id: "mock-variant-solis-s",
|
|
9276
|
+
title: "S / Clay",
|
|
9277
|
+
price: 164,
|
|
9278
|
+
quantityAvailable: 9,
|
|
9279
|
+
selectedOptions: [
|
|
9280
|
+
{ name: "Size", value: "S" },
|
|
9281
|
+
{ name: "Color", value: "Clay" }
|
|
9282
|
+
]
|
|
9283
|
+
}
|
|
9284
|
+
]
|
|
9285
|
+
},
|
|
9286
|
+
{
|
|
9287
|
+
id: "mock-product-helios-lamp",
|
|
9288
|
+
handle: "helios-lamp",
|
|
9289
|
+
title: "Helios Table Lamp",
|
|
9290
|
+
description: "Warm ambient lamp with sculptural proportions for lifestyle and home grids.",
|
|
9291
|
+
imageLabel: "Helios Lamp",
|
|
9292
|
+
imageHue: 45,
|
|
9293
|
+
collectionHandles: ["best-sellers", "studio-essentials"],
|
|
9294
|
+
categoryHandle: "home",
|
|
9295
|
+
productType: "lighting",
|
|
9296
|
+
vendor: "Thor Home",
|
|
9297
|
+
tags: ["home", "lighting", "decor"],
|
|
9298
|
+
options: [{ id: "helios-finish", name: "Finish", values: ["Brass"] }],
|
|
9299
|
+
variants: [
|
|
9300
|
+
{
|
|
9301
|
+
id: "mock-variant-helios-brass",
|
|
9302
|
+
title: "Brass",
|
|
9303
|
+
price: 96,
|
|
9304
|
+
quantityAvailable: 15,
|
|
9305
|
+
selectedOptions: [{ name: "Finish", value: "Brass" }]
|
|
9306
|
+
}
|
|
9307
|
+
]
|
|
9308
|
+
},
|
|
9309
|
+
{
|
|
9310
|
+
id: "mock-product-luna-bag",
|
|
9311
|
+
handle: "luna-bag",
|
|
9312
|
+
title: "Luna Crossbody Bag",
|
|
9313
|
+
description: "Compact everyday bag for accessory rails, checkout add-ons, and bundle modules.",
|
|
9314
|
+
imageLabel: "Luna Bag",
|
|
9315
|
+
imageHue: 306,
|
|
9316
|
+
collectionHandles: ["studio-essentials"],
|
|
9317
|
+
categoryHandle: "accessories",
|
|
9318
|
+
productType: "bag",
|
|
9319
|
+
vendor: "Thor Atelier",
|
|
9320
|
+
tags: ["bag", "accessory", "everyday"],
|
|
9321
|
+
options: [{ id: "luna-color", name: "Color", values: ["Berry"] }],
|
|
9322
|
+
variants: [
|
|
9323
|
+
{
|
|
9324
|
+
id: "mock-variant-luna-berry",
|
|
9325
|
+
title: "Berry",
|
|
9326
|
+
price: 82,
|
|
9327
|
+
quantityAvailable: 18,
|
|
9328
|
+
selectedOptions: [{ name: "Color", value: "Berry" }]
|
|
9329
|
+
}
|
|
9330
|
+
]
|
|
9331
|
+
}
|
|
9332
|
+
];
|
|
9333
|
+
var stockLocationFixture = {
|
|
9334
|
+
id: "mock-stock-primary",
|
|
9335
|
+
name: "Mock Main Warehouse",
|
|
9336
|
+
address: {
|
|
9337
|
+
address1: "100 Mock Avenue",
|
|
9338
|
+
city: "Design City",
|
|
9339
|
+
countryCode: "US",
|
|
9340
|
+
postalCode: "10001",
|
|
9341
|
+
province: "NY"
|
|
9342
|
+
},
|
|
9343
|
+
metadata: {
|
|
9344
|
+
timezone: "America/New_York"
|
|
9345
|
+
}
|
|
9346
|
+
};
|
|
9347
|
+
var cartStore = /* @__PURE__ */ new Map();
|
|
9348
|
+
var orderStore = /* @__PURE__ */ new Map();
|
|
9349
|
+
var sequence = 0;
|
|
9350
|
+
function nextId(prefix) {
|
|
9351
|
+
sequence += 1;
|
|
9352
|
+
return `${prefix}-${sequence}`;
|
|
9353
|
+
}
|
|
9354
|
+
function createMoney(amount, currencyCode) {
|
|
9355
|
+
return {
|
|
9356
|
+
amount: amount.toFixed(2),
|
|
9357
|
+
currencyCode
|
|
9358
|
+
};
|
|
9359
|
+
}
|
|
9360
|
+
function createImage(label, hue) {
|
|
9361
|
+
const svg = `
|
|
9362
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200" role="img" aria-label="${label}">
|
|
9363
|
+
<defs>
|
|
9364
|
+
<linearGradient id="g" x1="0" x2="1" y1="0" y2="1">
|
|
9365
|
+
<stop offset="0%" stop-color="hsl(${hue}, 72%, 72%)" />
|
|
9366
|
+
<stop offset="100%" stop-color="hsl(${(hue + 48) % 360}, 62%, 42%)" />
|
|
9367
|
+
</linearGradient>
|
|
9368
|
+
</defs>
|
|
9369
|
+
<rect width="1200" height="1200" fill="url(#g)" rx="48" />
|
|
9370
|
+
<circle cx="910" cy="280" r="180" fill="rgba(255,255,255,0.22)" />
|
|
9371
|
+
<text x="90" y="990" fill="white" font-family="Arial, sans-serif" font-size="96" font-weight="700">${label}</text>
|
|
9372
|
+
</svg>
|
|
9373
|
+
`.trim();
|
|
9374
|
+
return {
|
|
9375
|
+
url: `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`,
|
|
9376
|
+
altText: label,
|
|
9377
|
+
width: 1200,
|
|
9378
|
+
height: 1200
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9381
|
+
function getRegionFixture(regionId) {
|
|
9382
|
+
if (!regionId) {
|
|
9383
|
+
return regionFixtures[0];
|
|
9384
|
+
}
|
|
9385
|
+
return regionFixtures.find((region) => region.id === regionId) ?? regionFixtures[0];
|
|
9386
|
+
}
|
|
9387
|
+
function createProductImageSet(label, hue) {
|
|
9388
|
+
const featuredImage = createImage(label, hue);
|
|
9389
|
+
return {
|
|
9390
|
+
featuredImage,
|
|
9391
|
+
images: [featuredImage, createImage(`${label} Detail`, (hue + 18) % 360)]
|
|
9392
|
+
};
|
|
9393
|
+
}
|
|
9394
|
+
function buildCollections() {
|
|
9395
|
+
return collectionFixtures.map((collection) => ({
|
|
9396
|
+
id: collection.id,
|
|
9397
|
+
handle: collection.handle,
|
|
9398
|
+
title: collection.title,
|
|
9399
|
+
description: collection.description,
|
|
9400
|
+
path: `/collections/${collection.handle}`,
|
|
9401
|
+
updatedAt: FIXTURE_TIMESTAMP
|
|
9402
|
+
}));
|
|
9403
|
+
}
|
|
9404
|
+
function buildCategories() {
|
|
9405
|
+
return categoryFixtures.map((category) => ({
|
|
9406
|
+
id: category.id,
|
|
9407
|
+
handle: category.handle,
|
|
9408
|
+
name: category.name,
|
|
9409
|
+
description: category.description,
|
|
9410
|
+
parentCategoryId: category.parentCategoryId,
|
|
9411
|
+
productCount: productFixtures.filter((product) => product.categoryHandle === category.handle).length,
|
|
9412
|
+
image: createImage(category.name, 180).url
|
|
9413
|
+
}));
|
|
9414
|
+
}
|
|
9415
|
+
function buildProducts(currencyCode) {
|
|
9416
|
+
const collections = buildCollections();
|
|
9417
|
+
return productFixtures.map((product) => {
|
|
9418
|
+
const { featuredImage, images } = createProductImageSet(product.imageLabel, product.imageHue);
|
|
9419
|
+
const variants = product.variants.map((variant) => ({
|
|
9420
|
+
id: variant.id,
|
|
9421
|
+
title: variant.title,
|
|
9422
|
+
availableForSale: variant.quantityAvailable > 0,
|
|
9423
|
+
selectedOptions: variant.selectedOptions,
|
|
9424
|
+
price: createMoney(variant.price, currencyCode),
|
|
9425
|
+
compareAtPrice: variant.compareAtPrice ? createMoney(variant.compareAtPrice, currencyCode) : void 0,
|
|
9426
|
+
quantityAvailable: variant.quantityAvailable,
|
|
9427
|
+
image: featuredImage
|
|
9428
|
+
}));
|
|
9429
|
+
const prices = product.variants.map((variant) => variant.price);
|
|
9430
|
+
return {
|
|
9431
|
+
id: product.id,
|
|
9432
|
+
handle: product.handle,
|
|
9433
|
+
title: product.title,
|
|
9434
|
+
description: product.description,
|
|
9435
|
+
availableForSale: variants.some((variant) => variant.availableForSale),
|
|
9436
|
+
options: product.options,
|
|
9437
|
+
variants,
|
|
9438
|
+
featuredImage,
|
|
9439
|
+
images,
|
|
9440
|
+
priceRange: {
|
|
9441
|
+
minVariantPrice: createMoney(Math.min(...prices), currencyCode),
|
|
9442
|
+
maxVariantPrice: createMoney(Math.max(...prices), currencyCode)
|
|
9443
|
+
},
|
|
9444
|
+
collections: product.collectionHandles.map((handle) => collections.find((collection) => collection.handle === handle)).filter((collection) => Boolean(collection)).map((collection) => ({
|
|
9445
|
+
id: collection.id,
|
|
9446
|
+
title: collection.title,
|
|
9447
|
+
handle: collection.handle
|
|
9448
|
+
})),
|
|
9449
|
+
productType: product.productType,
|
|
9450
|
+
vendor: product.vendor,
|
|
9451
|
+
tags: product.tags,
|
|
9452
|
+
createdAt: FIXTURE_TIMESTAMP,
|
|
9453
|
+
updatedAt: FIXTURE_TIMESTAMP,
|
|
9454
|
+
metadata: {
|
|
9455
|
+
categoryHandle: product.categoryHandle,
|
|
9456
|
+
collectionHandles: product.collectionHandles
|
|
9457
|
+
}
|
|
9458
|
+
};
|
|
9459
|
+
});
|
|
9460
|
+
}
|
|
9461
|
+
function filterProducts(products, options) {
|
|
9462
|
+
const query = options.query?.trim().toLowerCase();
|
|
9463
|
+
const categoryIds = new Set(options.categoryIds ?? []);
|
|
9464
|
+
const collectionIds = new Set(options.collectionIds ?? []);
|
|
9465
|
+
return products.filter((product) => {
|
|
9466
|
+
if (query) {
|
|
9467
|
+
const matchesQuery = [product.title, product.description, ...product.tags ?? []].join(" ").toLowerCase().includes(query);
|
|
9468
|
+
if (!matchesQuery) {
|
|
9469
|
+
return false;
|
|
9470
|
+
}
|
|
9471
|
+
}
|
|
9472
|
+
if (categoryIds.size > 0) {
|
|
9473
|
+
const categoryHandle = String(product.metadata?.categoryHandle ?? "");
|
|
9474
|
+
const category = categoryFixtures.find((item) => item.handle === categoryHandle);
|
|
9475
|
+
const matchesCategory = category ? categoryIds.has(category.id) || categoryIds.has(category.handle) : false;
|
|
9476
|
+
if (!matchesCategory) {
|
|
9477
|
+
return false;
|
|
9478
|
+
}
|
|
9479
|
+
}
|
|
9480
|
+
if (collectionIds.size > 0) {
|
|
9481
|
+
const productCollections = (product.collections ?? []).map((collection) => collection.handle);
|
|
9482
|
+
const matchesCollection = (product.collections ?? []).some(
|
|
9483
|
+
(collection) => collectionIds.has(collection.id) || collectionIds.has(collection.handle)
|
|
9484
|
+
) || productCollections.some((handle) => collectionIds.has(handle));
|
|
9485
|
+
if (!matchesCollection) {
|
|
9486
|
+
return false;
|
|
9487
|
+
}
|
|
9488
|
+
}
|
|
9489
|
+
return true;
|
|
9490
|
+
});
|
|
9491
|
+
}
|
|
9492
|
+
function sortProducts(products, sortKey, reverse) {
|
|
9493
|
+
const sorted = [...products];
|
|
9494
|
+
switch (sortKey) {
|
|
9495
|
+
case "price":
|
|
9496
|
+
case "price-asc":
|
|
9497
|
+
case "price-desc":
|
|
9498
|
+
sorted.sort(
|
|
9499
|
+
(left, right) => Number(left.priceRange.minVariantPrice.amount) - Number(right.priceRange.minVariantPrice.amount)
|
|
9500
|
+
);
|
|
9501
|
+
break;
|
|
9502
|
+
case "created_at":
|
|
9503
|
+
case "createdAt":
|
|
9504
|
+
case "newest":
|
|
9505
|
+
sorted.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
9506
|
+
break;
|
|
9507
|
+
case "title":
|
|
9508
|
+
case "name":
|
|
9509
|
+
default:
|
|
9510
|
+
sorted.sort((left, right) => left.title.localeCompare(right.title));
|
|
9511
|
+
break;
|
|
9512
|
+
}
|
|
9513
|
+
const shouldReverse = reverse || sortKey === "price-desc" || sortKey === "newest";
|
|
9514
|
+
return shouldReverse ? sorted.reverse() : sorted;
|
|
9515
|
+
}
|
|
9516
|
+
function paginateProducts(products, skip, first) {
|
|
9517
|
+
const start = Math.max(0, skip ?? 0);
|
|
9518
|
+
const end = first ? start + first : void 0;
|
|
9519
|
+
return products.slice(start, end);
|
|
9520
|
+
}
|
|
9521
|
+
function resolveVariant(currencyCode, merchandiseId) {
|
|
9522
|
+
const products = buildProducts(currencyCode);
|
|
9523
|
+
for (const product of products) {
|
|
9524
|
+
const variant = product.variants.find((item) => item.id === merchandiseId);
|
|
9525
|
+
if (variant) {
|
|
9526
|
+
return { product, variant };
|
|
9527
|
+
}
|
|
9528
|
+
}
|
|
9529
|
+
return void 0;
|
|
9530
|
+
}
|
|
9531
|
+
function getShippingPrice(methodId) {
|
|
9532
|
+
switch (methodId) {
|
|
9533
|
+
case "mock-shipping-express":
|
|
9534
|
+
return 18;
|
|
9535
|
+
case "mock-shipping-standard":
|
|
9536
|
+
return 8;
|
|
9537
|
+
default:
|
|
9538
|
+
return 0;
|
|
9539
|
+
}
|
|
9540
|
+
}
|
|
9541
|
+
function buildExternalCart(state, currencyCode, siteUrl) {
|
|
9542
|
+
const region = getRegionFixture(state.regionId);
|
|
9543
|
+
const regionCurrency = region.currencyCode || currencyCode;
|
|
9544
|
+
const lines = state.lines.flatMap((line) => {
|
|
9545
|
+
const resolved = resolveVariant(regionCurrency, line.merchandiseId);
|
|
9546
|
+
if (!resolved || !resolved.product.featuredImage) {
|
|
9547
|
+
return [];
|
|
9548
|
+
}
|
|
9549
|
+
const lineTotal = Number(resolved.variant.price.amount) * line.quantity;
|
|
9550
|
+
const stockStatus = resolved.variant.quantityAvailable && resolved.variant.quantityAvailable > 0 ? "in_stock" : "out_of_stock";
|
|
9551
|
+
return [{
|
|
9552
|
+
id: line.id,
|
|
9553
|
+
quantity: line.quantity,
|
|
9554
|
+
stockStatus,
|
|
9555
|
+
cost: {
|
|
9556
|
+
totalAmount: createMoney(lineTotal, regionCurrency)
|
|
9557
|
+
},
|
|
9558
|
+
merchandise: {
|
|
9559
|
+
id: resolved.variant.id,
|
|
9560
|
+
title: resolved.variant.title,
|
|
9561
|
+
selectedOptions: resolved.variant.selectedOptions,
|
|
9562
|
+
product: {
|
|
9563
|
+
id: resolved.product.id,
|
|
9564
|
+
handle: resolved.product.handle,
|
|
9565
|
+
title: resolved.product.title,
|
|
9566
|
+
featuredImage: resolved.product.featuredImage
|
|
9567
|
+
}
|
|
9568
|
+
}
|
|
9569
|
+
}];
|
|
9570
|
+
});
|
|
9571
|
+
const subtotal = lines.reduce(
|
|
9572
|
+
(sum, line) => sum + Number(line.cost.totalAmount.amount),
|
|
9573
|
+
0
|
|
9574
|
+
);
|
|
9575
|
+
const shipping = getShippingPrice(state.shippingMethodId);
|
|
9576
|
+
const discount = state.discountCode ? subtotal * 0.1 : 0;
|
|
9577
|
+
const taxableBase = Math.max(subtotal + shipping - discount, 0);
|
|
9578
|
+
const totalTax = region.taxRate ? taxableBase * region.taxRate : 0;
|
|
9579
|
+
const total = taxableBase + totalTax;
|
|
9580
|
+
return {
|
|
9581
|
+
id: state.id,
|
|
9582
|
+
checkoutUrl: `${siteUrl}/checkout?cart=${state.id}`,
|
|
9583
|
+
cost: {
|
|
9584
|
+
subtotalAmount: createMoney(subtotal, regionCurrency),
|
|
9585
|
+
totalAmount: createMoney(total, regionCurrency),
|
|
9586
|
+
totalTaxAmount: createMoney(totalTax, regionCurrency)
|
|
9587
|
+
},
|
|
9588
|
+
lines,
|
|
9589
|
+
totalQuantity: lines.reduce((sum, line) => sum + line.quantity, 0),
|
|
9590
|
+
completedAt: state.completedAt
|
|
9591
|
+
};
|
|
9592
|
+
}
|
|
9593
|
+
function buildOrderFromCart(state, currencyCode, siteUrl) {
|
|
9594
|
+
const cart = buildExternalCart(state, currencyCode, siteUrl);
|
|
9595
|
+
return {
|
|
9596
|
+
id: `mock-order-${state.id}`,
|
|
9597
|
+
orderNumber: `${1e3 + sequence}`,
|
|
9598
|
+
email: "mock-customer@thorprovider.dev",
|
|
9599
|
+
status: "completed",
|
|
9600
|
+
paymentStatus: state.paymentProviderId ? "paid" : "pending",
|
|
9601
|
+
fulfillmentStatus: state.shippingMethodId ? "fulfilled" : "unfulfilled",
|
|
9602
|
+
items: cart.lines.map((line) => ({
|
|
9603
|
+
id: line.id ?? nextId("mock-order-line"),
|
|
9604
|
+
title: line.merchandise.product.title,
|
|
9605
|
+
variantTitle: line.merchandise.title,
|
|
9606
|
+
quantity: line.quantity,
|
|
9607
|
+
price: line.merchandise.product.featuredImage ? createMoney(Number(line.cost.totalAmount.amount) / Math.max(line.quantity, 1), cart.cost.totalAmount.currencyCode) : createMoney(0, cart.cost.totalAmount.currencyCode),
|
|
9608
|
+
total: line.cost.totalAmount,
|
|
9609
|
+
productId: line.merchandise.product.id,
|
|
9610
|
+
variantId: line.merchandise.id,
|
|
9611
|
+
image: line.merchandise.product.featuredImage
|
|
9612
|
+
})),
|
|
9613
|
+
subtotal: cart.cost.subtotalAmount,
|
|
9614
|
+
total: cart.cost.totalAmount,
|
|
9615
|
+
tax: cart.cost.totalTaxAmount,
|
|
9616
|
+
shipping: createMoney(getShippingPrice(state.shippingMethodId), cart.cost.totalAmount.currencyCode),
|
|
9617
|
+
discount: createMoney(state.discountCode ? Number(cart.cost.subtotalAmount.amount) * 0.1 : 0, cart.cost.totalAmount.currencyCode),
|
|
9618
|
+
createdAt: FIXTURE_TIMESTAMP,
|
|
9619
|
+
updatedAt: FIXTURE_TIMESTAMP,
|
|
9620
|
+
completedAt: state.completedAt,
|
|
9621
|
+
metadata: {
|
|
9622
|
+
provider: "mock",
|
|
9623
|
+
checkoutUrl: cart.checkoutUrl
|
|
9624
|
+
}
|
|
9625
|
+
};
|
|
9626
|
+
}
|
|
9627
|
+
function getMockCollections() {
|
|
9628
|
+
return buildCollections();
|
|
9629
|
+
}
|
|
9630
|
+
function getMockCategories() {
|
|
9631
|
+
return buildCategories();
|
|
9632
|
+
}
|
|
9633
|
+
function getMockProducts(options) {
|
|
9634
|
+
const region = getRegionFixture(options?.regionId);
|
|
9635
|
+
const currencyCode = options?.currencyCode ?? region.currencyCode;
|
|
9636
|
+
const products = buildProducts(currencyCode);
|
|
9637
|
+
const filtered = filterProducts(products, {
|
|
9638
|
+
query: options?.query,
|
|
9639
|
+
categoryIds: options?.categoryIds,
|
|
9640
|
+
collectionIds: options?.collectionIds
|
|
9641
|
+
});
|
|
9642
|
+
const sorted = sortProducts(filtered, options?.sortKey, options?.reverse);
|
|
9643
|
+
return paginateProducts(sorted, options?.skip, options?.first);
|
|
9644
|
+
}
|
|
9645
|
+
function getMockProduct(handle, regionId) {
|
|
9646
|
+
const region = getRegionFixture(regionId);
|
|
9647
|
+
return buildProducts(region.currencyCode).find(
|
|
9648
|
+
(product) => product.handle === handle || product.id === handle
|
|
9649
|
+
);
|
|
9650
|
+
}
|
|
9651
|
+
function getMockProductRecommendations(productId, regionId) {
|
|
9652
|
+
const product = getMockProduct(productId, regionId) ?? buildProducts(getRegionFixture(regionId).currencyCode).find((item) => item.id === productId);
|
|
9653
|
+
if (!product) {
|
|
9654
|
+
return [];
|
|
9655
|
+
}
|
|
9656
|
+
const collectionHandles = new Set((product.collections ?? []).map((collection) => collection.handle));
|
|
9657
|
+
return buildProducts(getRegionFixture(regionId).currencyCode).filter((candidate) => candidate.id !== product.id).filter(
|
|
9658
|
+
(candidate) => (candidate.collections ?? []).some((collection) => collectionHandles.has(collection.handle))
|
|
9659
|
+
).slice(0, 4);
|
|
9660
|
+
}
|
|
9661
|
+
function getMockCollection(handle) {
|
|
9662
|
+
return buildCollections().find(
|
|
9663
|
+
(collection) => collection.handle === handle || collection.id === handle
|
|
9664
|
+
);
|
|
9665
|
+
}
|
|
9666
|
+
function getMockCategory(idOrHandle) {
|
|
9667
|
+
return buildCategories().find(
|
|
9668
|
+
(category) => category.handle === idOrHandle || category.id === idOrHandle
|
|
9669
|
+
);
|
|
9670
|
+
}
|
|
9671
|
+
function getMockRegions() {
|
|
9672
|
+
return regionFixtures.map((region) => ({
|
|
9673
|
+
id: region.id,
|
|
9674
|
+
name: region.name,
|
|
9675
|
+
currency_code: region.currencyCode,
|
|
9676
|
+
countries: region.countries.map((country) => ({
|
|
9677
|
+
id: `country-${country.code.toLowerCase()}`,
|
|
9678
|
+
iso_2: country.code.toLowerCase(),
|
|
9679
|
+
name: country.name,
|
|
9680
|
+
display_name: country.name
|
|
9681
|
+
}))
|
|
9682
|
+
}));
|
|
9683
|
+
}
|
|
9684
|
+
function getMockAdminRegions() {
|
|
9685
|
+
return regionFixtures.map((region) => ({
|
|
9686
|
+
id: region.id,
|
|
9687
|
+
name: region.name,
|
|
9688
|
+
countryCodes: region.countries.map((country) => country.code),
|
|
9689
|
+
currency: region.currencyCode,
|
|
9690
|
+
taxRate: region.taxRate,
|
|
9691
|
+
isEnabled: true
|
|
9692
|
+
}));
|
|
9693
|
+
}
|
|
9694
|
+
function getMockRegionCountries(regionId) {
|
|
9695
|
+
const region = regionFixtures.find((item) => item.id === regionId);
|
|
9696
|
+
return region?.countries ?? [];
|
|
9697
|
+
}
|
|
9698
|
+
function createMockCart(regionId) {
|
|
9699
|
+
const cart = {
|
|
9700
|
+
id: nextId("mock-cart"),
|
|
9701
|
+
regionId: regionId ?? regionFixtures[0].id,
|
|
9702
|
+
lines: []
|
|
9703
|
+
};
|
|
9704
|
+
cartStore.set(cart.id, cart);
|
|
9705
|
+
return cart;
|
|
9706
|
+
}
|
|
9707
|
+
function getMockCartState(cartId) {
|
|
9708
|
+
return cartStore.get(cartId);
|
|
9709
|
+
}
|
|
9710
|
+
function saveMockCartState(cart) {
|
|
9711
|
+
cartStore.set(cart.id, cart);
|
|
9712
|
+
return cart;
|
|
9713
|
+
}
|
|
9714
|
+
function buildMockCart(cart, currencyCode, siteUrl) {
|
|
9715
|
+
return buildExternalCart(
|
|
9716
|
+
cart,
|
|
9717
|
+
currencyCode ?? getRegionFixture(cart.regionId).currencyCode,
|
|
9718
|
+
siteUrl ?? DEFAULT_SITE_URL
|
|
9719
|
+
);
|
|
9720
|
+
}
|
|
9721
|
+
function getMockShippingMethods(regionId) {
|
|
9722
|
+
const currencyCode = getRegionFixture(regionId).currencyCode;
|
|
9723
|
+
return [
|
|
9724
|
+
{
|
|
9725
|
+
id: "mock-shipping-standard",
|
|
9726
|
+
name: "Standard Shipping",
|
|
9727
|
+
description: "Fixture shipping option for checkout and cart layouts.",
|
|
9728
|
+
price: createMoney(8, currencyCode),
|
|
9729
|
+
estimatedDays: "3-5 business days"
|
|
9730
|
+
},
|
|
9731
|
+
{
|
|
9732
|
+
id: "mock-shipping-express",
|
|
9733
|
+
name: "Express Shipping",
|
|
9734
|
+
description: "Faster fixture shipping option for premium checkout flows.",
|
|
9735
|
+
price: createMoney(18, currencyCode),
|
|
9736
|
+
estimatedDays: "1-2 business days"
|
|
9737
|
+
}
|
|
9738
|
+
];
|
|
9739
|
+
}
|
|
9740
|
+
function getMockPaymentMethods(currencyCode) {
|
|
9741
|
+
return [
|
|
9742
|
+
{
|
|
9743
|
+
id: "mock-card",
|
|
9744
|
+
name: "Mock Card",
|
|
9745
|
+
type: "card",
|
|
9746
|
+
isEnabled: true,
|
|
9747
|
+
requiresSetup: true,
|
|
9748
|
+
description: `Fixture card checkout for ${currencyCode}.`
|
|
9749
|
+
},
|
|
9750
|
+
{
|
|
9751
|
+
id: "mock-cash",
|
|
9752
|
+
name: "Cash on Delivery",
|
|
9753
|
+
type: "cash_on_delivery",
|
|
9754
|
+
isEnabled: true,
|
|
9755
|
+
requiresSetup: false,
|
|
9756
|
+
description: "Mock cash payment option for checkout prototypes."
|
|
9757
|
+
}
|
|
9758
|
+
];
|
|
9759
|
+
}
|
|
9760
|
+
function getMockStockLocations() {
|
|
9761
|
+
return [stockLocationFixture];
|
|
9762
|
+
}
|
|
9763
|
+
function getMockInventoryLevels(variantId) {
|
|
9764
|
+
for (const region of regionFixtures) {
|
|
9765
|
+
const resolved = resolveVariant(region.currencyCode, variantId);
|
|
9766
|
+
if (resolved) {
|
|
9767
|
+
return [{
|
|
9768
|
+
locationId: stockLocationFixture.id,
|
|
9769
|
+
locationName: stockLocationFixture.name,
|
|
9770
|
+
availableQuantity: resolved.variant.quantityAvailable ?? 0,
|
|
9771
|
+
reservedQuantity: 0,
|
|
9772
|
+
stockedQuantity: resolved.variant.quantityAvailable ?? 0
|
|
9773
|
+
}];
|
|
9774
|
+
}
|
|
9775
|
+
}
|
|
9776
|
+
return [];
|
|
9777
|
+
}
|
|
9778
|
+
function validateMockCartStock(cart) {
|
|
9779
|
+
const currencyCode = getRegionFixture(cart.regionId).currencyCode;
|
|
9780
|
+
const unavailableItems = cart.lines.flatMap((line) => {
|
|
9781
|
+
const resolved = resolveVariant(currencyCode, line.merchandiseId);
|
|
9782
|
+
if (!resolved) {
|
|
9783
|
+
return [];
|
|
9784
|
+
}
|
|
9785
|
+
const availableQuantity = resolved.variant.quantityAvailable ?? 0;
|
|
9786
|
+
if (line.quantity <= availableQuantity) {
|
|
9787
|
+
return [];
|
|
9788
|
+
}
|
|
9789
|
+
return [{
|
|
9790
|
+
variantId: resolved.variant.id,
|
|
9791
|
+
productName: resolved.product.title,
|
|
9792
|
+
requestedQuantity: line.quantity,
|
|
9793
|
+
availableQuantity
|
|
9794
|
+
}];
|
|
9795
|
+
});
|
|
9796
|
+
return {
|
|
9797
|
+
allAvailable: unavailableItems.length === 0,
|
|
9798
|
+
unavailableItems
|
|
9799
|
+
};
|
|
9800
|
+
}
|
|
9801
|
+
function getMockFulfillmentOptions(regionId) {
|
|
9802
|
+
return getMockShippingMethods(regionId).map((method) => ({
|
|
9803
|
+
id: method.id,
|
|
9804
|
+
providerId: "mock-fulfillment",
|
|
9805
|
+
name: method.name,
|
|
9806
|
+
description: method.description,
|
|
9807
|
+
price: method.price,
|
|
9808
|
+
estimatedDays: method.estimatedDays,
|
|
9809
|
+
stockLocation: stockLocationFixture
|
|
9810
|
+
}));
|
|
9811
|
+
}
|
|
9812
|
+
function completeMockCheckout(cart, currencyCode, siteUrl) {
|
|
9813
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9814
|
+
const nextCart = {
|
|
9815
|
+
...cart,
|
|
9816
|
+
completedAt
|
|
9817
|
+
};
|
|
9818
|
+
cartStore.set(nextCart.id, nextCart);
|
|
9819
|
+
const order = buildOrderFromCart(
|
|
9820
|
+
nextCart,
|
|
9821
|
+
currencyCode ?? getRegionFixture(nextCart.regionId).currencyCode,
|
|
9822
|
+
siteUrl ?? DEFAULT_SITE_URL
|
|
9823
|
+
);
|
|
9824
|
+
orderStore.set(order.id, order);
|
|
9825
|
+
return order;
|
|
9826
|
+
}
|
|
9827
|
+
function getMockAdminOrders() {
|
|
9828
|
+
const orders = Array.from(orderStore.values()).sort(
|
|
9829
|
+
(left, right) => right.createdAt.localeCompare(left.createdAt)
|
|
9830
|
+
);
|
|
9831
|
+
return {
|
|
9832
|
+
orders,
|
|
9833
|
+
count: orders.length
|
|
9834
|
+
};
|
|
9835
|
+
}
|
|
9836
|
+
function getMockOrder(orderId) {
|
|
9837
|
+
return orderStore.get(orderId);
|
|
9838
|
+
}
|
|
9839
|
+
function saveMockOrder(order) {
|
|
9840
|
+
orderStore.set(order.id, order);
|
|
9841
|
+
return order;
|
|
9842
|
+
}
|
|
9843
|
+
|
|
9844
|
+
// src/providers/mock/index.ts
|
|
9845
|
+
var MockProvider = class {
|
|
9846
|
+
name = "mock";
|
|
9847
|
+
version = "1.0.0";
|
|
9848
|
+
capabilities = MOCK_CAPABILITIES;
|
|
9849
|
+
isMock = true;
|
|
9850
|
+
currencyCode;
|
|
9851
|
+
siteUrl;
|
|
9852
|
+
constructor(config = {}) {
|
|
9853
|
+
this.currencyCode = config.currencyCode ?? "USD";
|
|
9854
|
+
this.siteUrl = config.siteUrl ?? "https://mock.thorcommerce.local";
|
|
9855
|
+
}
|
|
9856
|
+
hasVariant(merchandiseId, regionId) {
|
|
9857
|
+
return getMockProducts({
|
|
9858
|
+
currencyCode: this.currencyCode,
|
|
9859
|
+
regionId
|
|
9860
|
+
}).some(
|
|
9861
|
+
(product) => product.variants.some((variant) => variant.id === merchandiseId)
|
|
9862
|
+
);
|
|
9863
|
+
}
|
|
9864
|
+
async getProduct(handle, options) {
|
|
9865
|
+
return getMockProduct(handle, options?.regionId);
|
|
9866
|
+
}
|
|
9867
|
+
async getProducts(options) {
|
|
9868
|
+
return getMockProducts({
|
|
9869
|
+
currencyCode: this.currencyCode,
|
|
9870
|
+
query: options?.query,
|
|
9871
|
+
sortKey: options?.sortKey,
|
|
9872
|
+
reverse: options?.reverse,
|
|
9873
|
+
first: options?.first,
|
|
9874
|
+
skip: options?.skip,
|
|
9875
|
+
categoryIds: options?.categoryIds,
|
|
9876
|
+
collectionIds: options?.collectionIds,
|
|
9877
|
+
regionId: options?.regionId
|
|
9878
|
+
});
|
|
9879
|
+
}
|
|
9880
|
+
async getProductRecommendations(productId) {
|
|
9881
|
+
return getMockProductRecommendations(productId);
|
|
9882
|
+
}
|
|
9883
|
+
async getCollection(handle) {
|
|
9884
|
+
return getMockCollection(handle);
|
|
9885
|
+
}
|
|
9886
|
+
async getCollections(options) {
|
|
9887
|
+
const collections = getMockCollections();
|
|
9888
|
+
const query = options?.query?.trim().toLowerCase();
|
|
9889
|
+
const filtered = query ? collections.filter(
|
|
9890
|
+
(collection) => [collection.title, collection.description, collection.handle].join(" ").toLowerCase().includes(query)
|
|
9891
|
+
) : collections;
|
|
9892
|
+
return filtered.slice(0, options?.limit ?? filtered.length);
|
|
9893
|
+
}
|
|
9894
|
+
async getCollectionProducts(handle, options) {
|
|
9895
|
+
const collection = getMockCollection(handle);
|
|
9896
|
+
if (!collection) {
|
|
9897
|
+
return [];
|
|
9898
|
+
}
|
|
9899
|
+
return getMockProducts({
|
|
9900
|
+
currencyCode: this.currencyCode,
|
|
9901
|
+
collectionIds: [collection.id],
|
|
9902
|
+
sortKey: options?.sortKey,
|
|
9903
|
+
reverse: options?.reverse,
|
|
9904
|
+
first: options?.first
|
|
9905
|
+
});
|
|
9906
|
+
}
|
|
9907
|
+
async getCategory(idOrHandle) {
|
|
9908
|
+
return getMockCategory(idOrHandle);
|
|
9909
|
+
}
|
|
9910
|
+
async getCategories(options) {
|
|
9911
|
+
const categories = getMockCategories();
|
|
9912
|
+
const query = options?.query?.trim().toLowerCase();
|
|
9913
|
+
let filtered = query ? categories.filter(
|
|
9914
|
+
(category) => [category.name, category.description ?? "", category.handle].join(" ").toLowerCase().includes(query)
|
|
9915
|
+
) : categories;
|
|
9916
|
+
if (options?.parentCategoryId) {
|
|
9917
|
+
filtered = filtered.filter((category) => category.parentCategoryId === options.parentCategoryId);
|
|
9918
|
+
}
|
|
9919
|
+
return filtered.slice(0, options?.limit ?? filtered.length);
|
|
9920
|
+
}
|
|
9921
|
+
async getCategoryProducts(handle, options) {
|
|
9922
|
+
const category = getMockCategory(handle);
|
|
9923
|
+
if (!category) {
|
|
9924
|
+
return [];
|
|
9925
|
+
}
|
|
9926
|
+
return getMockProducts({
|
|
9927
|
+
currencyCode: this.currencyCode,
|
|
9928
|
+
categoryIds: [category.id],
|
|
9929
|
+
sortKey: options?.sortKey,
|
|
9930
|
+
reverse: options?.reverse,
|
|
9931
|
+
first: options?.first
|
|
9932
|
+
});
|
|
9933
|
+
}
|
|
9934
|
+
async createCart(options) {
|
|
9935
|
+
const cart = createMockCart(options?.regionId);
|
|
9936
|
+
return buildMockCart(cart, this.currencyCode, this.siteUrl);
|
|
9937
|
+
}
|
|
9938
|
+
async getCart(cartId) {
|
|
9939
|
+
const cart = getMockCartState(cartId);
|
|
9940
|
+
return cart ? buildMockCart(cart, this.currencyCode, this.siteUrl) : void 0;
|
|
9941
|
+
}
|
|
9942
|
+
async addToCart(cartId, lines) {
|
|
9943
|
+
const cart = getMockCartState(cartId);
|
|
9944
|
+
if (!cart) {
|
|
9945
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
9946
|
+
}
|
|
9947
|
+
for (const line of lines) {
|
|
9948
|
+
if (!this.hasVariant(line.merchandiseId, cart.regionId)) {
|
|
9949
|
+
throw new ResourceNotFoundError("variant", line.merchandiseId);
|
|
9950
|
+
}
|
|
9951
|
+
}
|
|
9952
|
+
const nextLines = [...cart.lines];
|
|
9953
|
+
for (const line of lines) {
|
|
9954
|
+
const existing = nextLines.find((item) => item.merchandiseId === line.merchandiseId);
|
|
9955
|
+
if (existing) {
|
|
9956
|
+
existing.quantity += line.quantity;
|
|
9957
|
+
} else {
|
|
9958
|
+
nextLines.push({
|
|
9959
|
+
id: `mock-line-${line.merchandiseId}`,
|
|
9960
|
+
merchandiseId: line.merchandiseId,
|
|
9961
|
+
quantity: line.quantity
|
|
9962
|
+
});
|
|
9963
|
+
}
|
|
9964
|
+
}
|
|
9965
|
+
const saved = saveMockCartState({ ...cart, lines: nextLines });
|
|
9966
|
+
return buildMockCart(saved, this.currencyCode, this.siteUrl);
|
|
9967
|
+
}
|
|
9968
|
+
async removeFromCart(cartId, lineIds) {
|
|
9969
|
+
const cart = getMockCartState(cartId);
|
|
9970
|
+
if (!cart) {
|
|
9971
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
9972
|
+
}
|
|
9973
|
+
const saved = saveMockCartState({
|
|
9974
|
+
...cart,
|
|
9975
|
+
lines: cart.lines.filter((line) => !lineIds.includes(line.id))
|
|
9976
|
+
});
|
|
9977
|
+
return buildMockCart(saved, this.currencyCode, this.siteUrl);
|
|
9978
|
+
}
|
|
9979
|
+
async updateCart(cartId, lines) {
|
|
9980
|
+
const cart = getMockCartState(cartId);
|
|
9981
|
+
if (!cart) {
|
|
9982
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
9983
|
+
}
|
|
9984
|
+
for (const line of lines) {
|
|
9985
|
+
if (!this.hasVariant(line.merchandiseId, cart.regionId)) {
|
|
9986
|
+
throw new ResourceNotFoundError("variant", line.merchandiseId);
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9989
|
+
const updates = new Map(lines.map((line) => [line.id, line]));
|
|
9990
|
+
const nextLines = cart.lines.map((line) => {
|
|
9991
|
+
const update = updates.get(line.id);
|
|
9992
|
+
if (!update) {
|
|
9993
|
+
return line;
|
|
9994
|
+
}
|
|
9995
|
+
return {
|
|
9996
|
+
...line,
|
|
9997
|
+
merchandiseId: update.merchandiseId,
|
|
9998
|
+
quantity: update.quantity
|
|
9999
|
+
};
|
|
10000
|
+
}).filter((line) => line.quantity > 0);
|
|
10001
|
+
const saved = saveMockCartState({ ...cart, lines: nextLines });
|
|
10002
|
+
return buildMockCart(saved, this.currencyCode, this.siteUrl);
|
|
10003
|
+
}
|
|
10004
|
+
async getRegions() {
|
|
10005
|
+
return getMockRegions();
|
|
10006
|
+
}
|
|
10007
|
+
async completeCheckout(cartId) {
|
|
10008
|
+
const cart = getMockCartState(cartId);
|
|
10009
|
+
if (!cart) {
|
|
10010
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
10011
|
+
}
|
|
10012
|
+
const order = completeMockCheckout(cart, this.currencyCode, this.siteUrl);
|
|
10013
|
+
return order;
|
|
10014
|
+
}
|
|
10015
|
+
async getShippingMethods(cartId) {
|
|
10016
|
+
const cart = getMockCartState(cartId);
|
|
10017
|
+
return getMockShippingMethods(cart?.regionId);
|
|
10018
|
+
}
|
|
10019
|
+
async getRegionCountries(regionId) {
|
|
10020
|
+
return getMockRegionCountries(regionId);
|
|
10021
|
+
}
|
|
10022
|
+
async addShippingMethod(cartId, methodId) {
|
|
10023
|
+
const cart = getMockCartState(cartId);
|
|
10024
|
+
if (!cart) {
|
|
10025
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
10026
|
+
}
|
|
10027
|
+
const allowed = getMockShippingMethods(cart.regionId).some((method) => method.id === methodId);
|
|
10028
|
+
if (!allowed) {
|
|
10029
|
+
throw new ProviderAPIError(`Unknown mock shipping method: ${methodId}`, "mock", 400);
|
|
10030
|
+
}
|
|
10031
|
+
const saved = saveMockCartState({ ...cart, shippingMethodId: methodId });
|
|
10032
|
+
return buildMockCart(saved, this.currencyCode, this.siteUrl);
|
|
10033
|
+
}
|
|
10034
|
+
async initiatePaymentSession(cartId, providerId) {
|
|
10035
|
+
const cart = getMockCartState(cartId);
|
|
10036
|
+
if (!cart) {
|
|
10037
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
10038
|
+
}
|
|
10039
|
+
const allowed = getMockPaymentMethods(this.currencyCode).some((method) => method.id === providerId);
|
|
10040
|
+
if (!allowed) {
|
|
10041
|
+
throw new ProviderAPIError(`Unknown mock payment method: ${providerId}`, "mock", 400);
|
|
10042
|
+
}
|
|
10043
|
+
saveMockCartState({ ...cart, paymentProviderId: providerId });
|
|
10044
|
+
}
|
|
10045
|
+
async applyDiscountCode(cartId, code) {
|
|
10046
|
+
const cart = getMockCartState(cartId);
|
|
10047
|
+
if (!cart) {
|
|
10048
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
10049
|
+
}
|
|
10050
|
+
const normalized = code.trim();
|
|
10051
|
+
if (!normalized) {
|
|
10052
|
+
throw new ProviderAPIError("Discount code is required.", "mock", 400);
|
|
10053
|
+
}
|
|
10054
|
+
const saved = saveMockCartState({ ...cart, discountCode: normalized });
|
|
10055
|
+
return buildMockCart(saved, this.currencyCode, this.siteUrl);
|
|
10056
|
+
}
|
|
10057
|
+
async removeDiscountCode(cartId, _code) {
|
|
10058
|
+
const cart = getMockCartState(cartId);
|
|
10059
|
+
if (!cart) {
|
|
10060
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
10061
|
+
}
|
|
10062
|
+
const saved = saveMockCartState({ ...cart, discountCode: void 0 });
|
|
10063
|
+
return buildMockCart(saved, this.currencyCode, this.siteUrl);
|
|
10064
|
+
}
|
|
10065
|
+
async getOrders(_options) {
|
|
10066
|
+
return getMockAdminOrders().orders;
|
|
10067
|
+
}
|
|
10068
|
+
async getPaymentMethods(options) {
|
|
10069
|
+
return getMockPaymentMethods(options.currencyCode ?? this.currencyCode);
|
|
10070
|
+
}
|
|
10071
|
+
async getStockLocations() {
|
|
10072
|
+
return getMockStockLocations();
|
|
10073
|
+
}
|
|
10074
|
+
async checkInventoryLevels(variantId) {
|
|
10075
|
+
return getMockInventoryLevels(variantId);
|
|
10076
|
+
}
|
|
10077
|
+
async validateCartStock(cartId) {
|
|
10078
|
+
const cart = getMockCartState(cartId);
|
|
10079
|
+
if (!cart) {
|
|
10080
|
+
throw new ResourceNotFoundError("cart", cartId);
|
|
10081
|
+
}
|
|
10082
|
+
return validateMockCartStock(cart);
|
|
10083
|
+
}
|
|
10084
|
+
async getFulfillmentOptions(cartId, _salesChannelId) {
|
|
10085
|
+
const cart = getMockCartState(cartId);
|
|
10086
|
+
return getMockFulfillmentOptions(cart?.regionId);
|
|
10087
|
+
}
|
|
10088
|
+
async cancelOrder(orderId) {
|
|
10089
|
+
const order = getMockOrder(orderId);
|
|
10090
|
+
if (!order) {
|
|
10091
|
+
throw new ResourceNotFoundError("order", orderId);
|
|
10092
|
+
}
|
|
10093
|
+
return saveMockOrder({
|
|
10094
|
+
...order,
|
|
10095
|
+
status: "cancelled",
|
|
10096
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10097
|
+
cancelledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10098
|
+
});
|
|
10099
|
+
}
|
|
10100
|
+
async createFulfillment(_orderId, _items) {
|
|
10101
|
+
return;
|
|
10102
|
+
}
|
|
10103
|
+
async createRefund(orderId, _amount, _reason) {
|
|
10104
|
+
const order = getMockOrder(orderId);
|
|
10105
|
+
if (!order) {
|
|
10106
|
+
throw new ResourceNotFoundError("order", orderId);
|
|
10107
|
+
}
|
|
10108
|
+
saveMockOrder({
|
|
10109
|
+
...order,
|
|
10110
|
+
status: "refunded",
|
|
10111
|
+
paymentStatus: "refunded",
|
|
10112
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10113
|
+
});
|
|
10114
|
+
}
|
|
10115
|
+
async getAdminOrders() {
|
|
10116
|
+
return getMockAdminOrders();
|
|
10117
|
+
}
|
|
10118
|
+
async getAdminRegions() {
|
|
10119
|
+
return getMockAdminRegions();
|
|
10120
|
+
}
|
|
10121
|
+
async getStorefrontContext() {
|
|
10122
|
+
return {
|
|
10123
|
+
id: "mock-storefront",
|
|
10124
|
+
name: "Mock Storefront",
|
|
10125
|
+
platformType: "mock",
|
|
10126
|
+
requiresProductScoping: false,
|
|
10127
|
+
currencyCode: this.currencyCode,
|
|
10128
|
+
locale: "en-US",
|
|
10129
|
+
metadata: {
|
|
10130
|
+
mode: "design"
|
|
10131
|
+
}
|
|
10132
|
+
};
|
|
10133
|
+
}
|
|
10134
|
+
isStorefrontRequired() {
|
|
10135
|
+
return false;
|
|
10136
|
+
}
|
|
10137
|
+
};
|
|
10138
|
+
|
|
8045
10139
|
// src/factory/index.ts
|
|
8046
10140
|
function createProvider(options) {
|
|
8047
10141
|
if (!options || !options.provider) {
|
|
@@ -8052,8 +10146,12 @@ function createProvider(options) {
|
|
|
8052
10146
|
}
|
|
8053
10147
|
const config = options.config;
|
|
8054
10148
|
switch (options.provider) {
|
|
10149
|
+
case "mock":
|
|
10150
|
+
return new MockProvider(config);
|
|
8055
10151
|
case "medusa":
|
|
8056
10152
|
return new MedusaProvider(config);
|
|
10153
|
+
case "stelorder":
|
|
10154
|
+
return new StelOrderProvider(config);
|
|
8057
10155
|
case "shopify":
|
|
8058
10156
|
return new ShopifyProvider(config);
|
|
8059
10157
|
case "bigcommerce":
|
|
@@ -8087,17 +10185,21 @@ function isProviderType(provider, type) {
|
|
|
8087
10185
|
ConfigurationError,
|
|
8088
10186
|
MAGENTO_CAPABILITIES,
|
|
8089
10187
|
MEDUSA_CAPABILITIES,
|
|
10188
|
+
MOCK_CAPABILITIES,
|
|
8090
10189
|
MagentoProvider,
|
|
8091
10190
|
MedusaMetadataAdapter,
|
|
8092
10191
|
MedusaProvider,
|
|
8093
10192
|
MetricsService,
|
|
10193
|
+
MockProvider,
|
|
8094
10194
|
ProviderAPIError,
|
|
8095
10195
|
ProviderNotFoundError,
|
|
8096
10196
|
ResourceNotFoundError,
|
|
8097
10197
|
SHOPIFY_CAPABILITIES,
|
|
8098
10198
|
SPREE_CAPABILITIES,
|
|
10199
|
+
STELORDER_CAPABILITIES,
|
|
8099
10200
|
ShopifyProvider,
|
|
8100
10201
|
SpreeProvider,
|
|
10202
|
+
StelOrderProvider,
|
|
8101
10203
|
StorefrontConfigError,
|
|
8102
10204
|
WOOCOMMERCE_CAPABILITIES,
|
|
8103
10205
|
WooCommerceProvider,
|