UNPKG

@lineai/gov-deals

Version:

Explore Federal contracts for government building renovations, city hall renovations, courthouse updates, library modernizations, federal building improvement contracts, base housing and facilities upgrades.

310 lines 29.7 kB
/** * SAM.gov Opportunities endpoint */ import { ValidationError } from '../../../core/errors'; import { SamOpportunitySearchFiltersSchema, SamOpportunitySearchResponseSchema, } from '../../../types/opportunities'; // US States and territories for search guidance export const US_STATE_NAMES = [ 'alabama', 'alaska', 'arizona', 'arkansas', 'california', 'colorado', 'connecticut', 'delaware', 'florida', 'georgia', 'hawaii', 'idaho', 'illinois', 'indiana', 'iowa', 'kansas', 'kentucky', 'louisiana', 'maine', 'maryland', 'massachusetts', 'michigan', 'minnesota', 'mississippi', 'missouri', 'montana', 'nebraska', 'nevada', 'new hampshire', 'new jersey', 'new mexico', 'new york', 'north carolina', 'north dakota', 'ohio', 'oklahoma', 'oregon', 'pennsylvania', 'rhode island', 'south carolina', 'south dakota', 'tennessee', 'texas', 'utah', 'vermont', 'virginia', 'washington', 'west virginia', 'wisconsin', 'wyoming', 'puerto rico', 'district of columbia', 'american samoa', 'guam', 'northern mariana islands', 'us virgin islands' ]; export const US_STATE_CODES = [ 'al', 'ak', 'az', 'ar', 'ca', 'co', 'ct', 'de', 'fl', 'ga', 'hi', 'id', 'il', 'in', 'ia', 'ks', 'ky', 'la', 'me', 'md', 'ma', 'mi', 'mn', 'ms', 'mo', 'mt', 'ne', 'nv', 'nh', 'nj', 'nm', 'ny', 'nc', 'nd', 'oh', 'ok', 'or', 'pa', 'ri', 'sc', 'sd', 'tn', 'tx', 'ut', 'vt', 'va', 'wa', 'wv', 'wi', 'wy', 'pr', 'dc', 'as', 'gu', 'mp', 'vi', 'ap', 'ae', 'aa' ]; export class OpportunitiesEndpoint { client; constructor(client) { this.client = client; } /** * Search for opportunities */ async search(filters, pagination) { // Validate filters if provided if (filters) { const result = SamOpportunitySearchFiltersSchema.safeParse(filters); if (!result.success) { throw new ValidationError('Invalid search filters', result.error); } } // Build query parameters const params = { limit: pagination?.limit || 100, page: pagination?.page || 1, ...this.buildSearchParams(filters), }; // Make the API request const response = await this.client.get('/opportunities/v2/search', params); // Validate and transform response return this.transformSearchResponse(response, filters); } /** * Search for construction opportunities specifically */ async searchConstruction(additionalFilters, pagination) { const constructionFilters = { naicsCodes: ['236220', '236210', '238210', '238220'], keywords: 'renovation construction building modernization', ...additionalFilters, }; return this.search(constructionFilters, pagination); } /** * Build search parameters for the API */ buildSearchParams(filters) { const params = {}; // SAM.gov API requires PostedFrom and PostedTo - set defaults if not provided // API expects MM/dd/yyyy format if (filters?.postedFrom) { params.postedFrom = this.formatDateForApi(filters.postedFrom); } else { // Default to 30 days ago if not specified const thirtyDaysAgo = new Date(); thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); params.postedFrom = this.formatDateForApi(thirtyDaysAgo.toISOString().split('T')[0]); } if (filters?.postedTo) { params.postedTo = this.formatDateForApi(filters.postedTo); } else { // Default to today if not specified params.postedTo = this.formatDateForApi(new Date().toISOString().split('T')[0]); } if (!filters) return params; // Basic filters if (filters.keywords) params.title = filters.keywords; // API uses 'title' parameter if (filters.naicsCodes?.length) params.ncode = filters.naicsCodes.join(','); // API uses 'ncode' parameter if (filters.pscCodes?.length) params.ccode = filters.pscCodes.join(','); // API uses 'ccode' parameter if (filters.types?.length) params.ptype = filters.types.join(','); // API uses 'ptype' if (filters.setAsideTypes?.length) params.typeOfSetAside = filters.setAsideTypes.join(','); // Response deadline filters if (filters.responseDeadlineFrom) params.rdlFrom = this.formatDateForApi(filters.responseDeadlineFrom); if (filters.responseDeadlineTo) params.rdlTo = this.formatDateForApi(filters.responseDeadlineTo); // Location filters if (filters.placeOfPerformanceStates?.length) params.state = filters.placeOfPerformanceStates.join(','); if (filters.placeOfPerformanceZips?.length) params.zip = filters.placeOfPerformanceZips.join(','); // Status filter if (filters.activeOnly !== undefined) params.active = filters.activeOnly ? 'true' : 'false'; return params; } /** * Format date from YYYY-MM-DD to MM/dd/yyyy for SAM.gov API */ formatDateForApi(dateString) { const date = new Date(dateString); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); const year = date.getFullYear(); return `${month}/${day}/${year}`; } /** * Transform API response to our schema * Based on actual SAM.gov API structure */ transformSearchResponse(apiResponse, filters) { // Validate the raw response matches expected structure const result = SamOpportunitySearchResponseSchema.safeParse(apiResponse); if (!result.success) { console.error('Validation errors:', JSON.stringify(result.error.errors, null, 2)); console.error('Sample response data:', JSON.stringify(apiResponse, null, 2).substring(0, 1000)); throw new ValidationError('Invalid search response from API', result.error); } const response = result.data; // Generate search tips based on filters and results const searchTips = []; if (filters) { // Multiple keywords tip if (filters.keywords && filters.keywords.includes(' ') && !filters.keywords.includes('"')) { searchTips.push('Multiple keywords use AND logic - try single keywords for broader results'); } // Zero results tips if (response.totalRecords === 0) { if (filters.keywords) { searchTips.push('No results found - try broader terms, partial matches, or check spelling'); // Check if keywords might be state names or other non-title content const keywords = filters.keywords.toLowerCase(); if (US_STATE_NAMES.some(state => keywords.includes(state)) || US_STATE_CODES.some(code => keywords === code)) { searchTips.push('Keywords search titles only - use state filter for location-based searches'); } // Check for operators that don't work if (keywords.includes(' or ') || keywords.includes(' and ') || keywords.includes('|')) { searchTips.push('Operators like OR/AND/| do not work - use simple keywords instead'); } } else { searchTips.push('No results found - try adjusting your filters or expanding date ranges'); } } // Date range tips if (filters.postedFrom && filters.postedTo) { const fromDate = new Date(filters.postedFrom); const toDate = new Date(filters.postedTo); const daysDiff = Math.abs((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24)); if (response.totalRecords === 0 && daysDiff < 30) { searchTips.push('Try expanding your date range for more results'); } } // NAICS/PSC code tips if ((filters.naicsCodes?.length || filters.pscCodes?.length) && response.totalRecords === 0) { searchTips.push('No results for specified codes - try broader classification codes or remove code filters'); } // Set-aside types guidance if (filters.setAsideTypes?.length) { if (response.totalRecords === 0) { searchTips.push('No results for specified set-aside types - try "SBA" for most opportunities or remove set-aside filter'); } else if (response.totalRecords < 10 && filters.setAsideTypes.includes('HZC')) { searchTips.push('HUBZone set-asides are rare - consider "SBA" or "SDVOSBC" for more opportunities'); } } // Geographic filter guidance if (filters.placeOfPerformanceStates?.length && response.totalRecords === 0) { searchTips.push('No results for specified states - some opportunities may have incomplete location data'); } if (filters.placeOfPerformanceZips?.length) { if (response.totalRecords === 0) { searchTips.push('No results for specified zip codes - try using state filter instead as zip data is limited'); } else if (response.totalRecords > 100) { searchTips.push('High zip code results may include surrounding areas - consider adding other filters'); } } // Opportunity types guidance if (filters.types?.length) { if (response.totalRecords === 0) { searchTips.push('No results for specified opportunity types - try "a" (Award Notice) for most opportunities'); } // Warn about problematic types if (filters.types.includes('s')) { searchTips.push('Special Notice type may have data quality issues - consider using other opportunity types'); } // Guide toward high-volume types if (response.totalRecords < 10 && !filters.types.some(t => ['a', 'p', 'r'].includes(t))) { searchTips.push('For more opportunities, try "a" (Award Notice), "p" (Presolicitation), or "r" (Sources Sought)'); } } // Date range optimization if (filters.postedFrom && filters.postedTo) { const fromDate = new Date(filters.postedFrom); const toDate = new Date(filters.postedTo); const daysDiff = Math.abs((toDate.getTime() - fromDate.getTime()) / (1000 * 60 * 60 * 24)); if (daysDiff > 180 && response.totalRecords > 500) { searchTips.push('Large date range returned many results - consider narrowing the date range or adding filters'); } else if (daysDiff < 7 && response.totalRecords === 0) { searchTips.push('Short date range may be too restrictive - try expanding to 30+ days'); } } // Filter combination suggestions if (response.totalRecords > 200) { const activeFilters = [ filters.keywords ? 'keywords' : null, filters.naicsCodes?.length ? 'NAICS' : null, filters.pscCodes?.length ? 'PSC' : null, filters.setAsideTypes?.length ? 'set-aside' : null, filters.placeOfPerformanceStates?.length ? 'state' : null, filters.types?.length ? 'type' : null ].filter(Boolean); if (activeFilters.length === 1) { searchTips.push('Many results found - consider adding NAICS codes, set-aside types, or keywords to narrow search'); } } // Success optimization tips if (response.totalRecords > 0 && response.totalRecords < 50) { if (!filters.keywords && (filters.naicsCodes?.length || filters.pscCodes?.length)) { searchTips.push('Good results with classification codes - try adding keywords for more specific matching'); } } } // Add tips to response if (searchTips.length > 0) { response.searchTips = searchTips; } return response; } /** * Get opportunity by ID - uses search with specific notice ID */ async getById(noticeId) { const response = await this.client.get('/opportunities/v2/search', { noticeid: noticeId, limit: 1, }); if (!response.opportunitiesData || response.opportunitiesData.length === 0) { throw new ValidationError(`Opportunity with ID ${noticeId} not found`); } return response.opportunitiesData[0]; } /** * Get opportunity by SAM.gov UI URL - extracts notice ID from URL and retrieves the record * Accepts URLs like: https://sam.gov/opp/{noticeId}/view * Returns undefined if URL doesn't contain a valid notice ID */ async getByUrl(url) { // Extract notice ID from SAM.gov URL const noticeId = this.extractNoticeIdFromUrl(url); if (!noticeId) { return undefined; } return this.getById(noticeId); } /** * Extract notice ID from SAM.gov opportunity URL * Returns undefined if no valid notice ID found */ extractNoticeIdFromUrl(url) { // Handle different URL formats: // https://sam.gov/opp/{noticeId}/view // https://sam.gov/opp/{noticeId} // {noticeId} (just the ID) // If it's already just an ID (no protocol/domain), return as-is if (!url.includes('/') && url.length === 32) { return url; } // Match SAM.gov opportunity URL pattern const samGovPattern = /(?:https?:\/\/)?(?:www\.)?sam\.gov\/opp\/([a-f0-9]{32})(?:\/.*)?/i; const match = url.match(samGovPattern); if (match && match[1]) { return match[1]; } // Try to extract any 32-character hex string from the URL const hexPattern = /([a-f0-9]{32})/i; const hexMatch = url.match(hexPattern); if (hexMatch && hexMatch[1]) { return hexMatch[1]; } return undefined; } /** * Get opportunity description */ async getDescription(noticeId) { const response = await this.client.get('/opportunities/v1/noticedesc', { noticeid: noticeId, }); return response.description; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3Bwb3J0dW5pdGllcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jbGllbnRzL3NhbS9lbmRwb2ludHMvb3Bwb3J0dW5pdGllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUV2RCxPQUFPLEVBR0wsaUNBQWlDLEVBRWpDLGtDQUFrQyxHQUNuQyxNQUFNLDhCQUE4QixDQUFDO0FBR3RDLGdEQUFnRDtBQUNoRCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUc7SUFDNUIsU0FBUyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLFVBQVU7SUFDL0YsU0FBUyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxVQUFVO0lBQzVGLFdBQVcsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLGFBQWE7SUFDekYsVUFBVSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsWUFBWTtJQUN4RixVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLGNBQWM7SUFDMUYsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTO0lBQ3pGLFVBQVUsRUFBRSxZQUFZLEVBQUUsZUFBZSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsYUFBYTtJQUNoRixzQkFBc0IsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLEVBQUUsMEJBQTBCLEVBQUUsbUJBQW1CO0NBQ2xHLENBQUM7QUFF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