lancer-shared 1.2.193 → 1.2.195

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.
@@ -341,6 +341,14 @@ const regionNames = {
341
341
  USOnly: 'US Only',
342
342
  UKOnly: 'UK Only',
343
343
  };
344
+ const CLIENT_SIZE_TO_NUMBER = {
345
+ 'Individual client': 1,
346
+ 'Small company (2-9 people)': 2,
347
+ 'Mid-sized company (10-99 people)': 10,
348
+ 'Large company (100-1,000 people)': 100,
349
+ 'Large company (1,000+ people)': 1000,
350
+ Unspecified: null,
351
+ };
344
352
 
345
353
  const jobStatusOrder = [
346
354
  "leads",
@@ -11136,6 +11144,7 @@ const jobFiltersSchema = z.object({
11136
11144
  excludes: z.string().nullable(),
11137
11145
  })
11138
11146
  .nullable(),
11147
+ searchQuery: z.string().nullable(),
11139
11148
  isFeatured: z.enum(['all', 'true', 'false']).nullable(),
11140
11149
  regions: z.array(regionEnum).nullable(),
11141
11150
  categories: z
@@ -11169,12 +11178,16 @@ const jobFiltersSchema = z.object({
11169
11178
  clientLocationIncludes: z.array(z.string()).nullable(),
11170
11179
  clientLocationExcludes: z.array(z.string()).nullable(),
11171
11180
  minReviewScore: z.number().min(0).max(5).nullable(),
11172
- minTotalSpent: z.number().nullable(),
11181
+ maxReviewScore: z.number().min(0).max(5).nullable(),
11182
+ minTotalSpent: z.number().min(0).nullable(),
11183
+ maxTotalSpent: z.number().min(0).nullable(),
11173
11184
  minHireRate: z.number().min(0).max(100).nullable(),
11185
+ maxHireRate: z.number().min(0).max(100).nullable(),
11174
11186
  clientIndustry: z.array(clientIndustryEnum).nullable(),
11175
11187
  companySize: z.array(clientSizeEnum).nullable(),
11176
11188
  minJobsPosted: z.number().nullable(),
11177
11189
  minAvgHourlyRate: z.number().nullable(),
11190
+ maxAvgHourlyRate: z.number().nullable(),
11178
11191
  minNumReviews: z.number().nullable(),
11179
11192
  memberSinceFrom: z.string().date().nullable(),
11180
11193
  memberSinceTo: z.string().date().nullable(),
@@ -13407,6 +13420,354 @@ const campaignInsightsSchema = z.object({
13407
13420
  suitabilityRange90to100: z.number(),
13408
13421
  });
13409
13422
 
13423
+ // Clean, validated schema using Zod
13424
+ const SearchFieldsSchema = z.object({
13425
+ allWords: z.string().default(''),
13426
+ anyWords: z.string().default(''),
13427
+ noneWords: z.string().default(''),
13428
+ exactPhrase: z.string().default(''),
13429
+ titleSearch: z.string().default(''),
13430
+ skillsSearch: z.string().default(''),
13431
+ });
13432
+ class SearchQueryBuilder {
13433
+ /**
13434
+ * Build a search query from structured fields
13435
+ * Properly handles quoted phrases in all fields
13436
+ */
13437
+ static buildQuery(fields) {
13438
+ const validatedFields = SearchFieldsSchema.parse(fields);
13439
+ const parts = [];
13440
+ // All words (AND logic) - supports phrases
13441
+ if (validatedFields.allWords.trim()) {
13442
+ const terms = this.splitTerms(validatedFields.allWords);
13443
+ if (terms.length === 1) {
13444
+ parts.push(terms[0]);
13445
+ }
13446
+ else if (terms.length > 1) {
13447
+ parts.push(`(${terms.join(' AND ')})`);
13448
+ }
13449
+ }
13450
+ // Any words (OR logic) - supports phrases
13451
+ if (validatedFields.anyWords.trim()) {
13452
+ const terms = this.splitTerms(validatedFields.anyWords);
13453
+ if (terms.length === 1) {
13454
+ parts.push(terms[0]);
13455
+ }
13456
+ else if (terms.length > 1) {
13457
+ parts.push(`(${terms.join(' OR ')})`);
13458
+ }
13459
+ }
13460
+ // Excluded words (NOT logic) - supports phrases
13461
+ if (validatedFields.noneWords.trim()) {
13462
+ const terms = this.splitTerms(validatedFields.noneWords);
13463
+ const notParts = terms.map((term) => `NOT ${term}`);
13464
+ parts.push(...notParts);
13465
+ }
13466
+ // Exact phrase - single phrase only
13467
+ if (validatedFields.exactPhrase.trim()) {
13468
+ parts.push(`"${validatedFields.exactPhrase.trim()}"`);
13469
+ }
13470
+ // Field-specific searches - now support phrases too
13471
+ if (validatedFields.titleSearch.trim()) {
13472
+ const titleTerms = this.splitTerms(validatedFields.titleSearch);
13473
+ if (titleTerms.length === 1) {
13474
+ // Single term or phrase
13475
+ const term = titleTerms[0];
13476
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
13477
+ parts.push(isQuoted ? `title:${term}` : `title:"${term}"`);
13478
+ }
13479
+ else {
13480
+ // Multiple terms - each gets title: prefix
13481
+ const titleParts = titleTerms.map((term) => {
13482
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
13483
+ return isQuoted ? `title:${term}` : `title:"${term}"`;
13484
+ });
13485
+ parts.push(`(${titleParts.join(' AND ')})`);
13486
+ }
13487
+ }
13488
+ if (validatedFields.skillsSearch.trim()) {
13489
+ const skillsTerms = this.splitTerms(validatedFields.skillsSearch);
13490
+ if (skillsTerms.length === 1) {
13491
+ const term = skillsTerms[0];
13492
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
13493
+ parts.push(isQuoted ? `skills:${term}` : `skills:"${term}"`);
13494
+ }
13495
+ else {
13496
+ const skillsParts = skillsTerms.map((term) => {
13497
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
13498
+ return isQuoted ? `skills:${term}` : `skills:"${term}"`;
13499
+ });
13500
+ parts.push(`(${skillsParts.join(' AND ')})`);
13501
+ }
13502
+ }
13503
+ return parts.join(' AND ').trim() || '*';
13504
+ }
13505
+ /**
13506
+ * Get human-readable description of search criteria
13507
+ */
13508
+ static describe(fields) {
13509
+ const validatedFields = SearchFieldsSchema.parse(fields);
13510
+ const descriptions = [];
13511
+ if (validatedFields.allWords)
13512
+ descriptions.push(`All words: ${validatedFields.allWords}`);
13513
+ if (validatedFields.anyWords)
13514
+ descriptions.push(`Any words: ${validatedFields.anyWords}`);
13515
+ if (validatedFields.noneWords)
13516
+ descriptions.push(`Excluding: ${validatedFields.noneWords}`);
13517
+ if (validatedFields.exactPhrase)
13518
+ descriptions.push(`Exact phrase: "${validatedFields.exactPhrase}"`);
13519
+ if (validatedFields.titleSearch)
13520
+ descriptions.push(`In title: ${validatedFields.titleSearch}`);
13521
+ if (validatedFields.skillsSearch)
13522
+ descriptions.push(`Skills: ${validatedFields.skillsSearch}`);
13523
+ return descriptions.length > 0 ? descriptions.join(' • ') : 'All results';
13524
+ }
13525
+ /**
13526
+ * Validate search fields
13527
+ */
13528
+ static validate(fields) {
13529
+ const result = SearchFieldsSchema.safeParse(fields);
13530
+ if (result.success) {
13531
+ return { valid: true, data: result.data };
13532
+ }
13533
+ return {
13534
+ valid: false,
13535
+ errors: result.error.errors.map((err) => `${err.path.join('.')}: ${err.message}`),
13536
+ };
13537
+ }
13538
+ /**
13539
+ * Test/demo method to show phrase handling
13540
+ * Remove this in production
13541
+ */
13542
+ static examples() {
13543
+ const testFields = {
13544
+ allWords: 'react "senior developer" javascript',
13545
+ anyWords: 'frontend "full stack" backend',
13546
+ noneWords: 'junior "entry level"',
13547
+ exactPhrase: 'tech lead',
13548
+ titleSearch: 'software engineer',
13549
+ skillsSearch: 'node.js',
13550
+ };
13551
+ console.log('Query:', this.buildQuery(testFields));
13552
+ console.log('Description:', this.describe(testFields));
13553
+ // Should produce:
13554
+ // Query: (react AND "senior developer" AND javascript) AND (frontend OR "full stack" OR backend) AND NOT junior AND NOT "entry level" AND "tech lead" AND title:"software engineer" AND skills:"node.js"
13555
+ }
13556
+ /**
13557
+ * Parse a query string back into SearchFields structure
13558
+ * Fixed to handle grouped NOT expressions correctly
13559
+ */
13560
+ static parseQuery(query) {
13561
+ const result = {
13562
+ allWords: '',
13563
+ anyWords: '',
13564
+ noneWords: '',
13565
+ exactPhrase: '',
13566
+ titleSearch: '',
13567
+ skillsSearch: '',
13568
+ };
13569
+ if (!query || query.trim() === '*') {
13570
+ return result;
13571
+ }
13572
+ let remainingQuery = query.trim();
13573
+ // 1. Extract field-specific searches first
13574
+ const fieldPatterns = [
13575
+ { field: 'titleSearch', pattern: /title:("([^"]+)"|([^\s)]+))/g },
13576
+ { field: 'skillsSearch', pattern: /skills:("([^"]+)"|([^\s)]+))/g },
13577
+ ];
13578
+ for (const { field, pattern } of fieldPatterns) {
13579
+ const matches = [...remainingQuery.matchAll(pattern)];
13580
+ if (matches.length > 0) {
13581
+ const terms = matches.map((match) => {
13582
+ if (match[2]) {
13583
+ return `"${match[2]}"`;
13584
+ }
13585
+ return match[3];
13586
+ });
13587
+ result[field] = terms.join(' ');
13588
+ remainingQuery = remainingQuery.replace(pattern, '').trim();
13589
+ }
13590
+ }
13591
+ // 2. Extract grouped field searches like title:(term1 AND term2)
13592
+ const groupedFieldPattern = /(title|skills):\(([^)]+)\)/g;
13593
+ let groupMatch;
13594
+ while ((groupMatch = groupedFieldPattern.exec(remainingQuery)) !== null) {
13595
+ const fieldName = groupMatch[1] === 'title' ? 'titleSearch' : 'skillsSearch';
13596
+ const groupContent = groupMatch[2];
13597
+ const terms = this.extractTermsFromGroup(groupContent, groupMatch[1]);
13598
+ result[fieldName] = terms.join(' ');
13599
+ remainingQuery = remainingQuery.replace(groupMatch[0], '').trim();
13600
+ }
13601
+ // 3. **NEW** - Extract grouped NOT expressions FIRST: NOT (term1 OR term2 OR ...)
13602
+ const groupedNotPattern = /NOT\s+\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
13603
+ const groupedNotMatches = [...remainingQuery.matchAll(groupedNotPattern)];
13604
+ if (groupedNotMatches.length > 0) {
13605
+ const noneTerms = this.extractTermsFromORGroup(groupedNotMatches[0][1]);
13606
+ result.noneWords = noneTerms.join(' ');
13607
+ remainingQuery = remainingQuery
13608
+ .replace(groupedNotMatches[0][0], '')
13609
+ .trim();
13610
+ }
13611
+ // 4. Extract individual NOT terms (only if no grouped NOT was found)
13612
+ if (!result.noneWords) {
13613
+ const notPattern = /NOT\s+("([^"]+)"|([^\s)]+))/g;
13614
+ const notMatches = [...remainingQuery.matchAll(notPattern)];
13615
+ if (notMatches.length > 0) {
13616
+ const noneTerms = notMatches.map((match) => {
13617
+ if (match[2]) {
13618
+ return `"${match[2]}"`;
13619
+ }
13620
+ return match[3];
13621
+ });
13622
+ result.noneWords = noneTerms.join(' ');
13623
+ remainingQuery = remainingQuery.replace(notPattern, '').trim();
13624
+ }
13625
+ }
13626
+ // 5. Process grouped expressions - Clean up connectors first
13627
+ remainingQuery = this.cleanupConnectors(remainingQuery);
13628
+ // Extract OR groups (anyWords) - PROCESS FIRST
13629
+ const orGroupPattern = /\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
13630
+ const orMatches = [...remainingQuery.matchAll(orGroupPattern)];
13631
+ if (orMatches.length > 0) {
13632
+ const orTerms = this.extractTermsFromORGroup(orMatches[0][1]);
13633
+ result.anyWords = orTerms.join(' ');
13634
+ remainingQuery = remainingQuery.replace(orMatches[0][0], '').trim();
13635
+ }
13636
+ // Extract AND groups (allWords) - PROCESS SECOND
13637
+ const andGroupPattern = /\(([^)]+(?:\s+AND\s+[^)]+)+)\)/g;
13638
+ const andMatches = [...remainingQuery.matchAll(andGroupPattern)];
13639
+ if (andMatches.length > 0) {
13640
+ const andTerms = this.extractTermsFromANDGroup(andMatches[0][1]);
13641
+ result.allWords = andTerms.join(' ');
13642
+ remainingQuery = remainingQuery.replace(andMatches[0][0], '').trim();
13643
+ }
13644
+ // 6. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
13645
+ const standaloneQuotePattern = /(?:^|\s)("([^"]+)")(?=\s|$)/g;
13646
+ const quoteMatches = [...remainingQuery.matchAll(standaloneQuotePattern)];
13647
+ if (quoteMatches.length > 0) {
13648
+ result.exactPhrase = quoteMatches[0][2];
13649
+ remainingQuery = remainingQuery.replace(quoteMatches[0][1], '').trim();
13650
+ }
13651
+ // 7. Handle remaining simple terms as allWords
13652
+ if (remainingQuery) {
13653
+ const remainingTerms = this.splitTermsWithQuotes(remainingQuery);
13654
+ if (remainingTerms.length > 0) {
13655
+ result.allWords = result.allWords
13656
+ ? `${result.allWords} ${remainingTerms.join(' ')}`.trim()
13657
+ : remainingTerms.join(' ');
13658
+ }
13659
+ }
13660
+ return result;
13661
+ }
13662
+ /**
13663
+ * Extract terms from grouped field content, preserving quotes
13664
+ */
13665
+ static extractTermsFromGroup(content, fieldPrefix) {
13666
+ // Remove field prefixes but preserve quotes
13667
+ let cleanContent = content;
13668
+ const fieldPattern = new RegExp(`${fieldPrefix}:("([^"]+)"|([^\\s]+))`, 'g');
13669
+ const terms = [];
13670
+ let match;
13671
+ while ((match = fieldPattern.exec(content)) !== null) {
13672
+ if (match[2]) {
13673
+ // Quoted content
13674
+ terms.push(`"${match[2]}"`);
13675
+ }
13676
+ else if (match[3]) {
13677
+ // Unquoted content
13678
+ terms.push(match[3]);
13679
+ }
13680
+ }
13681
+ return terms.length > 0
13682
+ ? terms
13683
+ : [
13684
+ cleanContent
13685
+ .replace(/(title|skills):/g, '')
13686
+ .replace(/\s+AND\s+/g, ' ')
13687
+ .trim(),
13688
+ ];
13689
+ }
13690
+ /**
13691
+ * Extract terms from OR group, preserving quotes and removing OR separators
13692
+ */
13693
+ static extractTermsFromORGroup(content) {
13694
+ return content
13695
+ .split(/\s+OR\s+/)
13696
+ .map((term) => term.trim())
13697
+ .filter(Boolean);
13698
+ }
13699
+ /**
13700
+ * Extract terms from AND group, preserving quotes
13701
+ */
13702
+ static extractTermsFromANDGroup(content) {
13703
+ return content
13704
+ .split(/\s+AND\s+/)
13705
+ .map((term) => term.trim())
13706
+ .filter(Boolean);
13707
+ }
13708
+ /**
13709
+ * Split simple terms while preserving quoted phrases
13710
+ */
13711
+ static splitTermsWithQuotes(input) {
13712
+ const terms = [];
13713
+ const regex = /"([^"]+)"|(\S+)/g;
13714
+ let match;
13715
+ while ((match = regex.exec(input)) !== null) {
13716
+ if (match[1]) {
13717
+ // Quoted phrase - preserve quotes
13718
+ terms.push(`"${match[1]}"`);
13719
+ }
13720
+ else if (match[2] && !['AND', 'OR', 'NOT'].includes(match[2])) {
13721
+ // Regular word (not a connector)
13722
+ terms.push(match[2]);
13723
+ }
13724
+ }
13725
+ return terms;
13726
+ }
13727
+ /**
13728
+ * Clean up AND/OR connectors while preserving quotes
13729
+ */
13730
+ static cleanupConnectors(query) {
13731
+ return query
13732
+ .replace(/\s+AND\s+/g, ' ')
13733
+ .replace(/\s+/g, ' ')
13734
+ .trim();
13735
+ }
13736
+ /**
13737
+ * Test the roundtrip conversion (buildQuery -> parseQuery)
13738
+ */
13739
+ static testRoundtrip(fields) {
13740
+ const query = this.buildQuery(fields);
13741
+ const parsed = this.parseQuery(query);
13742
+ const matches = JSON.stringify(fields) === JSON.stringify(parsed);
13743
+ return {
13744
+ original: fields,
13745
+ query,
13746
+ parsed,
13747
+ matches,
13748
+ };
13749
+ }
13750
+ /**
13751
+ * Simple term splitting that handles quoted phrases
13752
+ */
13753
+ static splitTerms(input) {
13754
+ const terms = [];
13755
+ const regex = /"([^"]+)"|(\S+)/g;
13756
+ let match;
13757
+ while ((match = regex.exec(input)) !== null) {
13758
+ if (match[1]) {
13759
+ // Quoted phrase
13760
+ terms.push(`"${match[1]}"`);
13761
+ }
13762
+ else if (match[2]) {
13763
+ // Regular word
13764
+ terms.push(match[2]);
13765
+ }
13766
+ }
13767
+ return terms;
13768
+ }
13769
+ }
13770
+
13410
13771
  const fallbackEnum = z.enum(['noBoostBid', 'ignore']);
13411
13772
  const boostFormSchema = z.object({
13412
13773
  minPlace: z.number().int().min(1).max(4), // Don't boost below this place
@@ -13417,144 +13778,14 @@ const boostFormSchema = z.object({
13417
13778
  const nodeEnums = z.enum([
13418
13779
  'clientAvgHourlyRateNode',
13419
13780
  'bidNode',
13781
+ 'suitabilityNode',
13420
13782
  'clientHireRateNode',
13421
13783
  'clientSizeNode',
13422
13784
  'boostNode',
13423
13785
  'clientSpentNode',
13424
13786
  'clientRatingNode',
13425
- 'startNode',
13426
- 'budgetNode',
13427
- 'paymentTypeNode',
13428
13787
  ]);
13429
13788
 
13430
- const rangesOverlap$5 = (range1, range2) => {
13431
- return range1.min < range2.max && range2.min < range1.max;
13432
- };
13433
- // Payment type options (excluding 'Unspecified')
13434
- const budgetPaymentTypeEnum = z.enum(['Hourly', 'Fixed-price']);
13435
- const createBudgetFormSchema = (existingHourlyRateRanges, existingFixedBudgetRanges) => z
13436
- .object({
13437
- paymentTypes: z
13438
- .array(budgetPaymentTypeEnum)
13439
- .min(1, 'Please select at least one payment type'),
13440
- hourlyRateMin: z
13441
- .number()
13442
- .min(0, 'Minimum hourly rate must be non-negative')
13443
- .optional(),
13444
- hourlyRateMax: z
13445
- .number()
13446
- .min(0, 'Maximum hourly rate must be non-negative')
13447
- .optional(),
13448
- fixedBudgetMin: z
13449
- .number()
13450
- .min(0, 'Minimum fixed budget must be non-negative')
13451
- .optional(),
13452
- fixedBudgetMax: z
13453
- .number()
13454
- .min(0, 'Maximum fixed budget must be non-negative')
13455
- .optional(),
13456
- action: nodeEnums,
13457
- })
13458
- // Validate hourly rate fields are provided when Hourly is selected
13459
- .refine((data) => {
13460
- if (data.paymentTypes.includes('Hourly')) {
13461
- return (data.hourlyRateMin !== undefined && data.hourlyRateMax !== undefined);
13462
- }
13463
- return true;
13464
- }, {
13465
- message: 'Hourly rate min and max are required when Hourly payment type is selected',
13466
- path: ['hourlyRateMin'],
13467
- })
13468
- // Validate fixed budget fields are provided when Fixed-price is selected
13469
- .refine((data) => {
13470
- if (data.paymentTypes.includes('Fixed-price')) {
13471
- return (data.fixedBudgetMin !== undefined &&
13472
- data.fixedBudgetMax !== undefined);
13473
- }
13474
- return true;
13475
- }, {
13476
- message: 'Fixed budget min and max are required when Fixed-price payment type is selected',
13477
- path: ['fixedBudgetMin'],
13478
- })
13479
- // Validate hourly rate range when provided AND hourly payment type is selected
13480
- .refine((data) => {
13481
- if (data.paymentTypes.includes('Hourly') &&
13482
- data.hourlyRateMin !== undefined &&
13483
- data.hourlyRateMax !== undefined) {
13484
- return data.hourlyRateMin < data.hourlyRateMax;
13485
- }
13486
- return true;
13487
- }, {
13488
- message: 'Minimum hourly rate must be less than maximum',
13489
- path: ['hourlyRateMin'],
13490
- })
13491
- .refine((data) => {
13492
- if (data.paymentTypes.includes('Hourly') &&
13493
- data.hourlyRateMin !== undefined &&
13494
- data.hourlyRateMax !== undefined) {
13495
- return data.hourlyRateMax > data.hourlyRateMin;
13496
- }
13497
- return true;
13498
- }, {
13499
- message: 'Maximum hourly rate must be greater than minimum',
13500
- path: ['hourlyRateMax'],
13501
- })
13502
- // Validate fixed budget range when provided AND fixed payment type is selected
13503
- .refine((data) => {
13504
- if (data.paymentTypes.includes('Fixed-price') &&
13505
- data.fixedBudgetMin !== undefined &&
13506
- data.fixedBudgetMax !== undefined) {
13507
- return data.fixedBudgetMin < data.fixedBudgetMax;
13508
- }
13509
- return true;
13510
- }, {
13511
- message: 'Minimum fixed budget must be less than maximum',
13512
- path: ['fixedBudgetMin'],
13513
- })
13514
- .refine((data) => {
13515
- if (data.paymentTypes.includes('Fixed-price') &&
13516
- data.fixedBudgetMin !== undefined &&
13517
- data.fixedBudgetMax !== undefined) {
13518
- return data.fixedBudgetMax > data.fixedBudgetMin;
13519
- }
13520
- return true;
13521
- }, {
13522
- message: 'Maximum fixed budget must be greater than minimum',
13523
- path: ['fixedBudgetMax'],
13524
- })
13525
- // Check for hourly rate range overlaps when provided
13526
- .refine((data) => {
13527
- if (data.hourlyRateMin !== undefined &&
13528
- data.hourlyRateMax !== undefined) {
13529
- const newHourlyRateRange = {
13530
- min: data.hourlyRateMin,
13531
- max: data.hourlyRateMax,
13532
- };
13533
- return !existingHourlyRateRanges.some((existingRange) => rangesOverlap$5(newHourlyRateRange, existingRange));
13534
- }
13535
- return true;
13536
- }, {
13537
- message: 'Hourly rate range overlaps with existing hourly rate range',
13538
- path: ['hourlyRateMin'],
13539
- })
13540
- // Check for fixed budget range overlaps when provided
13541
- .refine((data) => {
13542
- if (data.fixedBudgetMin !== undefined &&
13543
- data.fixedBudgetMax !== undefined) {
13544
- const newFixedBudgetRange = {
13545
- min: data.fixedBudgetMin,
13546
- max: data.fixedBudgetMax,
13547
- };
13548
- return !existingFixedBudgetRanges.some((existingRange) => rangesOverlap$5(newFixedBudgetRange, existingRange));
13549
- }
13550
- return true;
13551
- }, {
13552
- message: 'Fixed budget range overlaps with existing fixed budget range',
13553
- path: ['fixedBudgetMin'],
13554
- });
13555
- // Default schema for backwards compatibility
13556
- const addBudgetNodeFormSchema = createBudgetFormSchema([], []);
13557
-
13558
13789
  const sizeOverlap = (size1, size2) => {
13559
13790
  if (size1 === size2) {
13560
13791
  return true;
@@ -13655,27 +13886,6 @@ const createHourlyRateFormSchema = (existingRanges) => z
13655
13886
  // Keep the original schema for backwards compatibility if needed
13656
13887
  const addFromHourlyRateNodeFormSchema = createHourlyRateFormSchema([]);
13657
13888
 
13658
- const limitedPaymentTypeEnum = paymentTypeEnum.exclude(['Unspecified']);
13659
- const paymentTypeOverlap = (paymentType1, paymentType2) => {
13660
- if (paymentType1 === paymentType2) {
13661
- return true;
13662
- }
13663
- return false;
13664
- };
13665
- const createPaymentTypeFormSchema = (existingPaymentTypes) => z
13666
- .object({
13667
- paymentTypes: z.array(limitedPaymentTypeEnum).min(1),
13668
- action: nodeEnums,
13669
- })
13670
- .refine((data) => {
13671
- const newPaymentTypes = data.paymentTypes;
13672
- return !existingPaymentTypes.some((existingPaymentType) => newPaymentTypes.some((newPaymentType) => paymentTypeOverlap(newPaymentType, existingPaymentType)));
13673
- }, {
13674
- message: 'Payment type overlaps with existing payment type',
13675
- path: ['paymentTypes'],
13676
- });
13677
- const addFromPaymentTypeNodeFormSchema = createPaymentTypeFormSchema([]);
13678
-
13679
13889
  const rangesOverlap$1 = (range1, range2) => {
13680
13890
  return range1.from < range2.to && range2.from < range1.to;
13681
13891
  };
@@ -13702,10 +13912,6 @@ const createClientRatingFormSchema = (existingRanges) => z
13702
13912
  });
13703
13913
  const addFromClientRatingNodeFormSchema = createClientRatingFormSchema([]);
13704
13914
 
13705
- const addFromStartNodeFormSchema = z.object({
13706
- action: nodeEnums,
13707
- });
13708
-
13709
13915
  const rangesOverlap = (range1, range2) => {
13710
13916
  return range1.from < range2.to && range2.from < range1.to;
13711
13917
  };
@@ -23484,6 +23690,7 @@ exports.BidderAccountAlreadyConnectedException = BidderAccountAlreadyConnectedEx
23484
23690
  exports.BoostAboveMaxConnectsException = BoostAboveMaxConnectsException;
23485
23691
  exports.CAMPAIGN_NOTIFICATION_SETTINGS = CAMPAIGN_NOTIFICATION_SETTINGS;
23486
23692
  exports.CAMPAIGN_NOTIFICATION_TYPES = CAMPAIGN_NOTIFICATION_TYPES;
23693
+ exports.CLIENT_SIZE_TO_NUMBER = CLIENT_SIZE_TO_NUMBER;
23487
23694
  exports.CloudflareChallengeFailedException = CloudflareChallengeFailedException;
23488
23695
  exports.DeleteMultiloginProfileException = DeleteMultiloginProfileException;
23489
23696
  exports.DropdownOptionNotPresentException = DropdownOptionNotPresentException;
@@ -23528,6 +23735,8 @@ exports.PuppeteerConnectionErrorException = PuppeteerConnectionErrorException;
23528
23735
  exports.QuestionPairNotMatchingException = QuestionPairNotMatchingException;
23529
23736
  exports.ROUTES = ROUTES;
23530
23737
  exports.ScraperAccountProxyNotFoundException = ScraperAccountProxyNotFoundException;
23738
+ exports.SearchFieldsSchema = SearchFieldsSchema;
23739
+ exports.SearchQueryBuilder = SearchQueryBuilder;
23531
23740
  exports.SelectAgencyException = SelectAgencyException;
23532
23741
  exports.SelectContractorException = SelectContractorException;
23533
23742
  exports.SelectorNotFoundError = SelectorNotFoundError;
@@ -23539,14 +23748,11 @@ exports.acceptUpworkInvitationSchema = acceptUpworkInvitationSchema;
23539
23748
  exports.accountStatusDisplayMap = accountStatusDisplayMap;
23540
23749
  exports.accountStatusOrder = accountStatusOrder;
23541
23750
  exports.accountStatusSchema = accountStatusSchema;
23542
- exports.addBudgetNodeFormSchema = addBudgetNodeFormSchema;
23543
23751
  exports.addFromClientHireRateNodeFormSchema = addFromClientHireRateNodeFormSchema;
23544
23752
  exports.addFromClientRatingNodeFormSchema = addFromClientRatingNodeFormSchema;
23545
23753
  exports.addFromClientSizeNodeFormSchema = addFromClientSizeNodeFormSchema;
23546
23754
  exports.addFromClientSpentNodeFormSchema = addFromClientSpentNodeFormSchema;
23547
23755
  exports.addFromHourlyRateNodeFormSchema = addFromHourlyRateNodeFormSchema;
23548
- exports.addFromPaymentTypeNodeFormSchema = addFromPaymentTypeNodeFormSchema;
23549
- exports.addFromStartNodeFormSchema = addFromStartNodeFormSchema;
23550
23756
  exports.addFromSuitabilityNodeFormSchema = addFromSuitabilityNodeFormSchema;
23551
23757
  exports.agencyBidPayloadSchema = agencyBidPayloadSchema;
23552
23758
  exports.agencyBidProposalDataSchema = agencyBidProposalDataSchema;
@@ -23581,7 +23787,6 @@ exports.biddingRejectedWithFeedbackEventMetadata = biddingRejectedWithFeedbackEv
23581
23787
  exports.booleanSchema = booleanSchema;
23582
23788
  exports.boostAboveMaxConnectsException = boostAboveMaxConnectsException;
23583
23789
  exports.boostFormSchema = boostFormSchema;
23584
- exports.budgetPaymentTypeEnum = budgetPaymentTypeEnum;
23585
23790
  exports.buildRoute = buildRoute;
23586
23791
  exports.campaignAIMetricsSchema = campaignAIMetricsSchema;
23587
23792
  exports.campaignActivityCreateSchema = campaignActivityCreateSchema;
@@ -23614,7 +23819,6 @@ exports.convertToUtc = convertToUtc;
23614
23819
  exports.countryMapping = countryMapping;
23615
23820
  exports.coverLetterTemplateSchema = coverLetterTemplateSchema;
23616
23821
  exports.createBidderAccountSchema = createBidderAccountSchema;
23617
- exports.createBudgetFormSchema = createBudgetFormSchema;
23618
23822
  exports.createCampaignSchema = createCampaignSchema;
23619
23823
  exports.createChatbotSchema = createChatbotSchema;
23620
23824
  exports.createClientHireRateFormSchema = createClientHireRateFormSchema;
@@ -23625,7 +23829,6 @@ exports.createCoverLetterTemplateSchema = createCoverLetterTemplateSchema;
23625
23829
  exports.createHourlyRateFormSchema = createHourlyRateFormSchema;
23626
23830
  exports.createOrganizationProfileSchema = createOrganizationProfileSchema;
23627
23831
  exports.createOrganizationSchema = createOrganizationSchema;
23628
- exports.createPaymentTypeFormSchema = createPaymentTypeFormSchema;
23629
23832
  exports.createScraperAccountSchema = createScraperAccountSchema;
23630
23833
  exports.createSuitabilityFormSchema = createSuitabilityFormSchema;
23631
23834
  exports.dailyUsageSchema = dailyUsageSchema;
@@ -23717,7 +23920,6 @@ exports.leadSchema = leadSchema;
23717
23920
  exports.leadStatusActivitySchema = leadStatusActivitySchema;
23718
23921
  exports.leadStatusEnum = leadStatusEnum;
23719
23922
  exports.leadStatusEventMetadata = leadStatusEventMetadata;
23720
- exports.limitedPaymentTypeEnum = limitedPaymentTypeEnum;
23721
23923
  exports.limitsSchema = limitsSchema;
23722
23924
  exports.logEventSchema = logEventSchema;
23723
23925
  exports.loginFailedException = loginFailedException;
@@ -65,3 +65,4 @@ export declare const JOB_FILTER_OPTIONS: {
65
65
  };
66
66
  export declare const HIERARCHICAL_CATEGORIES_TO_CHILDREN: Record<"Accounting & Consulting" | "Admin Support" | "Customer Service" | "Data Science & Analytics" | "Design & Creative" | "Engineering & Architecture" | "IT & Networking" | "Legal" | "Sales & Marketing" | "Translation" | "Software Development" | "Writing", readonly ["Accounting & Bookkeeping", "Financial Planning", "Management Consulting & Analysis", "Other - Accounting & Consulting", "Personal & Professional Coaching", "Recruiting & Human Resources"] | readonly ["Data Entry & Transcription Services", "Market Research & Product Reviews", "Project Management", "Virtual Assistance"] | readonly ["Community Management & Tagging", "Customer Service & Tech Support"] | readonly ["AI & Machine Learning", "Data Analysis & Testing", "Data Extraction/ETL", "Data Mining & Management"] | readonly ["Art & Illustration", "Audio & Music Production", "Branding & Logo Design", "Graphic, Editorial & Presentation Design", "NFT, AR/VR & Game Art", "Performing Arts", "Photography", "Product Design", "Video & Animation"] | readonly ["3D Modeling & CAD", "Building & Landscape Architecture", "Chemical Engineering", "Civil & Structural Engineering", "Contract Manufacturing", "Electrical & Electronic Engineering", "Energy & Mechanical Engineering"] | readonly ["Database Management & Administration", "DevOps & Solution Architecture", "ERP/CRM Software", "Information Security & Compliance", "Network & System Administration"] | readonly ["Corporate & Contract Law", "Finance & Tax Law", "International & Immigration Law", "Public Law"] | readonly ["Digital Marketing", "Lead Generation & Telemarketing", "Marketing, PR & Brand Strategy"] | readonly ["Language Tutoring & Interpretation", "Translation & Localization Services"] | readonly ["AI Apps & Integration", "Blockchain, NFT & Cryptocurrency", "Desktop Application Development", "Ecommerce Development", "Game Design & Development", "Mobile Development", "Other - Software Development", "Product Management & Scrum", "QA Testing", "Scripts & Utilities", "Web & Mobile Design", "Web Development"] | readonly ["Content Writing", "Editing & Proofreading Services", "Professional & Business Writing", "Sales & Marketing Copywriting"]>;
67
67
  export declare const regionNames: Record<Region, string>;
68
+ export declare const CLIENT_SIZE_TO_NUMBER: Record<(typeof JOB_FILTER_OPTIONS.CLIENT_SIZE)[number], number | null>;