@cliwant/mcp-sam-gov 1.8.0 → 1.10.0

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.
package/dist/ecfr.js CHANGED
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * Both keyless. Documented at https://www.ecfr.gov/developers/.
14
14
  */
15
- import { fetchWithRetry } from "./errors.js";
15
+ import { fetchWithRetry, ToolErrorCarrier } from "./errors.js";
16
16
  import { driftError } from "./datasource.js";
17
17
  import { memoize } from "./cache.js";
18
18
  import { withMeta } from "./meta.js";
@@ -59,6 +59,132 @@ export async function listTitles() {
59
59
  });
60
60
  });
61
61
  }
62
+ // ─── ecfr_get_section — full in-force text of one CFR section ──────────────
63
+ // The eval-found gap: ecfr_search returns ranked SNIPPETS; there was no way to pull
64
+ // a clause's COMPLETE text. This fetches one section from the versioner `full`
65
+ // endpoint (a per-section XML, ~5KB), de-XMLed to plain text. A bespoke individual
66
+ // source (not the search API) — mode-2 discovery.
67
+ const ECFR_SECTION_RE = /^[0-9]{1,3}\.[0-9]{1,4}(-[0-9]{1,4})?$/;
68
+ const ECFR_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
69
+ async function fetchXmlText(url) {
70
+ const r = await fetchWithRetry(url, { headers: { Accept: "application/xml" }, signal: AbortSignal.timeout(20_000) }, `ecfr:${url.split("/api/")[1] ?? url}`);
71
+ return await r.text();
72
+ }
73
+ function decodeXmlEntities(s) {
74
+ return s
75
+ .replace(/"/g, '"')
76
+ .replace(/&lt;/g, "<")
77
+ .replace(/&gt;/g, ">")
78
+ .replace(/&#39;/g, "'")
79
+ .replace(/&#(\d+);/g, (_, n) => String.fromCharCode(Number(n)))
80
+ .replace(/&amp;/g, "&");
81
+ }
82
+ // De-XML a section body to readable plain text: block tags → newlines, strip the
83
+ // rest, decode entities, drop empty lines. No fabrication — the eCFR's own text.
84
+ function xmlToPlainText(xml) {
85
+ return decodeXmlEntities(xml
86
+ .replace(/<\/(P|HD1|HD2|HD3|HD4|HEAD|FP|GID|GPOTABLE|ROW)>/gi, "\n")
87
+ .replace(/<[^>]+>/g, ""))
88
+ .split("\n")
89
+ .map((l) => l.trim())
90
+ .filter((l) => l.length > 0)
91
+ .join("\n");
92
+ }
93
+ export async function getSection(args) {
94
+ // SSRF/injection: `section` (+ derived `part`) interpolate into the URL query, so
95
+ // the charclass is the load-bearing guard. `titleNumber` is numeric (schema).
96
+ // `\s` reject is load-bearing: JS `$` also matches BEFORE a trailing "\n", so the
97
+ // charclass alone would admit "52.204-21\n". No valid section carries whitespace.
98
+ if (!ECFR_SECTION_RE.test(args.section) || /\s/.test(args.section)) {
99
+ throw new ToolErrorCarrier({
100
+ kind: "invalid_input",
101
+ retryable: false,
102
+ message: `Invalid section ${JSON.stringify(args.section)} — expected a CFR section like "52.204-21" or "12.301" (^[0-9]{1,3}\\.[0-9]{1,4}(-[0-9]{1,4})?$, no whitespace).`,
103
+ upstreamEndpoint: "ecfr:versioner/full",
104
+ });
105
+ }
106
+ let issueDate = args.date;
107
+ if (issueDate !== undefined && !ECFR_DATE_RE.test(issueDate)) {
108
+ throw new ToolErrorCarrier({
109
+ kind: "invalid_input",
110
+ retryable: false,
111
+ message: `Invalid date ${JSON.stringify(args.date)} — expected an eCFR issue date YYYY-MM-DD (omit to use the title's latest).`,
112
+ upstreamEndpoint: "ecfr:versioner/full",
113
+ });
114
+ }
115
+ if (!issueDate) {
116
+ // Resolve the title's latest issue date (memoized titles list) — DISCLOSED below.
117
+ const t = (await listTitles()).data.titles.find((x) => x.number === args.titleNumber);
118
+ issueDate = t?.latestIssueDate;
119
+ if (!issueDate) {
120
+ throw new ToolErrorCarrier({
121
+ kind: "invalid_input",
122
+ retryable: false,
123
+ message: `Title ${args.titleNumber} is not a known CFR title (or has no issue date). Verify it via ecfr_list_titles.`,
124
+ upstreamEndpoint: "ecfr:versioner/full",
125
+ });
126
+ }
127
+ }
128
+ const part = args.section.split(".")[0];
129
+ const url = `${ECFR}/versioner/v1/full/${issueDate}/title-${args.titleNumber}.xml?part=${encodeURIComponent(part)}&section=${encodeURIComponent(args.section)}`;
130
+ const xml = await fetchXmlText(url);
131
+ // Locate the SECTION DIV8 for EXACTLY this section (the endpoint may return the
132
+ // enclosing part). Absent ⇒ honest not_found, NEVER a fabricated empty/wrong text.
133
+ const escaped = args.section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
134
+ const div = xml.match(new RegExp(`<DIV8 N="${escaped}"[^>]*TYPE="SECTION"[^>]*>([\\s\\S]*?)</DIV8>`, "i"));
135
+ if (!div) {
136
+ throw new ToolErrorCarrier({
137
+ kind: "not_found",
138
+ retryable: false,
139
+ message: `Section ${args.section} not found in CFR title ${args.titleNumber} as of the ${issueDate} issue. Verify the citation (e.g. via ecfr_search); the part number (${part}) must actually contain the section.`,
140
+ upstreamEndpoint: "ecfr:versioner/full",
141
+ });
142
+ }
143
+ const body = div[1];
144
+ const headMatch = body.match(/<HEAD>([\s\S]*?)<\/HEAD>/i);
145
+ const heading = headMatch ? xmlToPlainText(headMatch[1]).replace(/\n+/g, " ").trim() : null;
146
+ let citation = null;
147
+ let alternateReference = null;
148
+ const meta = xml.match(/hierarchy_metadata="([^"]*)"/i);
149
+ if (meta) {
150
+ try {
151
+ const hm = JSON.parse(decodeXmlEntities(meta[1]));
152
+ citation = hm.citation ?? null;
153
+ alternateReference = hm.alternate_reference ?? null;
154
+ }
155
+ catch {
156
+ /* metadata is advisory — its absence never blocks the text */
157
+ }
158
+ }
159
+ const fullText = xmlToPlainText(body);
160
+ if (fullText.length === 0) {
161
+ // A 200 with a section shell but no readable text ⇒ schema drift, not a fake empty.
162
+ throw driftError("ecfr:versioner/full", `The section ${args.section} DIV8 carried no extractable text — eCFR XML shape drift, never a fabricated empty section.`);
163
+ }
164
+ const ecfrUrl = `https://www.ecfr.gov/current/title-${args.titleNumber}/section-${args.section}`;
165
+ return withMeta({
166
+ titleNumber: args.titleNumber,
167
+ section: args.section,
168
+ citation,
169
+ alternateReference,
170
+ heading,
171
+ fullText,
172
+ issueDate,
173
+ ecfrUrl,
174
+ }, {
175
+ source: "ecfr.gov/api (versioner/v1/full)",
176
+ keylessMode: true,
177
+ returned: 1,
178
+ totalAvailable: 1,
179
+ truncated: false,
180
+ filtersApplied: ["titleNumber", "section"],
181
+ filtersDropped: [],
182
+ fieldsUnavailable: [],
183
+ notes: [
184
+ `Full in-force text of ${citation ?? `${args.titleNumber} CFR ${args.section}`} as of the ${issueDate} eCFR issue (the title's LATEST unless a date was supplied — a moving target). De-XMLed to plain text; no content fabricated — open ecfrUrl for the authoritative rendering.`,
185
+ ],
186
+ });
187
+ }
62
188
  export async function search(args) {
63
189
  const url = new URL(`${ECFR}/search/v1/results`);
64
190
  url.searchParams.set("query", args.query);
package/dist/ecfr.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ecfr.js","sourceRoot":"","sources":["../src/ecfr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ecfr.js","sourceRoot":"","sources":["../src/ecfr.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * opengov.ts — OpenGov Procurement (formerly ProcureNow) public solicitations,
3
+ * a keyless-first SLED bid source (loop cycle — SLED bid campaign, 2026-07-19).
4
+ *
5
+ * WHAT IT ADDS: OpenGov Procurement hosts the live open-solicitation portals of
6
+ * **525+ US state/local governments** (cities, counties, school & special
7
+ * districts across 42 states + DC). The public portal SPA
8
+ * (`procurement.opengov.com/portal/{code}`) is served by an UNAUTHENTICATED
9
+ * backend REST API — the official key-gated `api-key` API is NOT used; this
10
+ * consumes ONLY the anonymous endpoints the public portal itself calls, so it is
11
+ * genuinely keyless (live-verified 2026-07-19: bare anonymous request, no api-key /
12
+ * auth header / cookie). It is the OpenGov sibling of the Socrata/CKAN/ArcGIS
13
+ * discovery tools and one of the two highest-reach keyless SLED bid feeds (with
14
+ * Bonfire RSS).
15
+ *
16
+ * The module writes ZERO fetch/coercion/error/meta code — it REUSES `getJson`
17
+ * (GET + POST/JSON via ADR-0014, redirect:"error") / `driftError` / `num`·`str`
18
+ * (coerce.ts, null-never-0 / null-never-empty) / `withMeta`·`buildMeta`,
19
+ * mirroring datagov-catalog.ts. KEYLESS: no key seam.
20
+ *
21
+ * ★ SSRF: the host is a compile-time literal (`OPENGOV_HOST`). All inputs ride in
22
+ * a MODULE-BUILT JSON body / URLSearchParams from validated typed args — NO
23
+ * raw-host/raw-path passthrough (this is a FIXED-host API). A post-construction
24
+ * hostname/protocol assertion + `redirect:"error"` lock every call.
25
+ *
26
+ * ★ TWO endpoints (both anonymous, live-verified):
27
+ * - `GET /api/v1/government` → a flat JSON array of ~560 org records (the whole
28
+ * directory in one call; `government.code` = the portal slug). We keep the
29
+ * ACTIVE, non-internal ones (~525 real public portals).
30
+ * - `POST /api/v1/project/list` body `{governmentCode, publicView:true, page,
31
+ * limit}` → `{projects:[…], count}`. `publicView:true` is REQUIRED (the public
32
+ * gate). `count` is the TRUE total of public projects for that org.
33
+ *
34
+ * ★ HONESTY PILLARS (captured live 2026-07-19):
35
+ * P1: totalAvailable = the real total — the filtered directory length (govt
36
+ * list) or the API's `count` (solicitations) — NEVER the page length.
37
+ * P2: getJson→fetchWithRetry THROWS on 429 / 5xx / timeout — NEVER a fake empty.
38
+ * A genuine no-match (projects:[], count:0) ⇒ honest empty.
39
+ * P3: every scalar via `str` (null-never-empty) / `num` (null-never-0). The
40
+ * `status` enum is surfaced VERBATIM (open = currently accepting; the response
41
+ * also carries pending/evaluation/closed — the CONSUMER filters; we do not
42
+ * hide non-open rows or fabricate an "open count").
43
+ * P4: `/government` non-array or `/project/list` `.projects` non-array ⇒
44
+ * driftError; a 200 non-JSON body ⇒ schema_drift via the catch-ladder
45
+ * (ToolErrorCarrier rethrow FIRST so a 429/5xx keeps its taxonomy).
46
+ */
47
+ import { num } from "./coerce.js";
48
+ import { type MetaBundle } from "./meta.js";
49
+ export { num };
50
+ export declare const OPENGOV_HOST = "api.procurement.opengov.com";
51
+ export declare const OPENGOV_CODE_RE: RegExp;
52
+ export type OpengovGovernment = {
53
+ code: string | null;
54
+ name: string | null;
55
+ city: string | null;
56
+ state: string | null;
57
+ website: string | null;
58
+ };
59
+ export type OpengovSolicitation = {
60
+ id: number | null;
61
+ title: string | null;
62
+ solicitationNumber: string | null;
63
+ status: string | null;
64
+ type: string | null;
65
+ department: string | null;
66
+ releaseDate: string | null;
67
+ proposalDeadline: string | null;
68
+ contactName: string | null;
69
+ link: string | null;
70
+ };
71
+ export type OpengovListGovernmentsArgs = {
72
+ state?: string;
73
+ query?: string;
74
+ limit?: number;
75
+ offset?: number;
76
+ };
77
+ /**
78
+ * List the OpenGov Procurement government portals (the whole directory arrives in
79
+ * ONE keyless GET). Client-side filters: `state` (2-letter), `query` (name
80
+ * substring). Only ACTIVE, non-internal portals are kept. Feeds `code` to
81
+ * opengov_search_solicitations. totalAvailable = the filtered directory size (P1).
82
+ */
83
+ export declare function listGovernments(args: OpengovListGovernmentsArgs): Promise<MetaBundle>;
84
+ export type OpengovSearchSolicitationsArgs = {
85
+ governmentCode: string;
86
+ limit?: number;
87
+ offset?: number;
88
+ };
89
+ /**
90
+ * List an OpenGov government's public solicitations (POST /project/list with the
91
+ * REQUIRED publicView gate). Returns all public projects with `status` surfaced
92
+ * (filter status==='open' for live bids). totalAvailable = the API's `count` (the
93
+ * org's total public-project count — P1, never the page length).
94
+ */
95
+ export declare function searchSolicitations(args: OpengovSearchSolicitationsArgs): Promise<MetaBundle>;
96
+ //# sourceMappingURL=opengov.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opengov.d.ts","sourceRoot":"","sources":["../src/opengov.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAIH,OAAO,EAAE,GAAG,EAAO,MAAM,aAAa,CAAC;AACvC,OAAO,EAAY,KAAK,UAAU,EAAqB,MAAM,WAAW,CAAC;AAGzE,OAAO,EAAE,GAAG,EAAE,CAAC;AAGf,eAAO,MAAM,YAAY,gCAAgC,CAAC;AAW1D,eAAO,MAAM,eAAe,QAAsB,CAAC;AAMnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AA6BF,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,UAAU,CAAC,CAuErB;AAGD,MAAM,MAAM,8BAA8B,GAAG;IAC3C,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,8BAA8B,GACnC,OAAO,CAAC,UAAU,CAAC,CAoFrB"}
@@ -0,0 +1,244 @@
1
+ /**
2
+ * opengov.ts — OpenGov Procurement (formerly ProcureNow) public solicitations,
3
+ * a keyless-first SLED bid source (loop cycle — SLED bid campaign, 2026-07-19).
4
+ *
5
+ * WHAT IT ADDS: OpenGov Procurement hosts the live open-solicitation portals of
6
+ * **525+ US state/local governments** (cities, counties, school & special
7
+ * districts across 42 states + DC). The public portal SPA
8
+ * (`procurement.opengov.com/portal/{code}`) is served by an UNAUTHENTICATED
9
+ * backend REST API — the official key-gated `api-key` API is NOT used; this
10
+ * consumes ONLY the anonymous endpoints the public portal itself calls, so it is
11
+ * genuinely keyless (live-verified 2026-07-19: bare anonymous request, no api-key /
12
+ * auth header / cookie). It is the OpenGov sibling of the Socrata/CKAN/ArcGIS
13
+ * discovery tools and one of the two highest-reach keyless SLED bid feeds (with
14
+ * Bonfire RSS).
15
+ *
16
+ * The module writes ZERO fetch/coercion/error/meta code — it REUSES `getJson`
17
+ * (GET + POST/JSON via ADR-0014, redirect:"error") / `driftError` / `num`·`str`
18
+ * (coerce.ts, null-never-0 / null-never-empty) / `withMeta`·`buildMeta`,
19
+ * mirroring datagov-catalog.ts. KEYLESS: no key seam.
20
+ *
21
+ * ★ SSRF: the host is a compile-time literal (`OPENGOV_HOST`). All inputs ride in
22
+ * a MODULE-BUILT JSON body / URLSearchParams from validated typed args — NO
23
+ * raw-host/raw-path passthrough (this is a FIXED-host API). A post-construction
24
+ * hostname/protocol assertion + `redirect:"error"` lock every call.
25
+ *
26
+ * ★ TWO endpoints (both anonymous, live-verified):
27
+ * - `GET /api/v1/government` → a flat JSON array of ~560 org records (the whole
28
+ * directory in one call; `government.code` = the portal slug). We keep the
29
+ * ACTIVE, non-internal ones (~525 real public portals).
30
+ * - `POST /api/v1/project/list` body `{governmentCode, publicView:true, page,
31
+ * limit}` → `{projects:[…], count}`. `publicView:true` is REQUIRED (the public
32
+ * gate). `count` is the TRUE total of public projects for that org.
33
+ *
34
+ * ★ HONESTY PILLARS (captured live 2026-07-19):
35
+ * P1: totalAvailable = the real total — the filtered directory length (govt
36
+ * list) or the API's `count` (solicitations) — NEVER the page length.
37
+ * P2: getJson→fetchWithRetry THROWS on 429 / 5xx / timeout — NEVER a fake empty.
38
+ * A genuine no-match (projects:[], count:0) ⇒ honest empty.
39
+ * P3: every scalar via `str` (null-never-empty) / `num` (null-never-0). The
40
+ * `status` enum is surfaced VERBATIM (open = currently accepting; the response
41
+ * also carries pending/evaluation/closed — the CONSUMER filters; we do not
42
+ * hide non-open rows or fabricate an "open count").
43
+ * P4: `/government` non-array or `/project/list` `.projects` non-array ⇒
44
+ * driftError; a 200 non-JSON body ⇒ schema_drift via the catch-ladder
45
+ * (ToolErrorCarrier rethrow FIRST so a 429/5xx keeps its taxonomy).
46
+ */
47
+ import { ToolErrorCarrier } from "./errors.js";
48
+ import { getJson, driftError } from "./datasource.js";
49
+ import { num, str } from "./coerce.js";
50
+ import { withMeta } from "./meta.js";
51
+ // Re-export the shared honesty coercion (num-parity guard).
52
+ export { num };
53
+ // ─── Fixed endpoint (SSRF core — compile-time CONSTANTS) ──────────
54
+ export const OPENGOV_HOST = "api.procurement.opengov.com";
55
+ const OPENGOV_GOVERNMENT_PATH = "/api/v1/government";
56
+ const OPENGOV_PROJECT_LIST_PATH = "/api/v1/project/list";
57
+ const OPENGOV_GOV_LABEL = "opengov:/api/v1/government";
58
+ const OPENGOV_PROJ_LABEL = "opengov:/api/v1/project/list";
59
+ const OPENGOV_SOURCE = "procurement.opengov.com via OpenGov Procurement public API (keyless)";
60
+ const OPENGOV_PORTAL = "https://procurement.opengov.com/portal";
61
+ // The org slug grammar (SSRF + injection guard). Real slugs are lowercase
62
+ // alnum + hyphen (e.g. "santacruzca", "u-46", "twc-texas-gov"). Validated
63
+ // BEFORE it rides the JSON body — a "../"/space/uppercase ⇒ invalid_input, 0 fetch.
64
+ export const OPENGOV_CODE_RE = /^[a-z0-9-]{1,64}$/;
65
+ const OPENGOV_STATUS_NOTE = "`status` is surfaced verbatim: open = currently ACCEPTING responses; pending/evaluation/closed are also returned (publicView shows all public projects). Filter status==='open' for live bids. totalAvailable is the org's TOTAL public-project count (all statuses), not an open-only count.";
66
+ /** null-preserving boolean (a real true/false survives; else null). */
67
+ function boolOrNull(x) {
68
+ return typeof x === "boolean" ? x : null;
69
+ }
70
+ // ─── SSRF-guarded fetch (fixed host + hostname assertion + redirect) ──
71
+ async function getOpengov(path, label, init = {}) {
72
+ const url = `https://${OPENGOV_HOST}${path}`;
73
+ const built = new URL(url);
74
+ if (built.hostname !== OPENGOV_HOST || built.protocol !== "https:") {
75
+ throw new ToolErrorCarrier({
76
+ kind: "invalid_input",
77
+ message: `Constructed OpenGov URL host ${JSON.stringify(built.hostname)} (${built.protocol}) does not match the fixed host ${JSON.stringify(OPENGOV_HOST)} over https — refusing to fetch (SSRF safety).`,
78
+ retryable: false,
79
+ upstreamEndpoint: label,
80
+ });
81
+ }
82
+ const headers = init.method === "POST" ? { "Content-Type": "application/json" } : {};
83
+ return getJson(url, { label, headers, redirect: "error", ...init });
84
+ }
85
+ /**
86
+ * List the OpenGov Procurement government portals (the whole directory arrives in
87
+ * ONE keyless GET). Client-side filters: `state` (2-letter), `query` (name
88
+ * substring). Only ACTIVE, non-internal portals are kept. Feeds `code` to
89
+ * opengov_search_solicitations. totalAvailable = the filtered directory size (P1).
90
+ */
91
+ export async function listGovernments(args) {
92
+ const limit = args.limit ?? 50;
93
+ const offset = args.offset ?? 0;
94
+ let body;
95
+ try {
96
+ body = await getOpengov(OPENGOV_GOVERNMENT_PATH, OPENGOV_GOV_LABEL);
97
+ }
98
+ catch (e) {
99
+ if (e instanceof ToolErrorCarrier)
100
+ throw e;
101
+ if (e instanceof SyntaxError)
102
+ throw driftError(OPENGOV_GOV_LABEL, "OpenGov /government returned a non-JSON body at HTTP 200 — schema drift.");
103
+ throw e;
104
+ }
105
+ // P4: the response MUST be an array (a missing/object body is drift).
106
+ if (!Array.isArray(body)) {
107
+ throw driftError(OPENGOV_GOV_LABEL, "OpenGov /government shape drift — response must be a JSON array of governments.");
108
+ }
109
+ const stateFilter = args.state ? args.state.trim().toUpperCase() : null;
110
+ const queryFilter = args.query ? args.query.trim().toLowerCase() : null;
111
+ const filtersApplied = [];
112
+ if (stateFilter)
113
+ filtersApplied.push("state");
114
+ if (queryFilter)
115
+ filtersApplied.push("query");
116
+ const all = [];
117
+ for (const row of body) {
118
+ const r = (row ?? {});
119
+ // Keep only active, non-internal, non-vendor real public portals.
120
+ if (boolOrNull(r.isActive) === false)
121
+ continue;
122
+ if (boolOrNull(r.isInternal) === true)
123
+ continue;
124
+ const gov = (r.government ?? {});
125
+ const g = {
126
+ code: str(gov.code),
127
+ name: str(r.name),
128
+ city: str(r.city),
129
+ state: str(r.state),
130
+ website: str(r.website),
131
+ };
132
+ if (g.code === null)
133
+ continue; // no portal slug ⇒ not queryable
134
+ if (stateFilter && (g.state ?? "").toUpperCase() !== stateFilter)
135
+ continue;
136
+ if (queryFilter && !(g.name ?? "").toLowerCase().includes(queryFilter))
137
+ continue;
138
+ all.push(g);
139
+ }
140
+ const totalAvailable = all.length;
141
+ const page = all.slice(offset, offset + limit);
142
+ const returned = page.length;
143
+ const hasMore = offset + returned < totalAvailable;
144
+ const nextOffset = hasMore ? offset + returned : null;
145
+ const notes = [
146
+ "The full OpenGov Procurement directory is returned in one keyless call and filtered client-side; totalAvailable is the exact filtered portal count. Feed a result's `code` to opengov_search_solicitations.",
147
+ ];
148
+ if (filtersApplied.length === 0) {
149
+ notes.push("No filters applied — this lists ALL active OpenGov portals. Add `state` and/or `query` to scope.");
150
+ }
151
+ return withMeta({ governments: page }, {
152
+ source: OPENGOV_SOURCE,
153
+ keylessMode: true,
154
+ returned,
155
+ totalAvailable,
156
+ filtersApplied,
157
+ filtersDropped: [],
158
+ fieldsUnavailable: [],
159
+ pagination: { offset, limit, hasMore, nextOffset },
160
+ notes,
161
+ });
162
+ }
163
+ /**
164
+ * List an OpenGov government's public solicitations (POST /project/list with the
165
+ * REQUIRED publicView gate). Returns all public projects with `status` surfaced
166
+ * (filter status==='open' for live bids). totalAvailable = the API's `count` (the
167
+ * org's total public-project count — P1, never the page length).
168
+ */
169
+ export async function searchSolicitations(args) {
170
+ const limit = args.limit ?? 50;
171
+ const offset = args.offset ?? 0;
172
+ const code = args.governmentCode ?? "";
173
+ // Belt-and-suspenders slug grammar (behind the server's Zod). A bad slug would
174
+ // ride the JSON body and either error or mis-scope — reject pre-fetch (0 fetch).
175
+ if (!OPENGOV_CODE_RE.test(code)) {
176
+ throw new ToolErrorCarrier({
177
+ kind: "invalid_input",
178
+ message: `Invalid OpenGov governmentCode ${JSON.stringify(code)} — expected a lowercase-alnum/hyphen portal slug (≤64 chars) from opengov_list_governments (e.g. 'santacruzca', 'u-46').`,
179
+ retryable: false,
180
+ upstreamEndpoint: OPENGOV_PROJ_LABEL,
181
+ });
182
+ }
183
+ // The API paginates by 0-based `page` + `limit`. Map our offset → page.
184
+ const page = Math.floor(offset / limit);
185
+ const servedOffset = page * limit;
186
+ const payload = JSON.stringify({ governmentCode: code, publicView: true, page, limit });
187
+ let body;
188
+ try {
189
+ body = await getOpengov(OPENGOV_PROJECT_LIST_PATH, OPENGOV_PROJ_LABEL, { method: "POST", body: payload });
190
+ }
191
+ catch (e) {
192
+ if (e instanceof ToolErrorCarrier)
193
+ throw e;
194
+ if (e instanceof SyntaxError)
195
+ throw driftError(OPENGOV_PROJ_LABEL, "OpenGov /project/list returned a non-JSON body at HTTP 200 — schema drift.");
196
+ throw e;
197
+ }
198
+ const b = (body ?? {});
199
+ // P4: `projects` MUST be an array (a missing/object projects is drift).
200
+ if (!Array.isArray(b.projects)) {
201
+ throw driftError(OPENGOV_PROJ_LABEL, "OpenGov /project/list shape drift — response.projects must be an array.");
202
+ }
203
+ const solicitations = b.projects.map((row) => {
204
+ const r = (row ?? {});
205
+ const id = num(r.id);
206
+ const codeForLink = code;
207
+ return {
208
+ id,
209
+ title: str(r.title),
210
+ solicitationNumber: str(r.financialId),
211
+ status: str(r.status),
212
+ type: str(r.type),
213
+ department: str(r.departmentName),
214
+ releaseDate: str(r.releaseProjectDate ?? r.postedAt),
215
+ proposalDeadline: str(r.proposalDeadline),
216
+ contactName: [str(r.contactFirstName), str(r.contactLastName)].filter((v) => v !== null).join(" ") || null,
217
+ link: id !== null ? `${OPENGOV_PORTAL}/${codeForLink}/projects/${id}` : null,
218
+ };
219
+ });
220
+ const returned = solicitations.length;
221
+ // P1: totalAvailable = the API `count` (total public projects), NEVER page length.
222
+ const totalAvailable = num(b.count);
223
+ const hasMore = totalAvailable !== null ? servedOffset + returned < totalAvailable : returned >= limit;
224
+ const nextOffset = hasMore ? servedOffset + returned : null;
225
+ const notes = [OPENGOV_STATUS_NOTE];
226
+ if (servedOffset !== offset) {
227
+ notes.push(`offset was snapped to the page boundary ${servedOffset} (OpenGov paginates by fixed pages of ${limit}).`);
228
+ }
229
+ if (totalAvailable === null) {
230
+ notes.push("totalAvailable is unknown (the API omitted `count`); completeness inferred from page fullness.");
231
+ }
232
+ return withMeta({ governmentCode: code, solicitations }, {
233
+ source: OPENGOV_SOURCE,
234
+ keylessMode: true,
235
+ returned,
236
+ totalAvailable,
237
+ filtersApplied: ["governmentCode", "publicView"],
238
+ filtersDropped: [],
239
+ fieldsUnavailable: [],
240
+ pagination: { offset: servedOffset, limit, hasMore, nextOffset },
241
+ notes,
242
+ });
243
+ }
244
+ //# sourceMappingURL=opengov.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opengov.js","sourceRoot":"","sources":["../src/opengov.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAsC,MAAM,WAAW,CAAC;AAEzE,4DAA4D;AAC5D,OAAO,EAAE,GAAG,EAAE,CAAC;AAEf,qEAAqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAAG,6BAA6B,CAAC;AAC1D,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AACrD,MAAM,yBAAyB,GAAG,sBAAsB,CAAC;AACzD,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AACvD,MAAM,kBAAkB,GAAG,8BAA8B,CAAC;AAC1D,MAAM,cAAc,GAAG,sEAAsE,CAAC;AAC9F,MAAM,cAAc,GAAG,wCAAwC,CAAC;AAEhE,0EAA0E;AAC1E,0EAA0E;AAC1E,oFAAoF;AACpF,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD,MAAM,mBAAmB,GACvB,+RAA+R,CAAC;AAwBlS,uEAAuE;AACvE,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,yEAAyE;AACzE,KAAK,UAAU,UAAU,CACvB,IAAY,EACZ,KAAa,EACb,OAA2C,EAAE;IAE7C,MAAM,GAAG,GAAG,WAAW,YAAY,GAAG,IAAI,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,KAAK,CAAC,QAAQ,KAAK,YAAY,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACnE,MAAM,IAAI,gBAAgB,CAAC;YACzB,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,gCAAgC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,QAAQ,mCAAmC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,gDAAgD;YACzM,SAAS,EAAE,KAAK;YAChB,gBAAgB,EAAE,KAAK;SACxB,CAAC,CAAC;IACL,CAAC;IACD,MAAM,OAAO,GACX,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,OAAO,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC;AAUD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAgC;IAEhC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAEhC,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,UAAU,CAAC,uBAAuB,EAAE,iBAAiB,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,gBAAgB;YAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,YAAY,WAAW;YAC1B,MAAM,UAAU,CAAC,iBAAiB,EAAE,0EAA0E,CAAC,CAAC;QAClH,MAAM,CAAC,CAAC;IACV,CAAC;IACD,sEAAsE;IACtE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,UAAU,CAAC,iBAAiB,EAAE,iFAAiF,CAAC,CAAC;IACzH,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,WAAW;QAAE,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,WAAW;QAAE,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE9C,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,IAAiB,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAA4B,CAAC;QACjD,kEAAkE;QAClE,IAAI,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,KAAK;YAAE,SAAS;QAC/C,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI;YAAE,SAAS;QAChD,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;QAC5D,MAAM,CAAC,GAAsB;YAC3B,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YACjB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YACjB,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YACnB,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;SACxB,CAAC;QACF,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;YAAE,SAAS,CAAC,iCAAiC;QAChE,IAAI,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,WAAW;YAAE,SAAS;QAC3E,IAAI,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,SAAS;QACjF,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IAED,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC;IAClC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;IAC7B,MAAM,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,cAAc,CAAC;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAEtD,MAAM,KAAK,GAAa;QACtB,6MAA6M;KAC9M,CAAC;IACF,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,kGAAkG,CAAC,CAAC;IACjH,CAAC;IAED,OAAO,QAAQ,CACb,EAAE,WAAW,EAAE,IAAI,EAAE,EACrB;QACE,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,IAAI;QACjB,QAAQ;QACR,cAAc;QACd,cAAc;QACd,cAAc,EAAE,EAAE;QAClB,iBAAiB,EAAE,EAAE;QACrB,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE;QAClD,KAAK;KAC0B,CAClC,CAAC;AACJ,CAAC;AASD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAoC;IAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC;IAEvC,+EAA+E;IAC/E,iFAAiF;IACjF,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,gBAAgB,CAAC;YACzB,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,kCAAkC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,0HAA0H;YACzL,SAAS,EAAE,KAAK;YAChB,gBAAgB,EAAE,kBAAkB;SACrC,CAAC,CAAC;IACL,CAAC;IAED,wEAAwE;IACxE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IACxC,MAAM,YAAY,GAAG,IAAI,GAAG,KAAK,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAExF,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,UAAU,CAAC,yBAAyB,EAAE,kBAAkB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5G,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,gBAAgB;YAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,YAAY,WAAW;YAC1B,MAAM,UAAU,CAAC,kBAAkB,EAAE,4EAA4E,CAAC,CAAC;QACrH,MAAM,CAAC,CAAC;IACV,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAA4C,CAAC;IAClE,wEAAwE;IACxE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,MAAM,UAAU,CAAC,kBAAkB,EAAE,yEAAyE,CAAC,CAAC;IAClH,CAAC;IAED,MAAM,aAAa,GAA2B,CAAC,CAAC,QAAsB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACjF,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAA4B,CAAC;QACjD,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrB,MAAM,WAAW,GAAG,IAAI,CAAC;QACzB,OAAO;YACL,EAAE;YACF,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YACnB,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;YACtC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YACrB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YACjB,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;YACjC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,QAAQ,CAAC;YACpD,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC;YACzC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI;YAC1G,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,cAAc,IAAI,WAAW,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI;SAC7E,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC;IAEtC,mFAAmF;IACnF,MAAM,cAAc,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,OAAO,GACX,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,GAAG,QAAQ,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC;IACzF,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5D,MAAM,KAAK,GAAa,CAAC,mBAAmB,CAAC,CAAC;IAC9C,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,2CAA2C,YAAY,yCAAyC,KAAK,IAAI,CAAC,CAAC;IACxH,CAAC;IACD,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,gGAAgG,CAAC,CAAC;IAC/G,CAAC;IAED,OAAO,QAAQ,CACb,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,EACvC;QACE,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,IAAI;QACjB,QAAQ;QACR,cAAc;QACd,cAAc,EAAE,CAAC,gBAAgB,EAAE,YAAY,CAAC;QAChD,cAAc,EAAE,EAAE;QAClB,iBAAiB,EAAE,EAAE;QACrB,UAAU,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE;QAChE,KAAK;KAC0B,CAClC,CAAC;AACJ,CAAC"}
package/dist/pricing.d.ts CHANGED
@@ -73,7 +73,7 @@ export declare function benchmarkLaborRates(args: {
73
73
  maxSamplePages?: number;
74
74
  }): Promise<import("./meta.js").MetaBundle<{
75
75
  laborCategory: string;
76
- matcher: "search" | "q";
76
+ matcher: "q" | "search";
77
77
  fuzzy: boolean;
78
78
  matchCount: number;
79
79
  matchCountSaturated: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,YAAY,EAKb,MAAM,oBAAoB,CAAC;AA66I5B,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,UAAU,CAAC;IAO1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE;QAAE,GAAG,EAAE,YAAY,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE,CAAC;AAoBF,eAAO,MAAM,KAAK,EAAE,OAAO,EA6vD1B,CAAC;AAkLF,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,OAAO,CAAC,CAkClB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,YAAY,EAKb,MAAM,oBAAoB,CAAC;AA4iJ5B,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,UAAU,CAAC;IAO1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE;QAAE,GAAG,EAAE,YAAY,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE,CAAC;AAoBF,eAAO,MAAM,KAAK,EAAE,OAAO,EAs0D1B,CAAC;AAkLF,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,OAAO,CAAC,CAkClB"}