Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / frontend/src/lib/api.ts |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 3be46ba89edb737182075a2b320509b42dc916f8 |
| Branch | workstream-d-missionmatch |
| Path or archive member | frontend/src/lib/api.ts |
| Original SHA-256 | 308e899ff025e00c2560ed36d6e943c9cb87574a6761efb1952e562f62c1e147 |
| Git blob SHA | 17ee171700b6e316051fc778b6bbb8b1a7332971 |
| Reading-copy SHA-256 | 308e899ff025e00c2560ed36d6e943c9cb87574a6761efb1952e562f62c1e147 |
Every recorded occurrence
These 25 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / frontend/src/lib/api.ts | workstream-d-missionmatch | 3be46ba89edb737182075a2b320509b42dc916f8 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | workstream-e-dataflow-deploy | 433815a042f9741411e60fa553fe72143e9b10db | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ai-intelligence-layer | 5d5ddff70393a197c5f54a45280bb5dd42b24755 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | workstream-e-dataflow-deploy | 433815a042f9741411e60fa553fe72143e9b10db | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ai-intelligence-layer | 5d5ddff70393a197c5f54a45280bb5dd42b24755 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / frontend/src/lib/api.ts | workstream-d-missionmatch | 3be46ba89edb737182075a2b320509b42dc916f8 | Open original |
Recovered source transcript
Download complete source text ↓181 lines · 7.8 KB
import type {
AdverseImpactReport,
CandidateListView,
ExternalCandidate,
FederalAward,
MissionCheckModeAResult,
MissionCheckModeBResult,
OpportunityFilters,
OpportunityFitView,
RankedCandidateView,
RequirementListView,
SamOpportunity,
SaveCandidateRequest,
ScreenView,
WageBaseline,
} from './types'
// opportunityQuery turns the filter object into a query string. Multi valued filters are repeated
// params (?naics=a&naics=b); the backend also accepts comma lists.
function opportunityQuery(f: OpportunityFilters): string {
const p = new URLSearchParams()
f.naics?.forEach((v) => p.append('naics', v))
f.set_aside?.forEach((v) => p.append('set_aside', v))
f.state?.forEach((v) => p.append('state', v))
f.department?.forEach((v) => p.append('department', v))
f.sub_agency?.forEach((v) => p.append('sub_agency', v))
if (f.q) p.set('q', f.q)
if (f.active_only === false) p.set('active_only', 'false')
if (f.limit) p.set('limit', String(f.limit))
const s = p.toString()
return s ? `?${s}` : ''
}
export class ApiError extends Error {
status: number
constructor(status: number, message: string) {
super(message)
this.status = status
}
}
// csrfToken is the signed double submit token issued by GET /auth/csrf. The companion __Host-mm_csrf
// cookie is set by that response; the __Host-mm_session cookie rides along via credentials include, so
// the validated session is the tenant source, not a client header.
let csrfToken: string | null = null
let csrfInflight: Promise<string> | null = null
async function ensureCsrf(): Promise<string> {
if (csrfToken) return csrfToken
// De-duplicate concurrent mints behind one shared fetch. Without this, two unsafe requests racing on a
// null token each hit GET /auth/csrf, the second response overwrites the __Host-mm_csrf cookie, and the
// first request's header no longer matches its cookie, so the double submit check 403s. One mint per
// token lifetime keeps the cookie and every header in agreement.
if (!csrfInflight) {
csrfInflight = fetch('/api/auth/csrf', { credentials: 'include' })
.then(async (res) => {
if (!res.ok) {
throw new Error(`csrf token request failed: ${res.status}`)
}
const body = (await res.json()) as { csrf_token?: string }
const token = body.csrf_token
if (!token) {
throw new Error('csrf token request returned an empty token')
}
csrfToken = token
return token
})
.finally(() => {
// Clear the in flight marker on success and failure so a failed mint is never cached and a
// later request can retry rather than sending an empty token into a guaranteed 403 loop.
csrfInflight = null
})
}
return csrfInflight
}
// normalizeHeaders flattens any HeadersInit form (a plain object, a Headers instance, or a tuple array)
// to a plain record so the spread below is correct for every caller, not just plain objects.
function normalizeHeaders(h: HeadersInit | undefined): Record<string, string> {
if (!h) return {}
if (h instanceof Headers) return Object.fromEntries(h.entries())
if (Array.isArray(h)) return Object.fromEntries(h)
return { ...h }
}
async function doFetch(path: string, init: RequestInit, method: string): Promise<Response> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...normalizeHeaders(init.headers),
}
if (method !== 'GET' && method !== 'HEAD') {
headers['X-CSRF-Token'] = await ensureCsrf()
}
// credentials include sends the __Host-mm_session cookie; the validated session is the tenant source.
return fetch(`/api${path}`, { ...init, credentials: 'include', headers })
}
async function rawRequest(path: string, init?: RequestInit): Promise<Response> {
const method = (init?.method ?? 'GET').toUpperCase()
let res = await doFetch(path, init ?? {}, method)
// A stale or rotated CSRF token returns 403; refresh once and retry the unsafe verb.
if (res.status === 403 && method !== 'GET' && method !== 'HEAD') {
csrfToken = null
res = await doFetch(path, init ?? {}, method)
}
if (!res.ok) {
let detail = res.statusText
try {
const body = (await res.clone().json()) as { error?: string }
if (body.error) detail = body.error
} catch {
/* ignore non-JSON error bodies */
}
throw new ApiError(res.status, detail)
}
return res
}
export async function request<T>(path: string, init?: RequestInit): Promise<T> {
const res = await rawRequest(path, init)
return (await res.json()) as T
}
async function requestText(path: string): Promise<string> {
const res = await rawRequest(path)
return res.text()
}
export const api = {
candidates: () => request<CandidateListView[]>('/candidates?limit=200'),
// Fetch one candidate or requirement by id so a deep linked evaluation works even when the row is
// not inside the first list page; the list scan would silently render a blank evaluation otherwise.
candidate: (id: string) =>
request<CandidateListView>(`/candidates/${encodeURIComponent(id)}`),
requirements: () => request<RequirementListView[]>('/requirements?limit=200'),
requirement: (id: string) =>
request<RequirementListView>(`/requirements/${encodeURIComponent(id)}`),
screen: (candidate_id: string, requirement_id: string) =>
request<ScreenView>('/screen', {
method: 'POST',
body: JSON.stringify({ candidate_id, requirement_id }),
}),
opportunities: (candidateId: string) =>
request<OpportunityFitView[]>(`/candidates/${candidateId}/opportunities?limit=10`),
rankCandidates: (requirementId: string) =>
request<RankedCandidateView[]>(`/requirements/${requirementId}/candidates`),
// Cached SAM.gov opportunities (the requirement feed). The frontend NEVER calls SAM live.
samOpportunities: (f: OpportunityFilters = {}) =>
request<SamOpportunity[]>(`/opportunities${opportunityQuery(f)}`),
samOpportunity: (noticeId: string) =>
request<SamOpportunity>(`/opportunities/${encodeURIComponent(noticeId)}`),
// USASpending awards (cache only): incumbents by NAICS and Galapagos own past performance.
incumbents: (naics: string) =>
request<FederalAward[]>(`/awards?naics=${encodeURIComponent(naics)}&limit=6`),
galapagosAwards: () => request<FederalAward[]>('/awards/galapagos?limit=8'),
// BLS OEWS regional wage baseline (cache only).
wages: () => request<WageBaseline[]>('/wages'),
// Externally sourced candidates (People Data Labs) plus the delete path.
externalCandidates: () => request<ExternalCandidate[]>('/sourcing/candidates'),
deleteExternalCandidate: (id: string) =>
request<{ status: string }>(`/sourcing/candidates/${encodeURIComponent(id)}`, { method: 'DELETE' }),
// Compliance: the adverse impact report (compliance role only) and its publication ready export.
adverseImpact: () => request<AdverseImpactReport>('/compliance/adverse-impact'),
adverseImpactExport: () => requestText('/compliance/adverse-impact/export'),
// Mission Check (W1): the resume is parsed to text in the browser; only the text crosses the wire.
// Mode A scores it against every open opportunity, Mode B against one pasted job description.
missionCheckOpportunities: (resume_text: string, limit = 10) =>
request<MissionCheckModeAResult>('/mission-check/opportunities', {
method: 'POST',
body: JSON.stringify({ resume_text, limit }),
}),
missionCheckJD: (resume_text: string, job_description_text: string) =>
request<MissionCheckModeBResult>('/mission-check/screen', {
method: 'POST',
body: JSON.stringify({ resume_text, job_description_text }),
}),
// Save Candidate: persist a reviewed Mission Check result as an audited candidate (recruiter capability).
saveCandidate: (body: SaveCandidateRequest) =>
request<{ id: string }>('/candidates', { method: 'POST', body: JSON.stringify(body) }),
}