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