@factorypure/client-helpers 1.1.23 → 1.1.25
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 +25 -2
- package/dist/index.js +76 -14
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -520,6 +520,11 @@ export declare const immersiveScrapeResultsSchema: z.ZodObject<{
|
|
|
520
520
|
delivery: z.ZodOptional<z.ZodNull>;
|
|
521
521
|
candidate_result: z.ZodOptional<z.ZodAny>;
|
|
522
522
|
confidence_override_active: z.ZodOptional<z.ZodBoolean>;
|
|
523
|
+
matchConfirmations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
524
|
+
confirmation_source: z.ZodString;
|
|
525
|
+
confirmed_by: z.ZodNumber;
|
|
526
|
+
confirmed_at: z.ZodString;
|
|
527
|
+
}, z.core.$strip>>>;
|
|
523
528
|
}, z.core.$strip>;
|
|
524
529
|
export type ScrapeResultsType = z.infer<typeof scrapeResultsSchema>;
|
|
525
530
|
export type ImmersiveScrapeResultsType = z.infer<typeof immersiveScrapeResultsSchema>;
|
|
@@ -571,6 +576,12 @@ export declare const variantScrapeOptionsSchema: z.ZodObject<{
|
|
|
571
576
|
day_window: z.ZodNullable<z.ZodString>;
|
|
572
577
|
}, z.core.$strip>;
|
|
573
578
|
export type VariantScrapeOptionsType = z.infer<typeof variantScrapeOptionsSchema>;
|
|
579
|
+
declare const matchConfirmationSchema: z.ZodObject<{
|
|
580
|
+
confirmation_source: z.ZodString;
|
|
581
|
+
confirmed_by: z.ZodNumber;
|
|
582
|
+
confirmed_at: z.ZodString;
|
|
583
|
+
}, z.core.$strip>;
|
|
584
|
+
export type MatchConfirmationType = z.infer<typeof matchConfirmationSchema>;
|
|
574
585
|
export declare const vendorScrapeOptionsSchema: z.ZodObject<{
|
|
575
586
|
vendor_skip_skus: z.ZodArray<z.ZodString>;
|
|
576
587
|
default_skip_skus: z.ZodArray<z.ZodString>;
|
|
@@ -597,6 +608,14 @@ export type ComparisonMapType = Record<string, Record<string, {
|
|
|
597
608
|
result_description: string;
|
|
598
609
|
compared_at: string;
|
|
599
610
|
}>>;
|
|
611
|
+
/**
|
|
612
|
+
* Manual match confirmation map, keyed by variant_id → listing_hash
|
|
613
|
+
*/
|
|
614
|
+
export type MatchConfirmationMapType = Record<string, Record<string, {
|
|
615
|
+
confirmation_source: string;
|
|
616
|
+
confirmed_by: number;
|
|
617
|
+
confirmed_at: string;
|
|
618
|
+
}>>;
|
|
600
619
|
/**
|
|
601
620
|
* Context provided to filter rules during evaluation
|
|
602
621
|
*/
|
|
@@ -615,6 +634,7 @@ export type FilterContext<T = ScrapeResultsType | ImmersiveScrapeResultsType> =
|
|
|
615
634
|
vendorScrapeOptions: VendorScrapeOptionsType;
|
|
616
635
|
globalScrapeOptions: GlobalScrapeOptionsType;
|
|
617
636
|
comparisonMap?: ComparisonMapType;
|
|
637
|
+
matchConfirmationMap?: MatchConfirmationMapType;
|
|
618
638
|
};
|
|
619
639
|
/**
|
|
620
640
|
* Base interface for filter rules
|
|
@@ -686,6 +706,7 @@ export declare const HIDE_OVERRIDE_REASONS: {
|
|
|
686
706
|
CALCULATED_SKU_PARTIAL_MATCH: string;
|
|
687
707
|
CALCULATED_ALT_SKU_MATCH: string;
|
|
688
708
|
AI_COMPARISON_MATCH: string;
|
|
709
|
+
MATCH_CONFIRMATION: string;
|
|
689
710
|
};
|
|
690
711
|
export declare const TOO_CHEAP_MULTIPLIER = 0.75;
|
|
691
712
|
export declare const TOO_EXPENSIVE_MULTIPLIER = 1.15;
|
|
@@ -757,7 +778,7 @@ export declare class FilterEngine {
|
|
|
757
778
|
/**
|
|
758
779
|
* Evaluate rules for a batch of results
|
|
759
780
|
*/
|
|
760
|
-
evaluateBatch<T extends ScrapeResultsType | ImmersiveScrapeResultsType>(results: T[], variant: FilterContext<T>['variant'], variantScrapeOptions: VariantScrapeOptionsType, vendorScrapeOptions: VendorScrapeOptionsType, globalScrapeOptions: GlobalScrapeOptionsType, comparisonMap?: ComparisonMapType): T[];
|
|
781
|
+
evaluateBatch<T extends ScrapeResultsType | ImmersiveScrapeResultsType>(results: T[], variant: FilterContext<T>['variant'], variantScrapeOptions: VariantScrapeOptionsType, vendorScrapeOptions: VendorScrapeOptionsType, globalScrapeOptions: GlobalScrapeOptionsType, comparisonMap?: ComparisonMapType, matchConfirmationMap?: MatchConfirmationMapType): T[];
|
|
761
782
|
/**
|
|
762
783
|
* Calculate visibility state based on filter results
|
|
763
784
|
*/
|
|
@@ -804,7 +825,7 @@ export declare function createCustomFilterRule(config: {
|
|
|
804
825
|
* Filter scrape results using the new rule-based engine
|
|
805
826
|
* This provides more flexibility and better extensibility than the legacy filterScrapeResults
|
|
806
827
|
*/
|
|
807
|
-
export declare const filterScrapeResultsV2: <T extends ScrapeResultsType | ImmersiveScrapeResultsType>({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, }: {
|
|
828
|
+
export declare const filterScrapeResultsV2: <T extends ScrapeResultsType | ImmersiveScrapeResultsType>({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, matchConfirmationMap, }: {
|
|
808
829
|
scrapeResults: T[];
|
|
809
830
|
variant: {
|
|
810
831
|
id: number;
|
|
@@ -821,6 +842,7 @@ export declare const filterScrapeResultsV2: <T extends ScrapeResultsType | Immer
|
|
|
821
842
|
filterConfig?: FilterConfiguration;
|
|
822
843
|
customRules?: FilterRule[];
|
|
823
844
|
comparisonMap?: ComparisonMapType;
|
|
845
|
+
matchConfirmationMap?: MatchConfirmationMapType;
|
|
824
846
|
}) => T[];
|
|
825
847
|
export declare const filterScrapeResults: <T extends ScrapeResultsType | ImmersiveScrapeResultsType>({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, }: {
|
|
826
848
|
scrapeResults: T[];
|
|
@@ -856,3 +878,4 @@ export declare const calculateHideOverrideReasons: (result: ScrapeResultsType |
|
|
|
856
878
|
found_product_ids?: string[];
|
|
857
879
|
}, sku_alternates: string[]) => string[];
|
|
858
880
|
export declare function findUnitVariations(data: any): any;
|
|
881
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,10 @@ import { startOfDay, subDays } from 'date-fns';
|
|
|
3
3
|
import { Index } from 'flexsearch';
|
|
4
4
|
import EnglishPreset from 'flexsearch/lang/en';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
// GOTCHA must restart client
|
|
7
|
+
// npm install /Users/kokkoalex/Documents/GitHub/npm-packages/client-helpers
|
|
8
|
+
// npm uninstall @factorypure/client-helpers
|
|
9
|
+
// npm install @factorypure/client-helpers --latest
|
|
6
10
|
/**
|
|
7
11
|
* @packageDocumentation
|
|
8
12
|
* @module @factorypure/client-helpers
|
|
@@ -348,6 +352,13 @@ export const immersiveScrapeResultsSchema = z.object({
|
|
|
348
352
|
// Populated by matching engine helpers
|
|
349
353
|
candidate_result: z.any().optional(),
|
|
350
354
|
confidence_override_active: z.boolean().optional(),
|
|
355
|
+
matchConfirmations: z
|
|
356
|
+
.array(z.object({
|
|
357
|
+
confirmation_source: z.string(),
|
|
358
|
+
confirmed_by: z.number(),
|
|
359
|
+
confirmed_at: z.string(),
|
|
360
|
+
}))
|
|
361
|
+
.optional(),
|
|
351
362
|
});
|
|
352
363
|
export const ResultIgnoreSchema = z.object({
|
|
353
364
|
id: z.number(),
|
|
@@ -370,6 +381,11 @@ export const variantScrapeOptionsSchema = z.object({
|
|
|
370
381
|
result_ignore_keys: z.array(ResultIgnoreSchema).nullable(),
|
|
371
382
|
day_window: z.string().nullable(),
|
|
372
383
|
});
|
|
384
|
+
const matchConfirmationSchema = z.object({
|
|
385
|
+
confirmation_source: z.string(),
|
|
386
|
+
confirmed_by: z.number(),
|
|
387
|
+
confirmed_at: z.string(),
|
|
388
|
+
});
|
|
373
389
|
export const vendorScrapeOptionsSchema = z.object({
|
|
374
390
|
vendor_skip_skus: z.array(z.string()),
|
|
375
391
|
default_skip_skus: z.array(z.string()),
|
|
@@ -428,6 +444,7 @@ export const HIDE_OVERRIDE_REASONS = {
|
|
|
428
444
|
CALCULATED_SKU_PARTIAL_MATCH: 'Calculated SKU Partial Match',
|
|
429
445
|
CALCULATED_ALT_SKU_MATCH: 'Calc. Alt SKU Match',
|
|
430
446
|
AI_COMPARISON_MATCH: 'AI Comparison Match',
|
|
447
|
+
MATCH_CONFIRMATION: 'Match Confirmation',
|
|
431
448
|
};
|
|
432
449
|
const HIDE_ALWAYS_MAP = {
|
|
433
450
|
[HIDE_REASONS.HIGH_PRICE_OUTLIER]: true,
|
|
@@ -591,7 +608,7 @@ export class FilterEngine {
|
|
|
591
608
|
/**
|
|
592
609
|
* Evaluate rules for a batch of results
|
|
593
610
|
*/
|
|
594
|
-
evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap) {
|
|
611
|
+
evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap, matchConfirmationMap) {
|
|
595
612
|
return results.map((result) => {
|
|
596
613
|
const context = {
|
|
597
614
|
result,
|
|
@@ -600,6 +617,7 @@ export class FilterEngine {
|
|
|
600
617
|
vendorScrapeOptions,
|
|
601
618
|
globalScrapeOptions,
|
|
602
619
|
comparisonMap,
|
|
620
|
+
matchConfirmationMap,
|
|
603
621
|
};
|
|
604
622
|
const filterResults = this.evaluateResult(context);
|
|
605
623
|
// Merge with existing filter_results from batch processing (duplicates, search exclusions, etc.)
|
|
@@ -787,7 +805,7 @@ class CompetitorExclusionRule {
|
|
|
787
805
|
priority = 80;
|
|
788
806
|
enabled = true;
|
|
789
807
|
canBeOverridden = true;
|
|
790
|
-
overridableBy = [];
|
|
808
|
+
overridableBy = ['match_confirmation_override'];
|
|
791
809
|
evaluate(context) {
|
|
792
810
|
const lowerSource = context.result.source.toLowerCase();
|
|
793
811
|
const isExcluded = context.variantScrapeOptions.competitor_exclusions.some((exclusion) => exclusion && lowerSource === exclusion.toLowerCase());
|
|
@@ -814,7 +832,7 @@ class AIComparisonMismatchRule {
|
|
|
814
832
|
priority = 85;
|
|
815
833
|
enabled = true;
|
|
816
834
|
canBeOverridden = true;
|
|
817
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
835
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
818
836
|
evaluate(context) {
|
|
819
837
|
// Only applies to results with listing_hash (primarily immersive results)
|
|
820
838
|
const result = context.result;
|
|
@@ -881,7 +899,7 @@ class SearchExclusionRule {
|
|
|
881
899
|
priority = 60;
|
|
882
900
|
enabled = true;
|
|
883
901
|
canBeOverridden = true;
|
|
884
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
902
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
885
903
|
evaluate(context) {
|
|
886
904
|
// This is handled in batch processing due to FlexSearch requirement
|
|
887
905
|
return null;
|
|
@@ -945,7 +963,7 @@ class VendorExclusionRule {
|
|
|
945
963
|
priority = 50;
|
|
946
964
|
enabled = true;
|
|
947
965
|
canBeOverridden = true;
|
|
948
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
966
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
949
967
|
evaluate(context) {
|
|
950
968
|
const nots = [];
|
|
951
969
|
const formatted = context.vendorScrapeOptions.default_skip_vendors
|
|
@@ -1052,7 +1070,7 @@ class BrandMismatchRule {
|
|
|
1052
1070
|
priority = 40;
|
|
1053
1071
|
enabled = true;
|
|
1054
1072
|
canBeOverridden = true;
|
|
1055
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1073
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1056
1074
|
evaluate(context) {
|
|
1057
1075
|
if (!context.result.brand) {
|
|
1058
1076
|
return null;
|
|
@@ -1115,7 +1133,7 @@ class CalculatedSkuMismatchRule {
|
|
|
1115
1133
|
priority = 30;
|
|
1116
1134
|
enabled = true;
|
|
1117
1135
|
canBeOverridden = true;
|
|
1118
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1136
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1119
1137
|
evaluate(context) {
|
|
1120
1138
|
const result = context.result;
|
|
1121
1139
|
if (!result.calculated_sku) {
|
|
@@ -1158,7 +1176,7 @@ class AISkuMismatchRule {
|
|
|
1158
1176
|
priority = 30;
|
|
1159
1177
|
enabled = true;
|
|
1160
1178
|
canBeOverridden = true;
|
|
1161
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1179
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1162
1180
|
evaluate(context) {
|
|
1163
1181
|
const result = context.result;
|
|
1164
1182
|
if (!result.ai_extracted_sku) {
|
|
@@ -1201,7 +1219,7 @@ class CriticalSpecMismatchRule {
|
|
|
1201
1219
|
priority = 35;
|
|
1202
1220
|
enabled = true;
|
|
1203
1221
|
canBeOverridden = true;
|
|
1204
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1222
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1205
1223
|
evaluate(context) {
|
|
1206
1224
|
if (!context.result.regexUnitResults || !context.variant.regexUnitResults) {
|
|
1207
1225
|
return null;
|
|
@@ -1230,7 +1248,7 @@ class RefurbishedUsedRule {
|
|
|
1230
1248
|
priority = 25;
|
|
1231
1249
|
enabled = true;
|
|
1232
1250
|
canBeOverridden = true;
|
|
1233
|
-
overridableBy = [];
|
|
1251
|
+
overridableBy = ['match_confirmation_override'];
|
|
1234
1252
|
evaluate(context) {
|
|
1235
1253
|
const refurbishedKeywords = getRefurbishedKeywords(context.variant);
|
|
1236
1254
|
const normalizedTitle = context.result.title?.toLowerCase().replace(/[^a-z0-9-]/g, ' ') ?? '';
|
|
@@ -1438,6 +1456,49 @@ class ProductIdMatchOverrideRule {
|
|
|
1438
1456
|
// ===============================
|
|
1439
1457
|
// Registry Factory
|
|
1440
1458
|
// ===============================
|
|
1459
|
+
/**
|
|
1460
|
+
* Override rule for manually confirmed matches
|
|
1461
|
+
*/
|
|
1462
|
+
class MatchConfirmationOverrideRule {
|
|
1463
|
+
id = 'match_confirmation_override';
|
|
1464
|
+
name = 'Match Confirmation Override';
|
|
1465
|
+
description = 'Overrides hide reasons when a match has been manually confirmed via matchConfirmationMap';
|
|
1466
|
+
severity = FilterSeverity.INFO;
|
|
1467
|
+
priority = 300;
|
|
1468
|
+
enabled = true;
|
|
1469
|
+
canBeOverridden = false;
|
|
1470
|
+
overridableBy = [];
|
|
1471
|
+
evaluate(context) {
|
|
1472
|
+
if (!context.matchConfirmationMap) {
|
|
1473
|
+
return null;
|
|
1474
|
+
}
|
|
1475
|
+
const result = context.result;
|
|
1476
|
+
if (!result.listing_hash) {
|
|
1477
|
+
return null;
|
|
1478
|
+
}
|
|
1479
|
+
const variantId = String(context.variant.id);
|
|
1480
|
+
const confirmation = context.matchConfirmationMap[variantId]?.[result.listing_hash];
|
|
1481
|
+
if (!confirmation) {
|
|
1482
|
+
return null;
|
|
1483
|
+
}
|
|
1484
|
+
return {
|
|
1485
|
+
ruleId: this.id,
|
|
1486
|
+
severity: this.severity,
|
|
1487
|
+
message: HIDE_OVERRIDE_REASONS.MATCH_CONFIRMATION,
|
|
1488
|
+
metadata: {
|
|
1489
|
+
isOverride: true,
|
|
1490
|
+
listingHash: result.listing_hash,
|
|
1491
|
+
confirmationSource: confirmation.confirmation_source,
|
|
1492
|
+
confirmedBy: confirmation.confirmed_by,
|
|
1493
|
+
confirmedAt: confirmation.confirmed_at,
|
|
1494
|
+
},
|
|
1495
|
+
timestamp: new Date().toISOString(),
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
// ===============================
|
|
1500
|
+
// Registry Factory
|
|
1501
|
+
// ===============================
|
|
1441
1502
|
/**
|
|
1442
1503
|
* Create and populate a registry with all built-in rules
|
|
1443
1504
|
*/
|
|
@@ -1467,6 +1528,7 @@ export function createDefaultFilterRegistry() {
|
|
|
1467
1528
|
registry.registerRule(new CalculatedSkuMatchOverrideRule());
|
|
1468
1529
|
registry.registerRule(new AltSkuMatchOverrideRule());
|
|
1469
1530
|
registry.registerRule(new ProductIdMatchOverrideRule());
|
|
1531
|
+
registry.registerRule(new MatchConfirmationOverrideRule());
|
|
1470
1532
|
return registry;
|
|
1471
1533
|
}
|
|
1472
1534
|
/**
|
|
@@ -1558,7 +1620,7 @@ export function createCustomFilterRule(config) {
|
|
|
1558
1620
|
* Filter scrape results using the new rule-based engine
|
|
1559
1621
|
* This provides more flexibility and better extensibility than the legacy filterScrapeResults
|
|
1560
1622
|
*/
|
|
1561
|
-
export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, }) => {
|
|
1623
|
+
export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, matchConfirmationMap, }) => {
|
|
1562
1624
|
const registry = createDefaultFilterRegistry();
|
|
1563
1625
|
// Register custom rules if provided
|
|
1564
1626
|
if (customRules) {
|
|
@@ -1573,7 +1635,7 @@ export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOpt
|
|
|
1573
1635
|
let results = handleDuplicatesV2(scrapeResults);
|
|
1574
1636
|
results = handleSearchExclusionsV2(results, variantScrapeOptions, variant, registry);
|
|
1575
1637
|
// Evaluate all other rules
|
|
1576
|
-
results = engine.evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap);
|
|
1638
|
+
results = engine.evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap, matchConfirmationMap);
|
|
1577
1639
|
return results;
|
|
1578
1640
|
};
|
|
1579
1641
|
/**
|
|
@@ -1582,8 +1644,8 @@ export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOpt
|
|
|
1582
1644
|
function handleDuplicatesV2(results) {
|
|
1583
1645
|
const filteredUniqueResultsMap = {};
|
|
1584
1646
|
results.forEach((item) => {
|
|
1585
|
-
//
|
|
1586
|
-
const key =
|
|
1647
|
+
// @ts-ignore
|
|
1648
|
+
const key = item.listing_hash;
|
|
1587
1649
|
if (!filteredUniqueResultsMap[key]) {
|
|
1588
1650
|
filteredUniqueResultsMap[key] = item;
|
|
1589
1651
|
}
|