@factorypure/client-helpers 1.1.27 → 1.1.29
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/dist/index.d.ts +3 -0
- package/dist/index.js +75 -38
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -385,6 +385,7 @@ export declare const scrapeResultsSchema: z.ZodObject<{
|
|
|
385
385
|
parsed_results: z.ZodOptional<z.ZodNull>;
|
|
386
386
|
lowest_price: z.ZodOptional<z.ZodNull>;
|
|
387
387
|
highest_price: z.ZodOptional<z.ZodNull>;
|
|
388
|
+
listing_hash: z.ZodOptional<z.ZodNull>;
|
|
388
389
|
latest_source_count: z.ZodOptional<z.ZodNull>;
|
|
389
390
|
largest_source_count: z.ZodOptional<z.ZodNull>;
|
|
390
391
|
is_immersive: z.ZodOptional<z.ZodNull>;
|
|
@@ -575,6 +576,8 @@ export declare const variantScrapeOptionsSchema: z.ZodObject<{
|
|
|
575
576
|
key_parts: z.ZodString;
|
|
576
577
|
}, z.core.$strip>>>;
|
|
577
578
|
day_window: z.ZodNullable<z.ZodString>;
|
|
579
|
+
latest_margin_email_sent_at: z.ZodNullable<z.ZodString>;
|
|
580
|
+
latest_map_email_sent_at: z.ZodNullable<z.ZodString>;
|
|
578
581
|
}, z.core.$strip>;
|
|
579
582
|
export type VariantScrapeOptionsType = z.infer<typeof variantScrapeOptionsSchema>;
|
|
580
583
|
declare const matchConfirmationSchema: z.ZodObject<{
|
package/dist/index.js
CHANGED
|
@@ -279,6 +279,7 @@ export const scrapeResultsSchema = z.object({
|
|
|
279
279
|
parsed_results: z.null().optional(),
|
|
280
280
|
lowest_price: z.null().optional(),
|
|
281
281
|
highest_price: z.null().optional(),
|
|
282
|
+
listing_hash: z.null().optional(),
|
|
282
283
|
latest_source_count: z.null().optional(),
|
|
283
284
|
largest_source_count: z.null().optional(),
|
|
284
285
|
is_immersive: z.null().optional(),
|
|
@@ -380,6 +381,8 @@ export const variantScrapeOptionsSchema = z.object({
|
|
|
380
381
|
found_product_ids: z.array(z.string()),
|
|
381
382
|
result_ignore_keys: z.array(ResultIgnoreSchema).nullable(),
|
|
382
383
|
day_window: z.string().nullable(),
|
|
384
|
+
latest_margin_email_sent_at: z.string().nullable(),
|
|
385
|
+
latest_map_email_sent_at: z.string().nullable(),
|
|
383
386
|
});
|
|
384
387
|
const matchConfirmationSchema = z.object({
|
|
385
388
|
confirmation_source: z.string(),
|
|
@@ -905,6 +908,7 @@ class SearchExclusionRule {
|
|
|
905
908
|
return null;
|
|
906
909
|
}
|
|
907
910
|
}
|
|
911
|
+
const skipSkuRegexCache = new Map();
|
|
908
912
|
/**
|
|
909
913
|
* Rule for SKU skip filtering
|
|
910
914
|
*/
|
|
@@ -918,28 +922,32 @@ class SkipSkuRule {
|
|
|
918
922
|
canBeOverridden = true;
|
|
919
923
|
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
920
924
|
evaluate(context) {
|
|
921
|
-
const
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
.
|
|
925
|
-
|
|
926
|
-
nots.
|
|
927
|
-
|
|
925
|
+
const variantSkuLower = context.variant.sku.toLowerCase();
|
|
926
|
+
const allSkus = [
|
|
927
|
+
...context.vendorScrapeOptions.default_skip_skus,
|
|
928
|
+
...context.vendorScrapeOptions.vendor_skip_skus,
|
|
929
|
+
];
|
|
930
|
+
const nots = allSkus.filter((s) => s.toLowerCase() !== variantSkuLower);
|
|
931
|
+
if (nots.length === 0)
|
|
932
|
+
return null;
|
|
928
933
|
const skuAlternates = context.variantScrapeOptions.sku_alternates || [];
|
|
929
|
-
const
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
}
|
|
934
|
+
const cacheKey = variantSkuLower + '\x00' + nots.join('\x00') + '\x01' + skuAlternates.join('\x00');
|
|
935
|
+
let cached = skipSkuRegexCache.get(cacheKey);
|
|
936
|
+
if (!cached) {
|
|
937
|
+
const alternatesSet = new Set(skuAlternates.map((a) => a.toLowerCase()));
|
|
938
|
+
// Only build regex for SKUs that are not alternates (alternates can never be exclusions)
|
|
939
|
+
const nonAlternateNots = nots.filter((s) => !alternatesSet.has(s.toLowerCase()));
|
|
940
|
+
const regex = nonAlternateNots.length > 0
|
|
941
|
+
? new RegExp(`(?: |\/|\&|\=|"|'|\`)(?:${nonAlternateNots
|
|
942
|
+
.map((s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'))
|
|
943
|
+
.join('|')})(?: |\/|\&|\=|"|'|\`)`, 'i')
|
|
944
|
+
: null;
|
|
945
|
+
cached = { regex: regex, alternatesSet };
|
|
946
|
+
skipSkuRegexCache.set(cacheKey, cached);
|
|
947
|
+
}
|
|
948
|
+
if (!cached.regex)
|
|
949
|
+
return null;
|
|
950
|
+
const hasExclusion = cached.regex.test(context.result.title ?? '');
|
|
943
951
|
if (hasExclusion) {
|
|
944
952
|
return {
|
|
945
953
|
ruleId: this.id,
|
|
@@ -952,6 +960,7 @@ class SkipSkuRule {
|
|
|
952
960
|
return null;
|
|
953
961
|
}
|
|
954
962
|
}
|
|
963
|
+
const vendorExclusionRegexCache = new Map();
|
|
955
964
|
/**
|
|
956
965
|
* Rule for vendor exclusions
|
|
957
966
|
*/
|
|
@@ -964,18 +973,42 @@ class VendorExclusionRule {
|
|
|
964
973
|
enabled = true;
|
|
965
974
|
canBeOverridden = true;
|
|
966
975
|
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
976
|
+
// evaluate(context: FilterContext): FilterResult | null {
|
|
977
|
+
// const nots: string[] = []
|
|
978
|
+
// const formatted = context.vendorScrapeOptions.default_skip_vendors
|
|
979
|
+
// .filter((s) => s.toLowerCase() !== context.variant.vendor.toLowerCase())
|
|
980
|
+
// .map((s) => `${s}`)
|
|
981
|
+
// nots.push(...formatted)
|
|
982
|
+
// const hasExclusion = nots.some((vendor) => {
|
|
983
|
+
// const escaped = vendor.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
984
|
+
// const matchRegex = new RegExp(`(?: |\/|\&|\=|"|'|\`)${escaped}(?: |\/|\&|\=|"|'|\`)`, 'gi')
|
|
985
|
+
// const matches = context.result.title?.match(matchRegex)
|
|
986
|
+
// return matches && matches.length > 0
|
|
987
|
+
// })
|
|
988
|
+
// if (hasExclusion) {
|
|
989
|
+
// return {
|
|
990
|
+
// ruleId: this.id,
|
|
991
|
+
// severity: this.severity,
|
|
992
|
+
// message: HIDE_REASONS.VENDOR_EXCLUSION,
|
|
993
|
+
// metadata: { title: context.result.title },
|
|
994
|
+
// timestamp: new Date().toISOString(),
|
|
995
|
+
// }
|
|
996
|
+
// }
|
|
997
|
+
// return null
|
|
998
|
+
// }
|
|
967
999
|
evaluate(context) {
|
|
968
|
-
const
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
}
|
|
1000
|
+
const variantVendorLower = context.variant.vendor.toLowerCase();
|
|
1001
|
+
const vendors = context.vendorScrapeOptions.default_skip_vendors.filter((s) => s.toLowerCase() !== variantVendorLower);
|
|
1002
|
+
if (vendors.length === 0)
|
|
1003
|
+
return null;
|
|
1004
|
+
const cacheKey = variantVendorLower + '\x00' + vendors.join('\x00');
|
|
1005
|
+
let matchRegex = vendorExclusionRegexCache.get(cacheKey);
|
|
1006
|
+
if (!matchRegex) {
|
|
1007
|
+
const combinedPattern = vendors.map((s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|');
|
|
1008
|
+
matchRegex = new RegExp(`(?: |\/|\&|\=|"|'|\`)(?:${combinedPattern})(?: |\/|\&|\=|"|'|\`)`, 'i');
|
|
1009
|
+
vendorExclusionRegexCache.set(cacheKey, matchRegex);
|
|
1010
|
+
}
|
|
1011
|
+
const hasExclusion = matchRegex.test(context.result.title ?? '');
|
|
979
1012
|
if (hasExclusion) {
|
|
980
1013
|
return {
|
|
981
1014
|
ruleId: this.id,
|
|
@@ -1252,8 +1285,9 @@ class RefurbishedUsedRule {
|
|
|
1252
1285
|
evaluate(context) {
|
|
1253
1286
|
const refurbishedKeywords = getRefurbishedKeywords(context.variant);
|
|
1254
1287
|
const normalizedTitle = context.result.title?.toLowerCase().replace(/[^a-z0-9-]/g, ' ') ?? '';
|
|
1288
|
+
const titleWords = normalizedTitle.split(/\s+/);
|
|
1255
1289
|
const details = context.result.details_and_offers;
|
|
1256
|
-
const isRefurbished = refurbishedKeywords.some((keyword) =>
|
|
1290
|
+
const isRefurbished = refurbishedKeywords.some((keyword) => titleWords.includes(keyword)) ||
|
|
1257
1291
|
(details && details.includes('Pre-owned'));
|
|
1258
1292
|
if (isRefurbished) {
|
|
1259
1293
|
return {
|
|
@@ -1621,6 +1655,9 @@ export function createCustomFilterRule(config) {
|
|
|
1621
1655
|
* This provides more flexibility and better extensibility than the legacy filterScrapeResults
|
|
1622
1656
|
*/
|
|
1623
1657
|
export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, matchConfirmationMap, }) => {
|
|
1658
|
+
if (scrapeResults.length === 0 || !scrapeResults) {
|
|
1659
|
+
return [];
|
|
1660
|
+
}
|
|
1624
1661
|
const registry = createDefaultFilterRegistry();
|
|
1625
1662
|
// Register custom rules if provided
|
|
1626
1663
|
if (customRules) {
|
|
@@ -1644,8 +1681,10 @@ export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOpt
|
|
|
1644
1681
|
function handleDuplicatesV2(results) {
|
|
1645
1682
|
const filteredUniqueResultsMap = {};
|
|
1646
1683
|
results.forEach((item) => {
|
|
1647
|
-
// @ts-ignore
|
|
1648
1684
|
const key = item.listing_hash;
|
|
1685
|
+
if (!key) {
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1649
1688
|
if (!filteredUniqueResultsMap[key]) {
|
|
1650
1689
|
filteredUniqueResultsMap[key] = item;
|
|
1651
1690
|
}
|
|
@@ -2019,11 +2058,9 @@ export const getRefurbishedKeywords = (variant) => {
|
|
|
2019
2058
|
];
|
|
2020
2059
|
if (variant?.sku) {
|
|
2021
2060
|
const skuBasedKeywords = [
|
|
2061
|
+
`${variant.sku.toLowerCase()}-r`,
|
|
2062
|
+
`${variant.sku.toUpperCase()}-R`,
|
|
2022
2063
|
`${variant.sku}-R`,
|
|
2023
|
-
`${variant.sku}-R`.toLowerCase(),
|
|
2024
|
-
`${variant.sku}-R`.toUpperCase(),
|
|
2025
|
-
`${variant.sku?.toLowerCase()}-R`,
|
|
2026
|
-
`${variant.sku?.toUpperCase()}-R`,
|
|
2027
2064
|
];
|
|
2028
2065
|
refurbishedKeywords.push(...skuBasedKeywords);
|
|
2029
2066
|
}
|