@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
JavaScript
/**
* 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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