@misiki/gocommerce-connector 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/{index-72kQMxjZ.d.cts → index-mqcHZ96i.d.cts} +126 -164
- package/dist/{index-72kQMxjZ.d.ts → index-mqcHZ96i.d.ts} +126 -164
- package/dist/index.cjs +123 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +123 -14
- package/dist/index.js.map +1 -1
- package/dist/services/index.cjs +123 -13
- package/dist/services/index.cjs.map +1 -1
- package/dist/services/index.d.cts +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +123 -14
- package/dist/services/index.js.map +1 -1
- package/package.json +1 -1
package/dist/services/index.cjs
CHANGED
|
@@ -1067,11 +1067,14 @@ var StoreFacts = class extends BaseService {
|
|
|
1067
1067
|
|
|
1068
1068
|
// src/services/catalog.ts
|
|
1069
1069
|
var PAGE_SIZE = 24;
|
|
1070
|
-
function
|
|
1071
|
-
if (!sort) return void 0;
|
|
1070
|
+
function sortParts(sort) {
|
|
1072
1071
|
const s = sort.trim();
|
|
1073
1072
|
const [field, dir] = s.startsWith("-") ? [s.slice(1), "desc"] : s.includes(":") ? s.split(":") : [s, "asc"];
|
|
1074
|
-
|
|
1073
|
+
return [field, dir === "desc" ? "desc" : "asc"];
|
|
1074
|
+
}
|
|
1075
|
+
function indexSort(sort) {
|
|
1076
|
+
if (!sort) return void 0;
|
|
1077
|
+
const [field, d] = sortParts(sort);
|
|
1075
1078
|
switch (field) {
|
|
1076
1079
|
case "price":
|
|
1077
1080
|
return `price_minor:${d}`;
|
|
@@ -1087,6 +1090,20 @@ function indexSort(sort) {
|
|
|
1087
1090
|
return void 0;
|
|
1088
1091
|
}
|
|
1089
1092
|
}
|
|
1093
|
+
function engineSort(sort) {
|
|
1094
|
+
if (!sort || NATURAL.has(sort)) return {};
|
|
1095
|
+
const [field, order] = sortParts(sort);
|
|
1096
|
+
const key = {
|
|
1097
|
+
price: "price",
|
|
1098
|
+
createdAt: "created_at",
|
|
1099
|
+
created_at: "created_at",
|
|
1100
|
+
updatedAt: "updated_at",
|
|
1101
|
+
updated_at: "updated_at",
|
|
1102
|
+
title: "title",
|
|
1103
|
+
name: "title"
|
|
1104
|
+
}[field];
|
|
1105
|
+
return key ? { sort: key, order } : {};
|
|
1106
|
+
}
|
|
1090
1107
|
var NATURAL = /* @__PURE__ */ new Set([
|
|
1091
1108
|
"-createdAt",
|
|
1092
1109
|
"createdAt:desc",
|
|
@@ -1096,6 +1113,7 @@ var NATURAL = /* @__PURE__ */ new Set([
|
|
|
1096
1113
|
"popularity:desc"
|
|
1097
1114
|
]);
|
|
1098
1115
|
var quote = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1116
|
+
var legacyListing = /* @__PURE__ */ new Set();
|
|
1099
1117
|
var CatalogService = class extends BaseService {
|
|
1100
1118
|
facts = new StoreFacts(this._fetch);
|
|
1101
1119
|
async queryCatalog(q) {
|
|
@@ -1105,6 +1123,39 @@ var CatalogService = class extends BaseService {
|
|
|
1105
1123
|
const wantsRange = Number.isFinite(q.priceFrom) || Number.isFinite(q.priceTo);
|
|
1106
1124
|
const sortKey = q.sort && !NATURAL.has(q.sort) ? indexSort(q.sort) : void 0;
|
|
1107
1125
|
const hierarchy = q.category ? await this.facts.hierarchy(q.category) : [];
|
|
1126
|
+
const attr = Object.entries(q.attributes ?? {}).flatMap(
|
|
1127
|
+
([handle, values]) => values.filter(Boolean).map((v) => `${handle}:${v}`)
|
|
1128
|
+
);
|
|
1129
|
+
if (q.facets && !legacyListing.has(this.engineBase())) {
|
|
1130
|
+
const { currency } = await this.facts.ready();
|
|
1131
|
+
const minor = (n) => Number.isFinite(n) ? Math.max(0, toMinor(n, currency)) : void 0;
|
|
1132
|
+
const env2 = await this.engine("/api/products", {
|
|
1133
|
+
query: {
|
|
1134
|
+
q: search,
|
|
1135
|
+
page,
|
|
1136
|
+
limit,
|
|
1137
|
+
channel: this.creds.channel,
|
|
1138
|
+
category: q.category,
|
|
1139
|
+
tag: q.tags,
|
|
1140
|
+
vendor: q.vendors,
|
|
1141
|
+
product_type: q.productTypes,
|
|
1142
|
+
attr,
|
|
1143
|
+
price_min: minor(q.priceFrom),
|
|
1144
|
+
price_max: minor(q.priceTo),
|
|
1145
|
+
...engineSort(q.sort),
|
|
1146
|
+
facets: 1
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
if (env2.meta?.facets) {
|
|
1150
|
+
return {
|
|
1151
|
+
...toPage(env2, (p) => toProduct(p)),
|
|
1152
|
+
categoryHierarchy: hierarchy,
|
|
1153
|
+
sorted: true,
|
|
1154
|
+
facets: env2.meta.facets
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
legacyListing.add(this.engineBase());
|
|
1158
|
+
}
|
|
1108
1159
|
if ((sortKey || wantsRange) && await this.facts.pluginOn("meilisearch")) {
|
|
1109
1160
|
const filters = [];
|
|
1110
1161
|
if (q.category) {
|
|
@@ -1152,9 +1203,6 @@ var CatalogService = class extends BaseService {
|
|
|
1152
1203
|
sorted
|
|
1153
1204
|
};
|
|
1154
1205
|
}
|
|
1155
|
-
const attr = Object.entries(q.attributes ?? {}).flatMap(
|
|
1156
|
-
([handle, values]) => values.filter(Boolean).map((v) => `${handle}:${v}`)
|
|
1157
|
-
);
|
|
1158
1206
|
const env = await this.engine("/api/products", {
|
|
1159
1207
|
query: { q: search, page, limit, channel: this.creds.channel, attr }
|
|
1160
1208
|
});
|
|
@@ -1222,17 +1270,46 @@ var ProductService = class extends CatalogService {
|
|
|
1222
1270
|
async listTrendingProducts({ page = 1, limit } = {}) {
|
|
1223
1271
|
return this.shelf("trending", { page, limit });
|
|
1224
1272
|
}
|
|
1225
|
-
/**
|
|
1273
|
+
/**
|
|
1274
|
+
* More like this product. Given `product` (a slug or id), it is the
|
|
1275
|
+
* product's category first, then its collections, then the newest — never
|
|
1276
|
+
* the product itself. Many shops never fill in categories, and an empty
|
|
1277
|
+
* rail under every product page reads as a broken shop.
|
|
1278
|
+
*
|
|
1279
|
+
* Without `product`, it is the old answer: more from `categoryId`.
|
|
1280
|
+
*/
|
|
1226
1281
|
async listRelatedProducts({
|
|
1227
1282
|
page = 1,
|
|
1228
1283
|
categoryId,
|
|
1284
|
+
product,
|
|
1229
1285
|
limit
|
|
1230
1286
|
} = {}) {
|
|
1287
|
+
if (product) return this.relatedTo(String(product), limit);
|
|
1231
1288
|
if (!categoryId) return this.list({ page, limit });
|
|
1232
1289
|
const category = (await this.facts.categories()).find((c) => String(c.id) === String(categoryId));
|
|
1233
1290
|
if (!category) return this.list({ page, limit });
|
|
1234
1291
|
return this.list({ page, limit, categories: category.slug });
|
|
1235
1292
|
}
|
|
1293
|
+
async relatedTo(slug, limit) {
|
|
1294
|
+
const size = Math.min(100, Math.max(1, Number(limit) || PAGE_SIZE));
|
|
1295
|
+
const p = await this.findProduct(slug);
|
|
1296
|
+
const self = String(p.id);
|
|
1297
|
+
const picked = /* @__PURE__ */ new Map();
|
|
1298
|
+
const add = (rows) => {
|
|
1299
|
+
for (const r of rows) {
|
|
1300
|
+
if (picked.size >= size) return;
|
|
1301
|
+
if (r.id !== self && !picked.has(r.id)) picked.set(r.id, r);
|
|
1302
|
+
}
|
|
1303
|
+
};
|
|
1304
|
+
if (p.category) add((await this.list({ limit: size + 1, categories: p.category.slug })).data);
|
|
1305
|
+
for (const c of p.collections ?? []) {
|
|
1306
|
+
if (picked.size >= size) break;
|
|
1307
|
+
add((await this.shelf(c.slug, { page: 1, limit: size + 1 })).data);
|
|
1308
|
+
}
|
|
1309
|
+
if (picked.size < size) add((await this.list({ limit: size + 1 })).data);
|
|
1310
|
+
const data = [...picked.values()];
|
|
1311
|
+
return { data, count: data.length, pageSize: size, noOfPage: 1, page: 1 };
|
|
1312
|
+
}
|
|
1236
1313
|
async shelf(slug, { page, sort, limit }) {
|
|
1237
1314
|
const size = Math.min(100, Math.max(1, Number(limit) || PAGE_SIZE));
|
|
1238
1315
|
try {
|
|
@@ -1291,16 +1368,44 @@ var num = (v) => {
|
|
|
1291
1368
|
const n = Number(v);
|
|
1292
1369
|
return Number.isFinite(n) ? n : void 0;
|
|
1293
1370
|
};
|
|
1371
|
+
function decodeOnce(v) {
|
|
1372
|
+
try {
|
|
1373
|
+
return decodeURIComponent(v);
|
|
1374
|
+
} catch {
|
|
1375
|
+
return v;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
function listParam(p, key) {
|
|
1379
|
+
const out = p.getAll(key).flatMap((v) => decodeOnce(v).split(",")).map((v) => v.trim()).filter(Boolean);
|
|
1380
|
+
return out.length ? out : void 0;
|
|
1381
|
+
}
|
|
1294
1382
|
function attributesFrom(p) {
|
|
1295
1383
|
const out = {};
|
|
1296
|
-
for (const
|
|
1384
|
+
for (const key of new Set(p.keys())) {
|
|
1297
1385
|
if (!key.startsWith("attributes.")) continue;
|
|
1298
1386
|
const handle = key.slice("attributes.".length);
|
|
1299
|
-
const values =
|
|
1300
|
-
if (handle && values
|
|
1387
|
+
const values = listParam(p, key);
|
|
1388
|
+
if (handle && values) out[handle] = values;
|
|
1301
1389
|
}
|
|
1302
1390
|
return Object.keys(out).length ? out : void 0;
|
|
1303
1391
|
}
|
|
1392
|
+
var counts = (values) => Object.fromEntries((values ?? []).map((v) => [v.value, v.count]));
|
|
1393
|
+
function toStorefrontFacets(f) {
|
|
1394
|
+
if (!f) return { priceStat: {}, categories: [], tags: [], allFilters: {} };
|
|
1395
|
+
const allFilters = {};
|
|
1396
|
+
const group = (key, values) => {
|
|
1397
|
+
if (values?.length) allFilters[key] = counts(values);
|
|
1398
|
+
};
|
|
1399
|
+
group("vendor", f.vendors);
|
|
1400
|
+
group("product_type", f.product_types);
|
|
1401
|
+
for (const [handle, values] of Object.entries(f.attributes ?? {})) group(`attributes.${handle}`, values);
|
|
1402
|
+
return {
|
|
1403
|
+
priceStat: f.price ? { min: toMajor(f.price.min), max: toMajor(f.price.max) } : {},
|
|
1404
|
+
categories: (f.categories ?? []).map((c) => ({ name: c.title, slug: c.slug, count: c.count })),
|
|
1405
|
+
tags: (f.tags ?? []).map((t) => ({ name: t.value, count: t.count })),
|
|
1406
|
+
allFilters
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1304
1409
|
var SearchService = class extends CatalogService {
|
|
1305
1410
|
emptyResult() {
|
|
1306
1411
|
return {
|
|
@@ -1308,7 +1413,7 @@ var SearchService = class extends CatalogService {
|
|
|
1308
1413
|
count: 0,
|
|
1309
1414
|
totalPages: 0,
|
|
1310
1415
|
categoryHierarchy: [],
|
|
1311
|
-
facets:
|
|
1416
|
+
facets: toStorefrontFacets()
|
|
1312
1417
|
};
|
|
1313
1418
|
}
|
|
1314
1419
|
async searchWithUrl(url, slug) {
|
|
@@ -1323,7 +1428,11 @@ var SearchService = class extends CatalogService {
|
|
|
1323
1428
|
category: slug || p.get("categories")?.split(",")[0] || void 0,
|
|
1324
1429
|
priceFrom: num(p.get("priceFrom")) ?? num(from ?? null),
|
|
1325
1430
|
priceTo: num(p.get("priceTo")) ?? num(to ?? null),
|
|
1326
|
-
attributes: attributesFrom(p)
|
|
1431
|
+
attributes: attributesFrom(p),
|
|
1432
|
+
tags: listParam(p, "tags"),
|
|
1433
|
+
vendors: listParam(p, "vendor"),
|
|
1434
|
+
productTypes: listParam(p, "product_type"),
|
|
1435
|
+
facets: true
|
|
1327
1436
|
});
|
|
1328
1437
|
return {
|
|
1329
1438
|
data: res.data,
|
|
@@ -1331,7 +1440,7 @@ var SearchService = class extends CatalogService {
|
|
|
1331
1440
|
totalPages: res.noOfPage,
|
|
1332
1441
|
page: res.page,
|
|
1333
1442
|
categoryHierarchy: res.categoryHierarchy,
|
|
1334
|
-
facets:
|
|
1443
|
+
facets: toStorefrontFacets(res.facets)
|
|
1335
1444
|
};
|
|
1336
1445
|
} catch (err) {
|
|
1337
1446
|
if (err?.status === 404) return this.emptyResult();
|
|
@@ -3467,6 +3576,7 @@ exports.staticStore = staticStore;
|
|
|
3467
3576
|
exports.storeForHost = storeForHost;
|
|
3468
3577
|
exports.storeService = storeService;
|
|
3469
3578
|
exports.toPage = toPage;
|
|
3579
|
+
exports.toStorefrontFacets = toStorefrontFacets;
|
|
3470
3580
|
exports.uploadService = uploadService;
|
|
3471
3581
|
exports.userService = userService;
|
|
3472
3582
|
exports.variantService = variantService;
|