@factorypure/client-helpers 1.0.14 → 1.0.16

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +20 -1
  2. package/dist/index.js +379 -65
  3. package/package.json +25 -25
package/dist/index.d.ts CHANGED
@@ -28,7 +28,25 @@ export type FilterOptionsType = {
28
28
  search_exclusions_enabled?: boolean;
29
29
  exclude_ignored_keys_enabled?: boolean;
30
30
  };
31
- export declare const filterScrapeResults: ({ scrapeResults, variant, filters, filterOptions, }: {
31
+ export declare const HIDE_REASONS: {
32
+ IGNORED: string;
33
+ HIGH_PRICE_OUTLIER: string;
34
+ LOW_PRICE_OUTLIER: string;
35
+ DATE_OUTLIER: string;
36
+ COMPETITOR_EXCLUSION: string;
37
+ DUPLICATE: string;
38
+ SEARCH_EXCLUSION: string;
39
+ CALCULATED_SKU_MISMATCH: string;
40
+ CRITICAL_SPEC_MISMATCH: string;
41
+ MANUALLY_IGNORED: string;
42
+ OUT_OF_STOCK_ONLINE: string;
43
+ REFURBISHED_USED: string;
44
+ SKIP_SKU: string;
45
+ VENDOR_EXCLUSION: string;
46
+ };
47
+ export declare const TOO_CHEAP_MULTIPLIER = 0.75;
48
+ export declare const TOO_EXPENSIVE_MULTIPLIER = 1.25;
49
+ export declare const filterScrapeResults: ({ scrapeResults, variant, filters, filterOptions, globalScrapeOptions, }: {
32
50
  scrapeResults: ScrapeResultsType[];
33
51
  variant: {
34
52
  id: number;
@@ -39,6 +57,7 @@ export declare const filterScrapeResults: ({ scrapeResults, variant, filters, fi
39
57
  };
40
58
  filters: ScrapeFiltersType;
41
59
  filterOptions?: FilterOptionsType;
60
+ globalScrapeOptions?: any;
42
61
  }) => z.infer<any>[];
43
62
  export declare const calculateIgnoreStatus: (result: ScrapeResultsType, variant: {
44
63
  id: number;
package/dist/index.js CHANGED
@@ -37,8 +37,24 @@ export const scrapeResultsSchema = z.object({
37
37
  store_id: z.number(),
38
38
  match_score: z.number().nullable(),
39
39
  });
40
- const TOO_CHEAP_MULTIPLIER = 0.75;
41
- const TOO_EXPENSIVE_MULTIPLIER = 1.25;
40
+ export const HIDE_REASONS = {
41
+ IGNORED: "Ignored",
42
+ HIGH_PRICE_OUTLIER: "Too Expensive",
43
+ LOW_PRICE_OUTLIER: "Too Cheap",
44
+ DATE_OUTLIER: "Outdated Listing",
45
+ COMPETITOR_EXCLUSION: "Source Excluded",
46
+ DUPLICATE: "Duplicate",
47
+ SEARCH_EXCLUSION: "Search Exclusion",
48
+ CALCULATED_SKU_MISMATCH: "Calculated SKU Mismatch",
49
+ CRITICAL_SPEC_MISMATCH: "Critical Spec Mismatch",
50
+ MANUALLY_IGNORED: "Manually ignored",
51
+ OUT_OF_STOCK_ONLINE: "Out of stock online",
52
+ REFURBISHED_USED: "Refurbished/Used",
53
+ SKIP_SKU: "Skipped SKU",
54
+ VENDOR_EXCLUSION: "Vendor Exclusion",
55
+ };
56
+ export const TOO_CHEAP_MULTIPLIER = 0.75;
57
+ export const TOO_EXPENSIVE_MULTIPLIER = 1.25;
42
58
  const wattages = Array.from({ length: 41 }, (_, i) => (5000 + i * 500).toString());
43
59
  export const filterScrapeResults = ({ scrapeResults, variant, filters, filterOptions = {
44
60
  exclude_linked_variants_enabled: true,
@@ -52,32 +68,35 @@ export const filterScrapeResults = ({ scrapeResults, variant, filters, filterOpt
52
68
  wattage_exclusions_enabled: true,
53
69
  search_exclusions_enabled: true,
54
70
  exclude_ignored_keys_enabled: false,
55
- }, }) => {
71
+ }, globalScrapeOptions, }) => {
56
72
  let filteredResults = scrapeResults;
57
- if (filterOptions.exclude_linked_variants_enabled) {
58
- filteredResults = filterLinkedElsewhereResults(filteredResults, variant.id);
59
- }
60
- if (filterOptions.found_id_exclusions_enabled) {
61
- filteredResults = filterFoundProductIdExclusions(filteredResults, filters.found_id_exclusions);
62
- }
63
- if (filterOptions.exclude_ignored_keys_enabled) {
64
- filteredResults = filterIgnoredResults(filteredResults);
65
- }
66
- if (filterOptions.price_filter_enabled) {
67
- filteredResults = filterPriceOutliers(filteredResults, variant.price, filters.showHighPriceOutliers, filters.showLowPriceOutliers);
68
- }
69
- if (filterOptions.date_filter_enabled) {
70
- filteredResults = filterDateWindow(filteredResults, filters.dayWindow);
71
- }
72
- if (filterOptions.competitor_filter_enabled) {
73
- filteredResults = filterCompetitors(filteredResults, filters.competitor_exclusions);
74
- }
75
- if (filterOptions.duplicates_filter_enabled) {
76
- filteredResults = filterDuplicateResults(filteredResults);
77
- }
78
- if (filterOptions.search_index_enabled) {
79
- filteredResults = handleIndexSearch(filteredResults, filters, variant, filterOptions);
80
- }
73
+ // if (filterOptions.exclude_linked_variants_enabled) {
74
+ // filteredResults = filterLinkedElsewhereResults(filteredResults, variant.id)
75
+ // }
76
+ // if (filterOptions.found_id_exclusions_enabled) {
77
+ // filteredResults = filterFoundProductIdExclusions(filteredResults, filters.found_id_exclusions)
78
+ // }
79
+ // if (filterOptions.exclude_ignored_keys_enabled) {
80
+ // filteredResults = filterIgnoredResults(filteredResults)
81
+ // }
82
+ // if (filterOptions.price_filter_enabled) {
83
+ filteredResults = filterPriceOutliers(filteredResults, variant.price, globalScrapeOptions);
84
+ // }
85
+ // if (filterOptions.date_filter_enabled) {
86
+ filteredResults = filterDateWindow(filteredResults, filters.dayWindow);
87
+ // }
88
+ // if (filterOptions.competitor_filter_enabled) {
89
+ filteredResults = filterCompetitors(filteredResults, filters.competitor_exclusions);
90
+ // }
91
+ // if (filterOptions.duplicates_filter_enabled) {
92
+ filteredResults = filterDuplicateResults(filteredResults);
93
+ // }
94
+ // if (filterOptions.search_index_enabled) {
95
+ filteredResults = handleExclusionsSearch(filteredResults, filters, variant, filterOptions);
96
+ filteredResults = handleSkipSkuSearch(filteredResults, filters, variant, filterOptions);
97
+ filteredResults = handleVendorExclusions(filteredResults, filters, variant, filterOptions);
98
+ // filteredResults = handleIndexSearch(filteredResults, filters, variant, filterOptions)
99
+ // }
81
100
  return filteredResults;
82
101
  };
83
102
  const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
@@ -104,6 +123,29 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
104
123
  index.add(id, item.title);
105
124
  });
106
125
  const searchTerms = filters.match_values;
126
+ let final = null;
127
+ searchTerms.forEach((term) => {
128
+ if (final === null) {
129
+ final = index.search(term, {
130
+ resolve: false,
131
+ suggest: true,
132
+ });
133
+ }
134
+ else {
135
+ final = final.or({
136
+ index: index,
137
+ query: term,
138
+ resolve: false,
139
+ suggest: true,
140
+ });
141
+ }
142
+ });
143
+ final = final.and({
144
+ index: index,
145
+ query: sku,
146
+ resolve: false,
147
+ suggest: true,
148
+ });
107
149
  const nots = [];
108
150
  if (filters.skip_skus.length && filterOptions.skip_skus_enabled) {
109
151
  const formatted = filters.skip_skus
@@ -142,10 +184,221 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
142
184
  if (title.toLowerCase().includes("dual fuel")) {
143
185
  // nots.push('tri fuel', 'trifuel', 'tri-fuel')
144
186
  }
187
+ nots.forEach((term) => {
188
+ final = final.not({
189
+ index: index,
190
+ query: term,
191
+ resolve: false,
192
+ });
193
+ });
194
+ const result = final.resolve({ limit: 1000 });
195
+ const resultsArray = [];
196
+ result.forEach((i) => {
197
+ resultsArray.push(dataToSearch[i]);
198
+ });
199
+ for (let index = 0; index < dataToSearch.length; index++) {
200
+ const element = dataToSearch[index];
201
+ if (!result.includes(index)) {
202
+ if (!element.hide_reasons) {
203
+ element.hide_reasons = [];
204
+ }
205
+ element.hide_reasons.push(HIDE_REASONS.SEARCH_EXCLUSION);
206
+ }
207
+ }
208
+ return dataToSearch;
209
+ };
210
+ const handleVendorExclusions = (dataToSearch, filters, variant, filterOptions) => {
211
+ if (!filters.skip_vendors || filters.skip_vendors.length === 0) {
212
+ return dataToSearch;
213
+ }
214
+ const { title, sku } = variant;
215
+ function customEncoder(content) {
216
+ const tokens = [];
217
+ const str = content.toLowerCase();
218
+ // Remove symbols from the string (keep only letters, numbers, commas, and spaces)
219
+ const cleanedStr = str.replace(/[\/-]/g, " ");
220
+ const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, "");
221
+ const words = cleanedStr2.split(/\s+/);
222
+ for (let word of words) {
223
+ tokens.push(word);
224
+ }
225
+ return tokens;
226
+ }
227
+ const index = new Index({
228
+ charset: EnglishPreset,
229
+ // encoder: encoder,
230
+ encode: customEncoder,
231
+ tokenize: "strict",
232
+ });
233
+ dataToSearch.forEach((item, id) => {
234
+ index.add(id, item.title);
235
+ });
236
+ const searchTerms = filters.match_values;
145
237
  let final = null;
146
- let urlFinal = null;
147
238
  searchTerms.forEach((term) => {
148
- if (final === null && urlFinal === null) {
239
+ if (final === null) {
240
+ final = index.search(term, {
241
+ resolve: false,
242
+ suggest: true,
243
+ });
244
+ }
245
+ else {
246
+ final = final.or({
247
+ index: index,
248
+ query: term,
249
+ resolve: false,
250
+ suggest: true,
251
+ });
252
+ }
253
+ });
254
+ final = final.and({
255
+ index: index,
256
+ query: sku,
257
+ resolve: false,
258
+ suggest: true,
259
+ });
260
+ const nots = [];
261
+ if (filters.skip_vendors.length && filterOptions.skip_vendors_enabled) {
262
+ const formatted = filters.skip_vendors
263
+ .filter((vendor) => vendor.toLowerCase() !== variant.vendor.toLowerCase())
264
+ .map((vendor) => ` ${vendor} `);
265
+ nots.push(...formatted);
266
+ }
267
+ nots.forEach((term) => {
268
+ final = final.not({
269
+ index: index,
270
+ query: term,
271
+ resolve: false,
272
+ });
273
+ });
274
+ const result = final.resolve({ limit: 1000 });
275
+ const resultsArray = [];
276
+ result.forEach((i) => {
277
+ resultsArray.push(dataToSearch[i]);
278
+ });
279
+ for (let index = 0; index < dataToSearch.length; index++) {
280
+ const element = dataToSearch[index];
281
+ if (!result.includes(index)) {
282
+ if (!element.hide_reasons) {
283
+ element.hide_reasons = [];
284
+ }
285
+ element.hide_reasons.push(HIDE_REASONS.VENDOR_EXCLUSION);
286
+ }
287
+ }
288
+ return dataToSearch;
289
+ };
290
+ const handleSkipSkuSearch = (dataToSearch, filters, variant, filterOptions) => {
291
+ // if (
292
+ // (!filters.skip_skus || filters.skip_skus.length === 0) &&
293
+ // (!filters.vendor_search_exclusions || filters.vendor_search_exclusions.length === 0)
294
+ // ) {
295
+ // return dataToSearch
296
+ // }
297
+ const { title, sku } = variant;
298
+ function customEncoder(content) {
299
+ const tokens = [];
300
+ const str = content.toLowerCase();
301
+ // Remove symbols from the string (keep only letters, numbers, commas, and spaces)
302
+ const cleanedStr = str.replace(/[\/-]/g, " ");
303
+ const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, "");
304
+ const words = cleanedStr2.split(/\s+/);
305
+ for (let word of words) {
306
+ tokens.push(word);
307
+ }
308
+ return tokens;
309
+ }
310
+ const index = new Index({
311
+ charset: EnglishPreset,
312
+ // encoder: encoder,
313
+ encode: customEncoder,
314
+ tokenize: "strict",
315
+ });
316
+ dataToSearch.forEach((item, id) => {
317
+ index.add(id, item.title);
318
+ });
319
+ const searchTerms = filters.match_values;
320
+ let final = null;
321
+ searchTerms.forEach((term) => {
322
+ if (final === null) {
323
+ final = index.search(term, {
324
+ resolve: false,
325
+ suggest: true,
326
+ });
327
+ }
328
+ else {
329
+ final = final.or({
330
+ index: index,
331
+ query: term,
332
+ resolve: false,
333
+ suggest: true,
334
+ });
335
+ }
336
+ });
337
+ final = final.and({
338
+ index: index,
339
+ query: sku,
340
+ resolve: false,
341
+ suggest: true,
342
+ });
343
+ const nots = [];
344
+ const formatted = filters.skip_skus
345
+ .filter((sku) => sku.toLowerCase() !== variant.sku.toLowerCase())
346
+ .map((sku) => ` ${sku} `);
347
+ nots.push(...formatted);
348
+ nots.push(...filters.vendor_search_exclusions.filter((sku) => sku.toLowerCase() !== variant.sku.toLowerCase()));
349
+ nots.forEach((term) => {
350
+ final = final.not({
351
+ index: index,
352
+ query: term,
353
+ resolve: false,
354
+ });
355
+ });
356
+ const result = final.resolve({ limit: 1000 });
357
+ const resultsArray = [];
358
+ result.forEach((i) => {
359
+ resultsArray.push(dataToSearch[i]);
360
+ });
361
+ for (let index = 0; index < dataToSearch.length; index++) {
362
+ const element = dataToSearch[index];
363
+ if (!result.includes(index)) {
364
+ if (!element.hide_reasons) {
365
+ element.hide_reasons = [];
366
+ }
367
+ element.hide_reasons.push(HIDE_REASONS.SKIP_SKU);
368
+ }
369
+ }
370
+ return dataToSearch;
371
+ };
372
+ const handleExclusionsSearch = (dataToSearch, filters, variant, filterOptions) => {
373
+ if (!filters.search_exclusions || filters.search_exclusions.length === 0) {
374
+ return dataToSearch;
375
+ }
376
+ const { title, sku } = variant;
377
+ function customEncoder(content) {
378
+ const tokens = [];
379
+ const str = content.toLowerCase();
380
+ // Remove symbols from the string (keep only letters, numbers, commas, and spaces)
381
+ const cleanedStr = str.replace(/[\/-]/g, " ");
382
+ const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, "");
383
+ const words = cleanedStr2.split(/\s+/);
384
+ for (let word of words) {
385
+ tokens.push(word);
386
+ }
387
+ return tokens;
388
+ }
389
+ const index = new Index({
390
+ charset: EnglishPreset,
391
+ // encoder: encoder,
392
+ encode: customEncoder,
393
+ tokenize: "strict",
394
+ });
395
+ dataToSearch.forEach((item, id) => {
396
+ index.add(id, item.title);
397
+ });
398
+ const searchTerms = filters.match_values;
399
+ let final = null;
400
+ searchTerms.forEach((term) => {
401
+ if (final === null) {
149
402
  final = index.search(term, {
150
403
  resolve: false,
151
404
  suggest: true,
@@ -160,19 +413,14 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
160
413
  });
161
414
  }
162
415
  });
163
- // final = final.and({
164
- // index: index,
165
- // query: 'Chipper',
166
- // resolve: false,
167
- // // suggest: true,
168
- // })
169
- // MUST INCLUDE SKU???
170
416
  final = final.and({
171
417
  index: index,
172
418
  query: sku,
173
419
  resolve: false,
174
420
  suggest: true,
175
421
  });
422
+ const nots = [];
423
+ nots.push(...filters.search_exclusions);
176
424
  nots.forEach((term) => {
177
425
  final = final.not({
178
426
  index: index,
@@ -185,7 +433,16 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
185
433
  result.forEach((i) => {
186
434
  resultsArray.push(dataToSearch[i]);
187
435
  });
188
- return resultsArray;
436
+ for (let index = 0; index < dataToSearch.length; index++) {
437
+ const element = dataToSearch[index];
438
+ if (!result.includes(index)) {
439
+ if (!element.hide_reasons) {
440
+ element.hide_reasons = [];
441
+ }
442
+ element.hide_reasons.push(HIDE_REASONS.SEARCH_EXCLUSION);
443
+ }
444
+ }
445
+ return dataToSearch;
189
446
  };
190
447
  const filterLinkedElsewhereResults = (results, variantId) => {
191
448
  const filtered = results.filter((result) => {
@@ -220,48 +477,89 @@ const filterFoundProductIdExclusions = (results, found_id_exclusions) => {
220
477
  return filtered;
221
478
  };
222
479
  const filterIgnoredResults = (results) => {
223
- const filtered = results.filter((item) => {
224
- return item.ignore_result ? false : true;
480
+ results.forEach((item) => {
481
+ if (!item.hide_reasons) {
482
+ item.hide_reasons = [];
483
+ }
484
+ if (item.ignore_result) {
485
+ item.hide_reasons.push(HIDE_REASONS.IGNORED);
486
+ }
225
487
  });
226
- return filtered;
488
+ // const filtered = results.filter((item) => {
489
+ // return item.ignore_result ? false : true
490
+ // })
491
+ return results;
227
492
  };
228
- const filterPriceOutliers = (results, variantPrice, showHighPriceOutliers, showLowPriceOutliers) => {
229
- const filtered = results.filter((item) => {
230
- const showMoreExpensive = showHighPriceOutliers === true;
493
+ const filterPriceOutliers = (results, variantPrice, globalScrapeOptions) => {
494
+ results.forEach((item) => {
495
+ if (!item.hide_reasons) {
496
+ item.hide_reasons = [];
497
+ }
498
+ const too_cheap_multiplier = getUndercutThreshold(variantPrice, globalScrapeOptions.undercut_threshold_ranges || []);
231
499
  const isMoreExpensive = item.extracted_price > variantPrice * TOO_EXPENSIVE_MULTIPLIER;
232
- const showTooCheap = showLowPriceOutliers === true;
233
- const isTooCheap = item.extracted_price < variantPrice * TOO_CHEAP_MULTIPLIER;
234
- if (isMoreExpensive && !showMoreExpensive) {
235
- return false;
500
+ const isTooCheap = item.extracted_price < variantPrice * too_cheap_multiplier;
501
+ if (isMoreExpensive) {
502
+ item.hide_reasons.push(HIDE_REASONS.HIGH_PRICE_OUTLIER);
236
503
  }
237
- if (isTooCheap && !showTooCheap) {
238
- return false;
504
+ if (isTooCheap) {
505
+ item.hide_reasons.push(HIDE_REASONS.LOW_PRICE_OUTLIER);
239
506
  }
240
- return true;
241
507
  });
508
+ const filtered = results;
509
+ // const filtered = results.filter((item) => {
510
+ // const showMoreExpensive = showHighPriceOutliers === true
511
+ // const isMoreExpensive = item.extracted_price > variantPrice * TOO_EXPENSIVE_MULTIPLIER
512
+ // const showTooCheap = showLowPriceOutliers === true
513
+ // const isTooCheap = item.extracted_price < variantPrice * TOO_CHEAP_MULTIPLIER
514
+ // if (isMoreExpensive && !showMoreExpensive) {
515
+ // return false
516
+ // }
517
+ // if (isTooCheap && !showTooCheap) {
518
+ // return false
519
+ // }
520
+ // return true
521
+ // })
242
522
  return filtered;
243
523
  };
244
524
  const filterDateWindow = (results, dayWindow) => {
245
- const filtered = results.filter((item) => {
246
- if (!dayWindow)
247
- return true;
525
+ results.forEach((item) => {
526
+ if (!item.hide_reasons) {
527
+ item.hide_reasons = [];
528
+ }
248
529
  const itemDate = new Date(item.created_at);
249
- const variantDate = startOfDay(subDays(new Date(), Number(dayWindow) || 7));
250
- return itemDate >= variantDate;
530
+ const variantDate = startOfDay(subDays(new Date(), Number(dayWindow) || 3));
531
+ if (itemDate < variantDate) {
532
+ item.hide_reasons.push(HIDE_REASONS.DATE_OUTLIER);
533
+ }
251
534
  });
252
- return filtered;
535
+ // const filtered = results.filter((item) => {
536
+ // if (!dayWindow) return true
537
+ // const itemDate = new Date(item.created_at)
538
+ // const variantDate = startOfDay(subDays(new Date(), Number(dayWindow) || 7))
539
+ // return itemDate >= variantDate
540
+ // })
541
+ return results;
253
542
  };
254
543
  const filterCompetitors = (results, competitor_exclusions) => {
255
- const filtered = results.filter((item) => {
544
+ results.forEach((item) => {
545
+ if (!item.hide_reasons) {
546
+ item.hide_reasons = [];
547
+ }
256
548
  const lowerSource = item.source.toLowerCase();
257
- for (const exclusion of competitor_exclusions) {
258
- if (exclusion && lowerSource === exclusion.toLowerCase()) {
259
- return false;
260
- }
549
+ if (competitor_exclusions.some((exclusion) => exclusion && lowerSource === exclusion.toLowerCase())) {
550
+ item.hide_reasons.push(HIDE_REASONS.COMPETITOR_EXCLUSION);
261
551
  }
262
- return true;
263
552
  });
264
- return filtered;
553
+ // const filtered = results.filter((item) => {
554
+ // const lowerSource = item.source.toLowerCase()
555
+ // for (const exclusion of competitor_exclusions) {
556
+ // if (exclusion && lowerSource === exclusion.toLowerCase()) {
557
+ // return false
558
+ // }
559
+ // }
560
+ // return true
561
+ // })
562
+ return results;
265
563
  };
266
564
  const filterDuplicateResults = (results) => {
267
565
  const filteredUniqueResultsMap = {};
@@ -273,12 +571,24 @@ const filterDuplicateResults = (results) => {
273
571
  else {
274
572
  const existingItem = filteredUniqueResultsMap[key];
275
573
  if (new Date(item.created_at) > new Date(existingItem.created_at)) {
574
+ const foundResult = results.find((res) => res.id === existingItem.id);
575
+ if (foundResult) {
576
+ if (!foundResult.hide_reasons) {
577
+ foundResult.hide_reasons = [];
578
+ }
579
+ foundResult.hide_reasons.push(HIDE_REASONS.DUPLICATE);
580
+ }
276
581
  filteredUniqueResultsMap[key] = item;
277
582
  }
583
+ else {
584
+ if (!item.hide_reasons) {
585
+ item.hide_reasons = [];
586
+ }
587
+ item.hide_reasons.push(HIDE_REASONS.DUPLICATE);
588
+ }
278
589
  }
279
590
  });
280
- const filtered = Object.values(filteredUniqueResultsMap);
281
- return filtered;
591
+ return results;
282
592
  };
283
593
  export const calculateIgnoreStatus = (result, variant, result_ignore_keys) => {
284
594
  let ignore = false;
@@ -316,3 +626,7 @@ export const calculateIgnoreStatus = (result, variant, result_ignore_keys) => {
316
626
  }
317
627
  return ignore;
318
628
  };
629
+ function getUndercutThreshold(price, undercutThresholdRanges) {
630
+ const range = undercutThresholdRanges.find((r) => price >= r.min && price <= r.max);
631
+ return range ? range.threshold : 0.75; // fallback default
632
+ }
package/package.json CHANGED
@@ -1,27 +1,27 @@
1
1
  {
2
- "name": "@factorypure/client-helpers",
3
- "version": "1.0.14",
4
- "description": "",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
- "files": [
8
- "dist"
9
- ],
10
- "type": "module",
11
- "scripts": {
12
- "build": "tsc",
13
- "test": "echo \"Error: no test specified\" && exit 1"
14
- },
15
- "keywords": [],
16
- "author": "",
17
- "license": "ISC",
18
- "devDependencies": {
19
- "typescript": "^5.6.2"
20
- },
21
- "dependencies": {
22
- "@types/date-fns": "^2.5.3",
23
- "date-fns": "^4.1.0",
24
- "flexsearch": "^0.8.212",
25
- "zod": "^4.3.5"
26
- }
2
+ "name": "@factorypure/client-helpers",
3
+ "version": "1.0.16",
4
+ "description": "",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "type": "module",
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "keywords": [],
16
+ "author": "",
17
+ "license": "ISC",
18
+ "devDependencies": {
19
+ "typescript": "^5.6.2"
20
+ },
21
+ "dependencies": {
22
+ "@types/date-fns": "^2.5.3",
23
+ "date-fns": "^4.1.0",
24
+ "flexsearch": "^0.8.212",
25
+ "zod": "^4.3.5"
26
+ }
27
27
  }