lancer-shared 1.2.260 → 1.2.262

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.
@@ -6727,6 +6727,7 @@ const leadStatusEnum = z.enum([
6727
6727
  'alreadyBiddedOn',
6728
6728
  'viewed',
6729
6729
  'replied',
6730
+ 'biddingProcessing',
6730
6731
  'won',
6731
6732
  ]);
6732
6733
  const updateLeadStatusSchema = z.object({
@@ -6747,6 +6748,29 @@ const questionAnswerPairSchema = z.object({
6747
6748
  question: z.string(),
6748
6749
  answer: z.string(),
6749
6750
  });
6751
+ const leadBiddingConfigSchema = z.object({
6752
+ appliedFromQueue: z.boolean().nullable(),
6753
+ biddingDelayInMinutes: z.number().nullable(),
6754
+ bidWithWarning: z.enum(['bid', 'skip']),
6755
+ biddingHourlyRateStrategy: z.enum([
6756
+ 'match_job_budget',
6757
+ 'match_profile_rate',
6758
+ 'fixed_rate',
6759
+ ]),
6760
+ biddingHourlyRatePercentage: z.number().nullable(),
6761
+ biddingFixedHourlyRate: z.number().nullable(),
6762
+ boostingEnabled: z.boolean().nullable(),
6763
+ boostDownToNthPlace: z.number().nullable(),
6764
+ connectsAbovePrevious: z.number().nullable(),
6765
+ maximumBoost: z.number().nullable(),
6766
+ minBoost: z.number().nullable(),
6767
+ insufficeintBoostConnectsAction: z.enum(['skip', 'bid_without_boost']),
6768
+ bidConfig: z.object({
6769
+ agencyName: z.string().nullable(),
6770
+ contractorName: z.string().nullable(),
6771
+ specialisedProfile: z.string().nullable(),
6772
+ }),
6773
+ });
6750
6774
  const leadSchema = upworkJobSchema
6751
6775
  .extend({
6752
6776
  jobId: stringType(),
@@ -6770,12 +6794,14 @@ const leadSchema = upworkJobSchema
6770
6794
  biddingTaskScheduled: booleanType().nullable(),
6771
6795
  scheduledBiddingTime: numberType().nullable(),
6772
6796
  inQueue: booleanType().nullable(),
6797
+ biddingDelayInMinutes: numberType().nullable(),
6798
+ checkFeedbackStatusCreatedAt: numberType().nullable(),
6773
6799
  wonAmount: numberType().optional(),
6774
6800
  feedbackCheckTaskId: stringType().nullable(),
6775
6801
  bidDecision: z.enum(['proceeded', 'rejected']).nullable(),
6776
6802
  rejectedFeedback: stringType().nullable(),
6777
6803
  applicationId: stringType().nullable(),
6778
- campaignName: stringType().optional(),
6804
+ leadBiddingConfig: leadBiddingConfigSchema.nullable(),
6779
6805
  })
6780
6806
  .omit({
6781
6807
  processed: true,
@@ -6814,6 +6840,7 @@ const getCampaignLeadsRequestQuerySchema = z.object({
6814
6840
  limit: z.number().default(20).optional(),
6815
6841
  status: getCampaignLeadsStatusEnum.optional(),
6816
6842
  campaignId: z.string().optional(),
6843
+ inQueue: z.boolean().optional(),
6817
6844
  });
6818
6845
  const getCampaignLeadsResponseSchema = z.object({
6819
6846
  data: z.array(leadSchema),
@@ -6853,6 +6880,7 @@ const agentGenerateProposalRequestSchema = z.object({
6853
6880
  userId: z.string().nullable(),
6854
6881
  organizationId: z.string(),
6855
6882
  campaignId: z.string(),
6883
+ coverLetterTemplateId: z.string().optional(),
6856
6884
  job: z.object({
6857
6885
  leadId: z.string(),
6858
6886
  jobId: z.string(),
@@ -6998,6 +7026,21 @@ const onboardingProgressSchema = z.object({
6998
7026
  startCampaign: z.boolean(),
6999
7027
  });
7000
7028
 
7029
+ const getOrganizationLeadsStatusEnum = z.enum([
7030
+ 'all',
7031
+ 'suitable',
7032
+ 'contacted',
7033
+ 'viewed',
7034
+ 'replied',
7035
+ ]);
7036
+ const getOrganizationLeadsRequestQuerySchema = z.object({
7037
+ cursor: z.string().optional(),
7038
+ limit: z.number().default(20).optional(),
7039
+ status: getOrganizationLeadsStatusEnum.optional(),
7040
+ campaignId: z.string().optional(),
7041
+ inQueue: z.boolean().optional(),
7042
+ });
7043
+
7001
7044
  const organizationTypeSchema = z.enum(['agency', 'freelancer']);
7002
7045
  const organizationTierEnum = z.enum(['free', 'premium']);
7003
7046
  const limitsSchema = objectType({
@@ -7357,6 +7400,7 @@ const updateCampaignAnalyticsSchema = z.object({
7357
7400
  'suitableJobs',
7358
7401
  'unsuitableJobs',
7359
7402
  'wonAmount',
7403
+ 'biddingProcessing',
7360
7404
  ])),
7361
7405
  });
7362
7406
 
@@ -7485,7 +7529,8 @@ const SearchFieldsSchema = z.object({
7485
7529
  anyWords: z.string().default(''),
7486
7530
  noneWords: z.string().default(''),
7487
7531
  exactPhrase: z.string().default(''),
7488
- titleSearch: z.string().default(''),
7532
+ titleSearch: z.string().default(''), // AND logic for titles
7533
+ titleAny: z.string().default(''), // OR logic for titles
7489
7534
  skillsSearch: z.string().default(''),
7490
7535
  });
7491
7536
  class SearchQueryBuilder {
@@ -7526,17 +7571,15 @@ class SearchQueryBuilder {
7526
7571
  if (validatedFields.exactPhrase.trim()) {
7527
7572
  parts.push(`"${validatedFields.exactPhrase.trim()}"`);
7528
7573
  }
7529
- // Field-specific searches - now support phrases too
7574
+ // Title searches with proper AND/OR logic
7530
7575
  if (validatedFields.titleSearch.trim()) {
7531
7576
  const titleTerms = this.splitTerms(validatedFields.titleSearch);
7532
7577
  if (titleTerms.length === 1) {
7533
- // Single term or phrase
7534
7578
  const term = titleTerms[0];
7535
7579
  const isQuoted = term.startsWith('"') && term.endsWith('"');
7536
7580
  parts.push(isQuoted ? `title:${term}` : `title:"${term}"`);
7537
7581
  }
7538
7582
  else {
7539
- // Multiple terms - each gets title: prefix
7540
7583
  const titleParts = titleTerms.map((term) => {
7541
7584
  const isQuoted = term.startsWith('"') && term.endsWith('"');
7542
7585
  return isQuoted ? `title:${term}` : `title:"${term}"`;
@@ -7544,6 +7587,21 @@ class SearchQueryBuilder {
7544
7587
  parts.push(`(${titleParts.join(' AND ')})`);
7545
7588
  }
7546
7589
  }
7590
+ if (validatedFields.titleAny.trim()) {
7591
+ const titleTerms = this.splitTerms(validatedFields.titleAny);
7592
+ if (titleTerms.length === 1) {
7593
+ const term = titleTerms[0];
7594
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
7595
+ parts.push(isQuoted ? `title:${term}` : `title:"${term}"`);
7596
+ }
7597
+ else {
7598
+ const titleParts = titleTerms.map((term) => {
7599
+ const isQuoted = term.startsWith('"') && term.endsWith('"');
7600
+ return isQuoted ? `title:${term}` : `title:"${term}"`;
7601
+ });
7602
+ parts.push(`(${titleParts.join(' OR ')})`);
7603
+ }
7604
+ }
7547
7605
  if (validatedFields.skillsSearch.trim()) {
7548
7606
  const skillsTerms = this.splitTerms(validatedFields.skillsSearch);
7549
7607
  if (skillsTerms.length === 1) {
@@ -7576,7 +7634,9 @@ class SearchQueryBuilder {
7576
7634
  if (validatedFields.exactPhrase)
7577
7635
  descriptions.push(`Exact phrase: "${validatedFields.exactPhrase}"`);
7578
7636
  if (validatedFields.titleSearch)
7579
- descriptions.push(`In title: ${validatedFields.titleSearch}`);
7637
+ descriptions.push(`Title (all): ${validatedFields.titleSearch}`);
7638
+ if (validatedFields.titleAny)
7639
+ descriptions.push(`Title (any): ${validatedFields.titleAny}`);
7580
7640
  if (validatedFields.skillsSearch)
7581
7641
  descriptions.push(`Skills: ${validatedFields.skillsSearch}`);
7582
7642
  return descriptions.length > 0 ? descriptions.join(' • ') : 'All results';
@@ -7594,24 +7654,6 @@ class SearchQueryBuilder {
7594
7654
  errors: result.error.errors.map((err) => `${err.path.join('.')}: ${err.message}`),
7595
7655
  };
7596
7656
  }
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
7657
  /**
7616
7658
  * Parse a query string back into SearchFields structure
7617
7659
  * Fixed to handle grouped NOT expressions correctly
@@ -7623,13 +7665,40 @@ class SearchQueryBuilder {
7623
7665
  noneWords: '',
7624
7666
  exactPhrase: '',
7625
7667
  titleSearch: '',
7668
+ titleAny: '',
7626
7669
  skillsSearch: '',
7627
7670
  };
7628
7671
  if (!query || query.trim() === '*') {
7629
7672
  return result;
7630
7673
  }
7631
7674
  let remainingQuery = query.trim();
7632
- // 1. Extract field-specific searches first
7675
+ // 1. FIRST: Extract grouped expressions like (title:"a" OR title:"b") or (title:"a" AND title:"b")
7676
+ const titleGroupPattern = /\((title:"[^"]+"(?:\s+(?:OR|AND)\s+title:"[^"]+")+)\)/g;
7677
+ const titleGroupMatches = [...remainingQuery.matchAll(titleGroupPattern)];
7678
+ for (const match of titleGroupMatches) {
7679
+ const groupContent = match[1]; // e.g., 'title:"developer" OR title:"expert"'
7680
+ if (groupContent.includes(' OR ')) {
7681
+ // Extract terms from OR group for titleAny
7682
+ const terms = groupContent
7683
+ .split(/\s+OR\s+/)
7684
+ .map((term) => term.replace(/^title:"([^"]+)"$/, '"$1"'))
7685
+ .filter(Boolean);
7686
+ result.titleAny = terms.join(' ');
7687
+ }
7688
+ else if (groupContent.includes(' AND ')) {
7689
+ // Extract terms from AND group for titleSearch
7690
+ const terms = groupContent
7691
+ .split(/\s+AND\s+/)
7692
+ .map((term) => term.replace(/^title:"([^"]+)"$/, '"$1"'))
7693
+ .filter(Boolean);
7694
+ result.titleSearch = result.titleSearch
7695
+ ? `${result.titleSearch} ${terms.join(' ')}`
7696
+ : terms.join(' ');
7697
+ }
7698
+ // Remove the matched group from remaining query
7699
+ remainingQuery = remainingQuery.replace(match[0], '').trim();
7700
+ }
7701
+ // 2. THEN: Extract individual title: and skills: patterns
7633
7702
  const fieldPatterns = [
7634
7703
  { field: 'titleSearch', pattern: /title:("([^"]+)"|([^\s)]+))/g },
7635
7704
  { field: 'skillsSearch', pattern: /skills:("([^"]+)"|([^\s)]+))/g },
@@ -7643,21 +7712,46 @@ class SearchQueryBuilder {
7643
7712
  }
7644
7713
  return match[3];
7645
7714
  });
7646
- result[field] = terms.join(' ');
7715
+ if (field === 'titleSearch') {
7716
+ result.titleSearch = result.titleSearch
7717
+ ? `${result.titleSearch} ${terms.join(' ')}`
7718
+ : terms.join(' ');
7719
+ }
7720
+ else {
7721
+ result[field] = terms.join(' ');
7722
+ }
7647
7723
  remainingQuery = remainingQuery.replace(pattern, '').trim();
7648
7724
  }
7649
7725
  }
7650
- // 2. Extract grouped field searches like title:(term1 AND term2)
7726
+ // 3. Handle legacy grouped field searches like title:(term1 AND term2)
7651
7727
  const groupedFieldPattern = /(title|skills):\(([^)]+)\)/g;
7652
7728
  let groupMatch;
7653
7729
  while ((groupMatch = groupedFieldPattern.exec(remainingQuery)) !== null) {
7654
- const fieldName = groupMatch[1] === 'title' ? 'titleSearch' : 'skillsSearch';
7730
+ const fieldType = groupMatch[1];
7655
7731
  const groupContent = groupMatch[2];
7656
- const terms = this.extractTermsFromGroup(groupContent, groupMatch[1]);
7657
- result[fieldName] = terms.join(' ');
7732
+ if (fieldType === 'title') {
7733
+ // Check if it's OR logic (titleAny) or AND logic (titleSearch)
7734
+ if (groupContent.includes(' OR ')) {
7735
+ const terms = this.extractTermsFromGroup(groupContent, fieldType);
7736
+ result.titleAny = result.titleAny
7737
+ ? `${result.titleAny} ${terms.join(' ')}`
7738
+ : terms.join(' ');
7739
+ }
7740
+ else {
7741
+ const terms = this.extractTermsFromGroup(groupContent, fieldType);
7742
+ result.titleSearch = result.titleSearch
7743
+ ? `${result.titleSearch} ${terms.join(' ')}`
7744
+ : terms.join(' ');
7745
+ }
7746
+ }
7747
+ else {
7748
+ // skills logic remains the same
7749
+ const terms = this.extractTermsFromGroup(groupContent, fieldType);
7750
+ result.skillsSearch = terms.join(' ');
7751
+ }
7658
7752
  remainingQuery = remainingQuery.replace(groupMatch[0], '').trim();
7659
7753
  }
7660
- // 3. **NEW** - Extract grouped NOT expressions FIRST: NOT (term1 OR term2 OR ...)
7754
+ // 4. Extract grouped NOT expressions: NOT (term1 OR term2 OR ...)
7661
7755
  const groupedNotPattern = /NOT\s+\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
7662
7756
  const groupedNotMatches = [...remainingQuery.matchAll(groupedNotPattern)];
7663
7757
  if (groupedNotMatches.length > 0) {
@@ -7667,7 +7761,7 @@ class SearchQueryBuilder {
7667
7761
  .replace(groupedNotMatches[0][0], '')
7668
7762
  .trim();
7669
7763
  }
7670
- // 4. Extract individual NOT terms (only if no grouped NOT was found)
7764
+ // 5. Extract individual NOT terms (only if no grouped NOT was found)
7671
7765
  if (!result.noneWords) {
7672
7766
  const notPattern = /NOT\s+("([^"]+)"|([^\s)]+))/g;
7673
7767
  const notMatches = [...remainingQuery.matchAll(notPattern)];
@@ -7682,7 +7776,7 @@ class SearchQueryBuilder {
7682
7776
  remainingQuery = remainingQuery.replace(notPattern, '').trim();
7683
7777
  }
7684
7778
  }
7685
- // 5. Process grouped expressions - DON'T clean up connectors first!
7779
+ // 6. Process grouped expressions - DON'T clean up connectors first!
7686
7780
  // Extract OR groups (anyWords) - PROCESS FIRST
7687
7781
  const orGroupPattern = /\(([^)]+(?:\s+OR\s+[^)]+)+)\)/g;
7688
7782
  const orMatches = [...remainingQuery.matchAll(orGroupPattern)];
@@ -7701,14 +7795,14 @@ class SearchQueryBuilder {
7701
7795
  }
7702
7796
  // NOW clean up connectors after group processing
7703
7797
  remainingQuery = this.cleanupConnectors(remainingQuery);
7704
- // 6. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
7798
+ // 7. Extract standalone quoted phrases (exactPhrase) - ONLY after all groups processed
7705
7799
  const standaloneQuotePattern = /(?:^|\s)("([^"]+)")(?=\s|$)/g;
7706
7800
  const quoteMatches = [...remainingQuery.matchAll(standaloneQuotePattern)];
7707
7801
  if (quoteMatches.length > 0) {
7708
7802
  result.exactPhrase = quoteMatches[0][2];
7709
7803
  remainingQuery = remainingQuery.replace(quoteMatches[0][1], '').trim();
7710
7804
  }
7711
- // 7. Handle remaining simple terms as allWords
7805
+ // 8. Handle remaining simple terms as allWords
7712
7806
  if (remainingQuery) {
7713
7807
  const remainingTerms = this.splitTermsWithQuotes(remainingQuery);
7714
7808
  if (remainingTerms.length > 0) {
@@ -7791,6 +7885,7 @@ class SearchQueryBuilder {
7791
7885
  return query
7792
7886
  .replace(/\s+AND\s+/g, ' ')
7793
7887
  .replace(/\s+/g, ' ')
7888
+ .replace(/\(\s*\)/g, '')
7794
7889
  .trim();
7795
7890
  }
7796
7891
  /**
@@ -8686,6 +8781,7 @@ const LogEventTypeEnum = z.enum([
8686
8781
  'acceptInvitationFailed',
8687
8782
  'syncProposalsStatusCompleted',
8688
8783
  'syncProposalsStatusFailed',
8784
+ 'scheduleBidding',
8689
8785
  // System/Generic Events
8690
8786
  'errorLogged',
8691
8787
  'cloudTaskRetry',
@@ -8780,6 +8876,11 @@ const leadStatusEventMetadata = objectType({
8780
8876
  const biddingRejectedWithFeedbackEventMetadata = objectType({
8781
8877
  feedback: z.string(),
8782
8878
  });
8879
+ const scheduleBiddingEventMetadataSchema = objectType({
8880
+ organizationId: z.string(),
8881
+ campaignId: z.string(),
8882
+ leadId: z.string(),
8883
+ });
8783
8884
  const suitabilityPendingEventMetadataSchema = objectType({
8784
8885
  jobId: z.string(),
8785
8886
  jobUrl: z.string(),
@@ -15149,6 +15250,7 @@ const ROUTES = {
15149
15250
  SEARCH: (organizationId, campaignId) => `organizations/${organizationId}/campaigns/${campaignId}/leads/search`,
15150
15251
  GENERATE_COUNTS: (organizationId, campaignId) => `organizations/${organizationId}/campaigns/${campaignId}/leads/generate-counts`,
15151
15252
  REJECTED: (organizationId, campaignId) => `organizations/${organizationId}/campaigns/${campaignId}/leads/rejected`,
15253
+ SCHEDULE_BIDDING: (organizationId, campaignId, leadId) => `organizations/${organizationId}/campaigns/${campaignId}/leads/${leadId}/schedule-bidding`,
15152
15254
  },
15153
15255
  ANALYTICS: (organizationId, campaignId) => `organizations/${organizationId}/campaigns/${campaignId}/analytics`,
15154
15256
  TOTAL_STATS: (organizationId, campaignId) => `organizations/${organizationId}/campaigns/${campaignId}/analytics/totals`,
@@ -24029,6 +24131,8 @@ exports.getCampaignLeadsResponseSchema = getCampaignLeadsResponseSchema;
24029
24131
  exports.getCampaignLeadsStatusEnum = getCampaignLeadsStatusEnum;
24030
24132
  exports.getMultiloginBrowserException = getMultiloginBrowserException;
24031
24133
  exports.getNextStatus = getNextStatus;
24134
+ exports.getOrganizationLeadsRequestQuerySchema = getOrganizationLeadsRequestQuerySchema;
24135
+ exports.getOrganizationLeadsStatusEnum = getOrganizationLeadsStatusEnum;
24032
24136
  exports.getPreviousStatus = getPreviousStatus;
24033
24137
  exports.getRouteWithoutAdminPrefix = getRouteWithoutAdminPrefix;
24034
24138
  exports.getSamplesRequestSchema = getSamplesRequestSchema;
@@ -24073,6 +24177,7 @@ exports.jobStatusOrder = jobStatusOrder;
24073
24177
  exports.labelEnum = labelEnum;
24074
24178
  exports.lancerBiddingExceptionEventMetadata = lancerBiddingExceptionEventMetadata;
24075
24179
  exports.leadAnalysisActivitySchema = leadAnalysisActivitySchema;
24180
+ exports.leadBiddingConfigSchema = leadBiddingConfigSchema;
24076
24181
  exports.leadResponseSchema = leadResponseSchema;
24077
24182
  exports.leadSchema = leadSchema;
24078
24183
  exports.leadStatusActivitySchema = leadStatusActivitySchema;
@@ -24157,6 +24262,7 @@ exports.requiredEarningsEnum = requiredEarningsEnum;
24157
24262
  exports.requiredJSSEnum = requiredJSSEnum;
24158
24263
  exports.sampleSchema = sampleSchema;
24159
24264
  exports.savedSearchSchema = savedSearchSchema;
24265
+ exports.scheduleBiddingEventMetadataSchema = scheduleBiddingEventMetadataSchema;
24160
24266
  exports.scrapeJobActivityPayloadSchema = scrapeJobActivityPayloadSchema;
24161
24267
  exports.scrapeJobPayloadSchema = scrapeJobPayloadSchema;
24162
24268
  exports.scrapeJobsCompletedEventMetadata = scrapeJobsCompletedEventMetadata;