lancer-shared 1.2.260 → 1.2.261

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.
@@ -6770,12 +6770,12 @@ const leadSchema = upworkJobSchema
6770
6770
  biddingTaskScheduled: booleanType().nullable(),
6771
6771
  scheduledBiddingTime: numberType().nullable(),
6772
6772
  inQueue: booleanType().nullable(),
6773
+ biddingDelayInMinutes: numberType().nullable(),
6773
6774
  wonAmount: numberType().optional(),
6774
6775
  feedbackCheckTaskId: stringType().nullable(),
6775
6776
  bidDecision: z.enum(['proceeded', 'rejected']).nullable(),
6776
6777
  rejectedFeedback: stringType().nullable(),
6777
6778
  applicationId: stringType().nullable(),
6778
- campaignName: stringType().optional(),
6779
6779
  })
6780
6780
  .omit({
6781
6781
  processed: true,
@@ -6814,6 +6814,7 @@ const getCampaignLeadsRequestQuerySchema = z.object({
6814
6814
  limit: z.number().default(20).optional(),
6815
6815
  status: getCampaignLeadsStatusEnum.optional(),
6816
6816
  campaignId: z.string().optional(),
6817
+ inQueue: z.boolean().optional(),
6817
6818
  });
6818
6819
  const getCampaignLeadsResponseSchema = z.object({
6819
6820
  data: z.array(leadSchema),
@@ -6998,6 +6999,21 @@ const onboardingProgressSchema = z.object({
6998
6999
  startCampaign: z.boolean(),
6999
7000
  });
7000
7001
 
7002
+ const getOrganizationLeadsStatusEnum = z.enum([
7003
+ 'all',
7004
+ 'suitable',
7005
+ 'contacted',
7006
+ 'viewed',
7007
+ 'replied',
7008
+ ]);
7009
+ const getOrganizationLeadsRequestQuerySchema = z.object({
7010
+ cursor: z.string().optional(),
7011
+ limit: z.number().default(20).optional(),
7012
+ status: getOrganizationLeadsStatusEnum.optional(),
7013
+ campaignId: z.string().optional(),
7014
+ inQueue: z.boolean().optional(),
7015
+ });
7016
+
7001
7017
  const organizationTypeSchema = z.enum(['agency', 'freelancer']);
7002
7018
  const organizationTierEnum = z.enum(['free', 'premium']);
7003
7019
  const limitsSchema = objectType({
@@ -7485,7 +7501,8 @@ const SearchFieldsSchema = z.object({
7485
7501
  anyWords: z.string().default(''),
7486
7502
  noneWords: z.string().default(''),
7487
7503
  exactPhrase: z.string().default(''),
7488
- titleSearch: z.string().default(''),
7504
+ titleSearch: z.string().default(''), // AND logic for titles
7505
+ titleAny: z.string().default(''), // OR logic for titles
7489
7506
  skillsSearch: z.string().default(''),
7490
7507
  });
7491
7508
  class SearchQueryBuilder {
@@ -7526,17 +7543,15 @@ class SearchQueryBuilder {
7526
7543
  if (validatedFields.exactPhrase.trim()) {
7527
7544
  parts.push(`"${validatedFields.exactPhrase.trim()}"`);
7528
7545
  }
7529
- // Field-specific searches - now support phrases too
7546
+ // Title searches with proper AND/OR logic
7530
7547
  if (validatedFields.titleSearch.trim()) {
7531
7548
  const titleTerms = this.splitTerms(validatedFields.titleSearch);
7532
7549
  if (titleTerms.length === 1) {
7533
- // Single term or phrase
7534
7550
  const term = titleTerms[0];
7535
7551
  const isQuoted = term.startsWith('"') && term.endsWith('"');
7536
7552
  parts.push(isQuoted ? `title:${term}` : `title:"${term}"`);
7537
7553
  }
7538
7554
  else {
7539
- // Multiple terms - each gets title: prefix
7540
7555
  const titleParts = titleTerms.map((term) => {
7541
7556
  const isQuoted = term.startsWith('"') && term.endsWith('"');
7542
7557
  return isQuoted ? `title:${term}` : `title:"${term}"`;
@@ -7544,6 +7559,21 @@ class SearchQueryBuilder {
7544
7559
  parts.push(`(${titleParts.join(' AND ')})`);
7545
7560
  }
7546
7561
  }
7562
+ if (validatedFields.titleAny.trim()) {
7563
+ const titleTerms = this.splitTerms(validatedFields.titleAny);
7564
+ if (titleTerms.length === 1) {
7565
+ const term = titleTerms[0];
7566
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
7567
+ parts.push(isQuoted ? `title:${term}` : `title:"${term}"`);
7568
+ }
7569
+ else {
7570
+ const titleParts = titleTerms.map((term) => {
7571
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
7572
+ return isQuoted ? `title:${term}` : `title:"${term}"`;
7573
+ });
7574
+ parts.push(`(${titleParts.join(' OR ')})`);
7575
+ }
7576
+ }
7547
7577
  if (validatedFields.skillsSearch.trim()) {
7548
7578
  const skillsTerms = this.splitTerms(validatedFields.skillsSearch);
7549
7579
  if (skillsTerms.length === 1) {
@@ -7576,7 +7606,9 @@ class SearchQueryBuilder {
7576
7606
  if (validatedFields.exactPhrase)
7577
7607
  descriptions.push(`Exact phrase: "${validatedFields.exactPhrase}"`);
7578
7608
  if (validatedFields.titleSearch)
7579
- descriptions.push(`In title: ${validatedFields.titleSearch}`);
7609
+ descriptions.push(`Title (all): ${validatedFields.titleSearch}`);
7610
+ if (validatedFields.titleAny)
7611
+ descriptions.push(`Title (any): ${validatedFields.titleAny}`);
7580
7612
  if (validatedFields.skillsSearch)
7581
7613
  descriptions.push(`Skills: ${validatedFields.skillsSearch}`);
7582
7614
  return descriptions.length > 0 ? descriptions.join(' • ') : 'All results';
@@ -7594,24 +7626,6 @@ class SearchQueryBuilder {
7594
7626
  errors: result.error.errors.map((err) => `${err.path.join('.')}: ${err.message}`),
7595
7627
  };
7596
7628
  }
7597
- /**
7598
- * Test/demo method to show phrase handling
7599
- * Remove this in production
7600
- */
7601
- static examples() {
7602
- const testFields = {
7603
- allWords: 'react "senior developer" javascript',
7604
- anyWords: 'frontend "full stack" backend',
7605
- noneWords: 'junior "entry level"',
7606
- exactPhrase: 'tech lead',
7607
- titleSearch: 'software engineer',
7608
- skillsSearch: 'node.js',
7609
- };
7610
- console.log('Query:', this.buildQuery(testFields));
7611
- console.log('Description:', this.describe(testFields));
7612
- // Should produce:
7613
- // 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"
7614
- }
7615
7629
  /**
7616
7630
  * Parse a query string back into SearchFields structure
7617
7631
  * Fixed to handle grouped NOT expressions correctly
@@ -7623,13 +7637,40 @@ class SearchQueryBuilder {
7623
7637
  noneWords: '',
7624
7638
  exactPhrase: '',
7625
7639
  titleSearch: '',
7640
+ titleAny: '',
7626
7641
  skillsSearch: '',
7627
7642
  };
7628
7643
  if (!query || query.trim() === '*') {
7629
7644
  return result;
7630
7645
  }
7631
7646
  let remainingQuery = query.trim();
7632
- // 1. Extract field-specific searches first
7647
+ // 1. FIRST: Extract grouped expressions like (title:"a" OR title:"b") or (title:"a" AND title:"b")
7648
+ const titleGroupPattern = /\((title:"[^"]+"(?:\s+(?:OR|AND)\s+title:"[^"]+")+)\)/g;
7649
+ const titleGroupMatches = [...remainingQuery.matchAll(titleGroupPattern)];
7650
+ for (const match of titleGroupMatches) {
7651
+ const groupContent = match[1]; // e.g., 'title:"developer" OR title:"expert"'
7652
+ if (groupContent.includes(' OR ')) {
7653
+ // Extract terms from OR group for titleAny
7654
+ const terms = groupContent
7655
+ .split(/\s+OR\s+/)
7656
+ .map((term) => term.replace(/^title:"([^"]+)"$/, '"$1"'))
7657
+ .filter(Boolean);
7658
+ result.titleAny = terms.join(' ');
7659
+ }
7660
+ else if (groupContent.includes(' AND ')) {
7661
+ // Extract terms from AND group for titleSearch
7662
+ const terms = groupContent
7663
+ .split(/\s+AND\s+/)
7664
+ .map((term) => term.replace(/^title:"([^"]+)"$/, '"$1"'))
7665
+ .filter(Boolean);
7666
+ result.titleSearch = result.titleSearch
7667
+ ? `${result.titleSearch} ${terms.join(' ')}`
7668
+ : terms.join(' ');
7669
+ }
7670
+ // Remove the matched group from remaining query
7671
+ remainingQuery = remainingQuery.replace(match[0], '').trim();
7672
+ }
7673
+ // 2. THEN: Extract individual title: and skills: patterns
7633
7674
  const fieldPatterns = [
7634
7675
  { field: 'titleSearch', pattern: /title:("([^"]+)"|([^\s)]+))/g },
7635
7676
  { field: 'skillsSearch', pattern: /skills:("([^"]+)"|([^\s)]+))/g },
@@ -7643,21 +7684,46 @@ class SearchQueryBuilder {
7643
7684
  }
7644
7685
  return match[3];
7645
7686
  });
7646
- result[field] = terms.join(' ');
7687
+ if (field === 'titleSearch') {
7688
+ result.titleSearch = result.titleSearch
7689
+ ? `${result.titleSearch} ${terms.join(' ')}`
7690
+ : terms.join(' ');
7691
+ }
7692
+ else {
7693
+ result[field] = terms.join(' ');
7694
+ }
7647
7695
  remainingQuery = remainingQuery.replace(pattern, '').trim();
7648
7696
  }
7649
7697
  }
7650
- // 2. Extract grouped field searches like title:(term1 AND term2)
7698
+ // 3. Handle legacy grouped field searches like title:(term1 AND term2)
7651
7699
  const groupedFieldPattern = /(title|skills):\(([^)]+)\)/g;
7652
7700
  let groupMatch;
7653
7701
  while ((groupMatch = groupedFieldPattern.exec(remainingQuery)) !== null) {
7654
- const fieldName = groupMatch[1] === 'title' ? 'titleSearch' : 'skillsSearch';
7702
+ const fieldType = groupMatch[1];
7655
7703
  const groupContent = groupMatch[2];
7656
- const terms = this.extractTermsFromGroup(groupContent, groupMatch[1]);
7657
- result[fieldName] = terms.join(' ');
7704
+ if (fieldType === 'title') {
7705
+ // Check if it's OR logic (titleAny) or AND logic (titleSearch)
7706
+ if (groupContent.includes(' OR ')) {
7707
+ const terms = this.extractTermsFromGroup(groupContent, fieldType);
7708
+ result.titleAny = result.titleAny
7709
+ ? `${result.titleAny} ${terms.join(' ')}`
7710
+ : terms.join(' ');
7711
+ }
7712
+ else {
7713
+ const terms = this.extractTermsFromGroup(groupContent, fieldType);
7714
+ result.titleSearch = result.titleSearch
7715
+ ? `${result.titleSearch} ${terms.join(' ')}`
7716
+ : terms.join(' ');
7717
+ }
7718
+ }
7719
+ else {
7720
+ // skills logic remains the same
7721
+ const terms = this.extractTermsFromGroup(groupContent, fieldType);
7722
+ result.skillsSearch = terms.join(' ');
7723
+ }
7658
7724
  remainingQuery = remainingQuery.replace(groupMatch[0], '').trim();
7659
7725
  }
7660
- // 3. **NEW** - Extract grouped NOT expressions FIRST: NOT (term1 OR term2 OR ...)
7726
+ // 4. Extract grouped NOT expressions: NOT (term1 OR term2 OR ...)
7661
7727
  const groupedNotPattern = /NOT\s+\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
7662
7728
  const groupedNotMatches = [...remainingQuery.matchAll(groupedNotPattern)];
7663
7729
  if (groupedNotMatches.length > 0) {
@@ -7667,7 +7733,7 @@ class SearchQueryBuilder {
7667
7733
  .replace(groupedNotMatches[0][0], '')
7668
7734
  .trim();
7669
7735
  }
7670
- // 4. Extract individual NOT terms (only if no grouped NOT was found)
7736
+ // 5. Extract individual NOT terms (only if no grouped NOT was found)
7671
7737
  if (!result.noneWords) {
7672
7738
  const notPattern = /NOT\s+("([^"]+)"|([^\s)]+))/g;
7673
7739
  const notMatches = [...remainingQuery.matchAll(notPattern)];
@@ -7682,7 +7748,7 @@ class SearchQueryBuilder {
7682
7748
  remainingQuery = remainingQuery.replace(notPattern, '').trim();
7683
7749
  }
7684
7750
  }
7685
- // 5. Process grouped expressions - DON'T clean up connectors first!
7751
+ // 6. Process grouped expressions - DON'T clean up connectors first!
7686
7752
  // Extract OR groups (anyWords) - PROCESS FIRST
7687
7753
  const orGroupPattern = /\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
7688
7754
  const orMatches = [...remainingQuery.matchAll(orGroupPattern)];
@@ -7701,14 +7767,14 @@ class SearchQueryBuilder {
7701
7767
  }
7702
7768
  // NOW clean up connectors after group processing
7703
7769
  remainingQuery = this.cleanupConnectors(remainingQuery);
7704
- // 6. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
7770
+ // 7. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
7705
7771
  const standaloneQuotePattern = /(?:^|\s)("([^"]+)")(?=\s|$)/g;
7706
7772
  const quoteMatches = [...remainingQuery.matchAll(standaloneQuotePattern)];
7707
7773
  if (quoteMatches.length > 0) {
7708
7774
  result.exactPhrase = quoteMatches[0][2];
7709
7775
  remainingQuery = remainingQuery.replace(quoteMatches[0][1], '').trim();
7710
7776
  }
7711
- // 7. Handle remaining simple terms as allWords
7777
+ // 8. Handle remaining simple terms as allWords
7712
7778
  if (remainingQuery) {
7713
7779
  const remainingTerms = this.splitTermsWithQuotes(remainingQuery);
7714
7780
  if (remainingTerms.length > 0) {
@@ -7791,6 +7857,7 @@ class SearchQueryBuilder {
7791
7857
  return query
7792
7858
  .replace(/\s+AND\s+/g, ' ')
7793
7859
  .replace(/\s+/g, ' ')
7860
+ .replace(/\(\s*\)/g, '')
7794
7861
  .trim();
7795
7862
  }
7796
7863
  /**
@@ -24029,6 +24096,8 @@ exports.getCampaignLeadsResponseSchema = getCampaignLeadsResponseSchema;
24029
24096
  exports.getCampaignLeadsStatusEnum = getCampaignLeadsStatusEnum;
24030
24097
  exports.getMultiloginBrowserException = getMultiloginBrowserException;
24031
24098
  exports.getNextStatus = getNextStatus;
24099
+ exports.getOrganizationLeadsRequestQuerySchema = getOrganizationLeadsRequestQuerySchema;
24100
+ exports.getOrganizationLeadsStatusEnum = getOrganizationLeadsStatusEnum;
24032
24101
  exports.getPreviousStatus = getPreviousStatus;
24033
24102
  exports.getRouteWithoutAdminPrefix = getRouteWithoutAdminPrefix;
24034
24103
  exports.getSamplesRequestSchema = getSamplesRequestSchema;