@factorypure/client-helpers 1.1.24 → 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 +73 -12
- 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,7 +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
|
|
6
7
|
// npm install /Users/kokkoalex/Documents/GitHub/npm-packages/client-helpers
|
|
8
|
+
// npm uninstall @factorypure/client-helpers
|
|
9
|
+
// npm install @factorypure/client-helpers --latest
|
|
7
10
|
/**
|
|
8
11
|
* @packageDocumentation
|
|
9
12
|
* @module @factorypure/client-helpers
|
|
@@ -349,6 +352,13 @@ export const immersiveScrapeResultsSchema = z.object({
|
|
|
349
352
|
// Populated by matching engine helpers
|
|
350
353
|
candidate_result: z.any().optional(),
|
|
351
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(),
|
|
352
362
|
});
|
|
353
363
|
export const ResultIgnoreSchema = z.object({
|
|
354
364
|
id: z.number(),
|
|
@@ -371,6 +381,11 @@ export const variantScrapeOptionsSchema = z.object({
|
|
|
371
381
|
result_ignore_keys: z.array(ResultIgnoreSchema).nullable(),
|
|
372
382
|
day_window: z.string().nullable(),
|
|
373
383
|
});
|
|
384
|
+
const matchConfirmationSchema = z.object({
|
|
385
|
+
confirmation_source: z.string(),
|
|
386
|
+
confirmed_by: z.number(),
|
|
387
|
+
confirmed_at: z.string(),
|
|
388
|
+
});
|
|
374
389
|
export const vendorScrapeOptionsSchema = z.object({
|
|
375
390
|
vendor_skip_skus: z.array(z.string()),
|
|
376
391
|
default_skip_skus: z.array(z.string()),
|
|
@@ -429,6 +444,7 @@ export const HIDE_OVERRIDE_REASONS = {
|
|
|
429
444
|
CALCULATED_SKU_PARTIAL_MATCH: 'Calculated SKU Partial Match',
|
|
430
445
|
CALCULATED_ALT_SKU_MATCH: 'Calc. Alt SKU Match',
|
|
431
446
|
AI_COMPARISON_MATCH: 'AI Comparison Match',
|
|
447
|
+
MATCH_CONFIRMATION: 'Match Confirmation',
|
|
432
448
|
};
|
|
433
449
|
const HIDE_ALWAYS_MAP = {
|
|
434
450
|
[HIDE_REASONS.HIGH_PRICE_OUTLIER]: true,
|
|
@@ -592,7 +608,7 @@ export class FilterEngine {
|
|
|
592
608
|
/**
|
|
593
609
|
* Evaluate rules for a batch of results
|
|
594
610
|
*/
|
|
595
|
-
evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap) {
|
|
611
|
+
evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap, matchConfirmationMap) {
|
|
596
612
|
return results.map((result) => {
|
|
597
613
|
const context = {
|
|
598
614
|
result,
|
|
@@ -601,6 +617,7 @@ export class FilterEngine {
|
|
|
601
617
|
vendorScrapeOptions,
|
|
602
618
|
globalScrapeOptions,
|
|
603
619
|
comparisonMap,
|
|
620
|
+
matchConfirmationMap,
|
|
604
621
|
};
|
|
605
622
|
const filterResults = this.evaluateResult(context);
|
|
606
623
|
// Merge with existing filter_results from batch processing (duplicates, search exclusions, etc.)
|
|
@@ -788,7 +805,7 @@ class CompetitorExclusionRule {
|
|
|
788
805
|
priority = 80;
|
|
789
806
|
enabled = true;
|
|
790
807
|
canBeOverridden = true;
|
|
791
|
-
overridableBy = [];
|
|
808
|
+
overridableBy = ['match_confirmation_override'];
|
|
792
809
|
evaluate(context) {
|
|
793
810
|
const lowerSource = context.result.source.toLowerCase();
|
|
794
811
|
const isExcluded = context.variantScrapeOptions.competitor_exclusions.some((exclusion) => exclusion && lowerSource === exclusion.toLowerCase());
|
|
@@ -815,7 +832,7 @@ class AIComparisonMismatchRule {
|
|
|
815
832
|
priority = 85;
|
|
816
833
|
enabled = true;
|
|
817
834
|
canBeOverridden = true;
|
|
818
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
835
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
819
836
|
evaluate(context) {
|
|
820
837
|
// Only applies to results with listing_hash (primarily immersive results)
|
|
821
838
|
const result = context.result;
|
|
@@ -882,7 +899,7 @@ class SearchExclusionRule {
|
|
|
882
899
|
priority = 60;
|
|
883
900
|
enabled = true;
|
|
884
901
|
canBeOverridden = true;
|
|
885
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
902
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
886
903
|
evaluate(context) {
|
|
887
904
|
// This is handled in batch processing due to FlexSearch requirement
|
|
888
905
|
return null;
|
|
@@ -946,7 +963,7 @@ class VendorExclusionRule {
|
|
|
946
963
|
priority = 50;
|
|
947
964
|
enabled = true;
|
|
948
965
|
canBeOverridden = true;
|
|
949
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
966
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
950
967
|
evaluate(context) {
|
|
951
968
|
const nots = [];
|
|
952
969
|
const formatted = context.vendorScrapeOptions.default_skip_vendors
|
|
@@ -1053,7 +1070,7 @@ class BrandMismatchRule {
|
|
|
1053
1070
|
priority = 40;
|
|
1054
1071
|
enabled = true;
|
|
1055
1072
|
canBeOverridden = true;
|
|
1056
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1073
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1057
1074
|
evaluate(context) {
|
|
1058
1075
|
if (!context.result.brand) {
|
|
1059
1076
|
return null;
|
|
@@ -1116,7 +1133,7 @@ class CalculatedSkuMismatchRule {
|
|
|
1116
1133
|
priority = 30;
|
|
1117
1134
|
enabled = true;
|
|
1118
1135
|
canBeOverridden = true;
|
|
1119
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1136
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1120
1137
|
evaluate(context) {
|
|
1121
1138
|
const result = context.result;
|
|
1122
1139
|
if (!result.calculated_sku) {
|
|
@@ -1159,7 +1176,7 @@ class AISkuMismatchRule {
|
|
|
1159
1176
|
priority = 30;
|
|
1160
1177
|
enabled = true;
|
|
1161
1178
|
canBeOverridden = true;
|
|
1162
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1179
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1163
1180
|
evaluate(context) {
|
|
1164
1181
|
const result = context.result;
|
|
1165
1182
|
if (!result.ai_extracted_sku) {
|
|
@@ -1202,7 +1219,7 @@ class CriticalSpecMismatchRule {
|
|
|
1202
1219
|
priority = 35;
|
|
1203
1220
|
enabled = true;
|
|
1204
1221
|
canBeOverridden = true;
|
|
1205
|
-
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match'];
|
|
1222
|
+
overridableBy = ['sku_match', 'calculated_sku_match', 'alt_sku_match', 'match_confirmation_override'];
|
|
1206
1223
|
evaluate(context) {
|
|
1207
1224
|
if (!context.result.regexUnitResults || !context.variant.regexUnitResults) {
|
|
1208
1225
|
return null;
|
|
@@ -1231,7 +1248,7 @@ class RefurbishedUsedRule {
|
|
|
1231
1248
|
priority = 25;
|
|
1232
1249
|
enabled = true;
|
|
1233
1250
|
canBeOverridden = true;
|
|
1234
|
-
overridableBy = [];
|
|
1251
|
+
overridableBy = ['match_confirmation_override'];
|
|
1235
1252
|
evaluate(context) {
|
|
1236
1253
|
const refurbishedKeywords = getRefurbishedKeywords(context.variant);
|
|
1237
1254
|
const normalizedTitle = context.result.title?.toLowerCase().replace(/[^a-z0-9-]/g, ' ') ?? '';
|
|
@@ -1439,6 +1456,49 @@ class ProductIdMatchOverrideRule {
|
|
|
1439
1456
|
// ===============================
|
|
1440
1457
|
// Registry Factory
|
|
1441
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
|
+
// ===============================
|
|
1442
1502
|
/**
|
|
1443
1503
|
* Create and populate a registry with all built-in rules
|
|
1444
1504
|
*/
|
|
@@ -1468,6 +1528,7 @@ export function createDefaultFilterRegistry() {
|
|
|
1468
1528
|
registry.registerRule(new CalculatedSkuMatchOverrideRule());
|
|
1469
1529
|
registry.registerRule(new AltSkuMatchOverrideRule());
|
|
1470
1530
|
registry.registerRule(new ProductIdMatchOverrideRule());
|
|
1531
|
+
registry.registerRule(new MatchConfirmationOverrideRule());
|
|
1471
1532
|
return registry;
|
|
1472
1533
|
}
|
|
1473
1534
|
/**
|
|
@@ -1559,7 +1620,7 @@ export function createCustomFilterRule(config) {
|
|
|
1559
1620
|
* Filter scrape results using the new rule-based engine
|
|
1560
1621
|
* This provides more flexibility and better extensibility than the legacy filterScrapeResults
|
|
1561
1622
|
*/
|
|
1562
|
-
export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, }) => {
|
|
1623
|
+
export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, filterConfig, customRules, comparisonMap, matchConfirmationMap, }) => {
|
|
1563
1624
|
const registry = createDefaultFilterRegistry();
|
|
1564
1625
|
// Register custom rules if provided
|
|
1565
1626
|
if (customRules) {
|
|
@@ -1574,7 +1635,7 @@ export const filterScrapeResultsV2 = ({ scrapeResults, variant, variantScrapeOpt
|
|
|
1574
1635
|
let results = handleDuplicatesV2(scrapeResults);
|
|
1575
1636
|
results = handleSearchExclusionsV2(results, variantScrapeOptions, variant, registry);
|
|
1576
1637
|
// Evaluate all other rules
|
|
1577
|
-
results = engine.evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap);
|
|
1638
|
+
results = engine.evaluateBatch(results, variant, variantScrapeOptions, vendorScrapeOptions, globalScrapeOptions, comparisonMap, matchConfirmationMap);
|
|
1578
1639
|
return results;
|
|
1579
1640
|
};
|
|
1580
1641
|
/**
|