@cliwant/mcp-sam-gov 1.9.0 → 1.11.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/README.ja.md +5 -5
- package/README.ko.md +5 -5
- package/README.md +19 -7
- package/dist/arcgis-feature.d.ts +68 -0
- package/dist/arcgis-feature.d.ts.map +1 -0
- package/dist/arcgis-feature.js +206 -0
- package/dist/arcgis-feature.js.map +1 -0
- package/dist/arcgis-hub.d.ts +90 -0
- package/dist/arcgis-hub.d.ts.map +1 -0
- package/dist/arcgis-hub.js +210 -0
- package/dist/arcgis-hub.js.map +1 -0
- package/dist/bonfire.d.ts +69 -0
- package/dist/bonfire.d.ts.map +1 -0
- package/dist/bonfire.js +212 -0
- package/dist/bonfire.js.map +1 -0
- package/dist/cbp-border.d.ts +9 -5
- package/dist/cbp-border.d.ts.map +1 -1
- package/dist/cbp-border.js +31 -11
- package/dist/cbp-border.js.map +1 -1
- package/dist/gao.d.ts.map +1 -1
- package/dist/gao.js +25 -0
- package/dist/gao.js.map +1 -1
- package/dist/grants.js +1 -1
- package/dist/grants.js.map +1 -1
- package/dist/gsa-perdiem.d.ts +16 -2
- package/dist/gsa-perdiem.d.ts.map +1 -1
- package/dist/gsa-perdiem.js +25 -4
- package/dist/gsa-perdiem.js.map +1 -1
- package/dist/integrity.d.ts.map +1 -1
- package/dist/integrity.js +18 -3
- package/dist/integrity.js.map +1 -1
- package/dist/lda.d.ts.map +1 -1
- package/dist/lda.js +17 -4
- package/dist/lda.js.map +1 -1
- package/dist/nhtsa.d.ts +9 -5
- package/dist/nhtsa.d.ts.map +1 -1
- package/dist/nhtsa.js +90 -26
- package/dist/nhtsa.js.map +1 -1
- package/dist/nist-controls.d.ts +3 -1
- package/dist/nist-controls.d.ts.map +1 -1
- package/dist/nist-controls.js +34 -12
- package/dist/nist-controls.js.map +1 -1
- package/dist/ofac.d.ts.map +1 -1
- package/dist/ofac.js +10 -1
- package/dist/ofac.js.map +1 -1
- package/dist/opengov.d.ts +96 -0
- package/dist/opengov.d.ts.map +1 -0
- package/dist/opengov.js +244 -0
- package/dist/opengov.js.map +1 -0
- package/dist/pricing.d.ts +1 -1
- package/dist/sam-gov/client.d.ts.map +1 -1
- package/dist/sam-gov/client.js +13 -4
- package/dist/sam-gov/client.js.map +1 -1
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +199 -8
- package/dist/server.js.map +1 -1
- package/dist/socrata.d.ts +27 -16
- package/dist/socrata.d.ts.map +1 -1
- package/dist/socrata.js +149 -18
- package/dist/socrata.js.map +1 -1
- package/package.json +11 -3
- package/src/arcgis-feature.ts +232 -0
- package/src/arcgis-hub.ts +270 -0
- package/src/bonfire.ts +249 -0
- package/src/cbp-border.ts +30 -9
- package/src/gao.ts +27 -0
- package/src/grants.ts +1 -1
- package/src/gsa-perdiem.ts +28 -4
- package/src/integrity.ts +18 -3
- package/src/lda.ts +21 -5
- package/src/nhtsa.ts +92 -27
- package/src/nist-controls.ts +58 -9
- package/src/ofac.ts +12 -1
- package/src/opengov.ts +309 -0
- package/src/sam-gov/client.ts +13 -4
- package/src/server.ts +213 -8
- package/src/socrata.ts +153 -18
package/README.ja.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @cliwant/mcp-sam-gov
|
|
2
2
|
|
|
3
3
|
> **最も包括的なキーレス連邦データ MCP サーバー。**
|
|
4
|
-
> SAM.gov · USAspending · SEC EDGAR · OFAC · FDIC · Federal Register · Regulations.gov · eCFR · FAR/DFARS · BLS · Treasury · NIH · NSF · ClinicalTrials · CMS · NVD/CISA · USITC · Census · FRED · BEA · DOL · FEMA · openFDA · NHTSA · CPSC · EPA Envirofacts · CourtListener · IRS-990(ProPublica) ほか **
|
|
4
|
+
> SAM.gov · USAspending · SEC EDGAR · OFAC · FDIC · Federal Register · Regulations.gov · eCFR · FAR/DFARS · BLS · Treasury · NIH · NSF · ClinicalTrials · CMS · NVD/CISA · USITC · Census · FRED · BEA · DOL · FEMA · openFDA · NHTSA · CPSC · EPA Envirofacts · CourtListener · IRS-990(ProPublica) ほか **52 のデータソース、150 ツール。** キーレス優先 — Census business-patterns · FRED · BEA · DOL データエンドポイントの 4 ソースのみ無料キーが必要で、残り 48 ソースはキー不要。
|
|
5
5
|
> API キー不要、登録不要、サインアップ不要。Claude Desktop, Claude Code, Codex CLI, Cursor, Continue, Gemini CLI、すべての MCP ホスト対応。
|
|
6
6
|
|
|
7
7
|
[English README](./README.md) · [한국어 README](./README.ko.md)
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
| 🌐 **貿易・地理・災害** | "この品目の HTS 関税、この住所の Census tract、この州の FEMA 宣言" | USITC HTS, Census, FEMA, Socrata, CKAN |
|
|
31
31
|
| 🎓 **grant・データセット** | "過去 30 日のサイバーセキュリティ grant、連邦オープンデータセット発見" | Grants.gov, data.gov |
|
|
32
32
|
|
|
33
|
-
**
|
|
33
|
+
**52 のデータソース、合計 150 ツール — キーレス優先: Census business-patterns · FRED · BEA · DOL データエンドポイントの 4 ソースのみ無料キーが必要で、残り 48 ソースはキー不要。** (初期の 52 ツール版でおおよそ p50 ~0.25s / p95 ~0.8s を計測 — ソースや上流負荷で変動する近似値であり保証値ではありません。)
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
@@ -57,7 +57,7 @@ Claude Code (CLI) を既に使用している場合:
|
|
|
57
57
|
/plugin install cliwant/mcp-sam-gov
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
MCP サーバー + Claude が
|
|
60
|
+
MCP サーバー + Claude が 150 ツールをいつ・どう呼ぶかを教える [SKILL.md ワークフローガイド](./skills/sam-gov/SKILL.md) を同時登録。
|
|
61
61
|
|
|
62
62
|
### 🔵 パス 3 — Codex / Cursor / Continue / Gemini 等の手動インストール
|
|
63
63
|
|
|
@@ -188,9 +188,9 @@ npm はインストール済みユーザーに新バージョンを通知しな
|
|
|
188
188
|
|
|
189
189
|
**自動投稿は一切ありません。** サーバーにトークンもアカウントもなく、リンクを作るだけで、開いて送信するのは**あなた**です。事前入力リンクにはツール名・エラー種別・サーバーバージョンのみが含まれ、クエリ値は含まれません。公開リポジトリなので、機微な内容は削除してから送信してください。直接開く: [**New issue**](https://github.com/cliwant/mcp-sam-gov/issues/new/choose)。
|
|
190
190
|
|
|
191
|
-
## ツールカタログ (
|
|
191
|
+
## ツールカタログ (150)
|
|
192
192
|
|
|
193
|
-
ワークフロー別グループ。キーレス優先 — 大半はキー不要、Census business-patterns · FRED · BEA · DOL データエンドポイントは無料キーが必要。全 per-tool 一覧と入力 schema・誠実性 caveat の原文は [英語 README のカタログセクション](./README.md#tool-catalog-
|
|
193
|
+
ワークフロー別グループ。キーレス優先 — 大半はキー不要、Census business-patterns · FRED · BEA · DOL データエンドポイントは無料キーが必要。全 per-tool 一覧と入力 schema・誠実性 caveat の原文は [英語 README のカタログセクション](./README.md#tool-catalog-150-tools) を正とします。
|
|
194
194
|
|
|
195
195
|
- **案件 + ソリシテーション — SAM.gov + Grants.gov (10)**: `sam_search_opportunities` `sam_search_shaping` `sam_get_opportunity` `sam_fetch_description` `sam_fetch_attachment_text` `sam_attachment_url` `sam_lookup_organization` `sam_lookup_notice_fields` `grants_search` `grants_get_opportunity`
|
|
196
196
|
- **spending・受注・競合 — USAspending + FPDS + GAO (31)**: `usas_search_awards` `usas_search_individual_awards` `usas_get_award_detail` `usas_search_awards_by_recipient` `usas_search_subawards` `usas_search_recompetes` `usas_search_expiring_contracts`(deprecated) `usas_analyze_incumbent` `usas_search_teaming_partners` `usas_spending_over_time` `usas_search_agency_spending` `usas_search_subagency_spending` `usas_search_psc_spending` `usas_search_cfda_spending` `usas_search_state_spending` `usas_search_federal_account_spending` `usas_search_recipients` `usas_get_recipient_profile` `usas_get_agency_profile` `usas_get_agency_awards_summary` `usas_get_agency_budget_function` `usas_list_toptier_agencies` `usas_lookup_agency` `usas_autocomplete_naics` `usas_autocomplete_recipient` `usas_naics_hierarchy` `usas_glossary` `usas_list_disaster_codes`(災害緊急基金コード(DEFC)一覧 — COVID-19·IIJA/インフラ等の緊急歳出タグ) `usas_disaster_spending`(指定 DEFC の災害/緊急基金支出の地域別内訳 — どの州/郡/選挙区が COVID/IIJA 救済金を受領) `fpds_search_awards` `gao_protest_lookup`
|
package/README.ko.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @cliwant/mcp-sam-gov
|
|
2
2
|
|
|
3
3
|
> **가장 포괄적인 keyless 연방 데이터 MCP 서버.**
|
|
4
|
-
> SAM.gov · USAspending · SEC EDGAR · OFAC · FDIC · Federal Register · Regulations.gov · eCFR · FAR/DFARS · BLS · Treasury · NIH · NSF · ClinicalTrials · CMS · NVD/CISA · USITC · Census · FRED · BEA · DOL · FEMA · openFDA · NHTSA · CPSC · EPA Envirofacts · CourtListener · IRS-990(ProPublica) 외 **
|
|
4
|
+
> SAM.gov · USAspending · SEC EDGAR · OFAC · FDIC · Federal Register · Regulations.gov · eCFR · FAR/DFARS · BLS · Treasury · NIH · NSF · ClinicalTrials · CMS · NVD/CISA · USITC · Census · FRED · BEA · DOL · FEMA · openFDA · NHTSA · CPSC · EPA Envirofacts · CourtListener · IRS-990(ProPublica) 외 **52개 데이터 소스, 150개 도구.** keyless 우선 — Census business-patterns · FRED · BEA · DOL 데이터 엔드포인트 4개 소스만 무료 키가 필요하고 나머지 48개 소스는 키가 필요 없습니다.
|
|
5
5
|
> API 키 / 등록 / 가입 불필요. Claude Desktop, Claude Code, Codex CLI, Cursor, Continue, Gemini CLI, 모든 MCP 호스트 호환.
|
|
6
6
|
|
|
7
7
|
[English README](./README.md) · [日本語 README](./README.ja.md)
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
| 🌐 **무역·지리·재난** | "이 품목 HTS 관세, 이 주소 Census tract, 이 주의 FEMA 선포" | USITC HTS, Census, FEMA, Socrata, CKAN |
|
|
31
31
|
| 🎓 **grant·데이터셋** | "최근 30일 사이버보안 grant, 연방 오픈 데이터셋 발굴" | Grants.gov, data.gov |
|
|
32
32
|
|
|
33
|
-
**
|
|
33
|
+
**52개 데이터 소스, 총 150개 도구 — keyless 우선: Census business-patterns · FRED · BEA · DOL 데이터 엔드포인트 4개 소스만 무료 키가 필요하고 나머지 48개 소스는 키가 필요 없습니다.** (초기 52-도구 빌드 기준 대략 p50 ~0.25s / p95 ~0.8s 측정 — 소스·업스트림 부하에 따라 변동하는 근사치이며 보장값이 아님.)
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
@@ -57,7 +57,7 @@ PowerShell, npm 등 필요 없음.
|
|
|
57
57
|
/plugin install cliwant/mcp-sam-gov
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
MCP 서버 + Claude 가
|
|
60
|
+
MCP 서버 + Claude 가 150개 도구를 언제 / 어떻게 호출할지 가르치는 [SKILL.md 워크플로 가이드](./skills/sam-gov/SKILL.md) 동시 등록.
|
|
61
61
|
|
|
62
62
|
### 🔵 경로 3 — Codex / Cursor / Continue / Gemini 등 수동 설치
|
|
63
63
|
|
|
@@ -188,9 +188,9 @@ npm은 설치한 사용자에게 새 버전을 알려주지 않으므로, 서버
|
|
|
188
188
|
|
|
189
189
|
**자동 제출은 절대 없습니다.** 서버엔 토큰·계정이 없고 링크만 만들며, 열어서 제출하는 건 **사용자**입니다. 프리필 링크에는 툴명·에러종류·서버버전만 담기고 쿼리값은 담기지 않습니다. 공개 레포이니 민감한 내용은 지우고 제출하세요. 직접 열기: [**New issue**](https://github.com/cliwant/mcp-sam-gov/issues/new/choose).
|
|
190
190
|
|
|
191
|
-
## 도구 카탈로그 (
|
|
191
|
+
## 도구 카탈로그 (150개)
|
|
192
192
|
|
|
193
|
-
워크플로별 그룹. keyless 우선 — 대부분 키가 필요 없고, Census business-patterns · FRED · BEA · DOL 데이터 엔드포인트는 무료 키가 필요합니다. 전체 per-tool 목록과 입력 schema·정직성 caveat 원문은 [영문 README 의 카탈로그 섹션](./README.md#tool-catalog-
|
|
193
|
+
워크플로별 그룹. keyless 우선 — 대부분 키가 필요 없고, Census business-patterns · FRED · BEA · DOL 데이터 엔드포인트는 무료 키가 필요합니다. 전체 per-tool 목록과 입력 schema·정직성 caveat 원문은 [영문 README 의 카탈로그 섹션](./README.md#tool-catalog-150-tools)을 기준으로 하세요.
|
|
194
194
|
|
|
195
195
|
- **입찰 + 솔리시테이션 — SAM.gov + Grants.gov (10)**: `sam_search_opportunities` `sam_search_shaping` `sam_get_opportunity` `sam_fetch_description` `sam_fetch_attachment_text` `sam_attachment_url` `sam_lookup_organization` `sam_lookup_notice_fields` `grants_search` `grants_get_opportunity`
|
|
196
196
|
- **spending·수주·경쟁 — USAspending + FPDS + GAO (31)**: `usas_search_awards` `usas_search_individual_awards` `usas_get_award_detail` `usas_search_awards_by_recipient` `usas_search_subawards` `usas_search_recompetes` `usas_search_expiring_contracts`(deprecated) `usas_analyze_incumbent` `usas_search_teaming_partners` `usas_spending_over_time` `usas_search_agency_spending` `usas_search_subagency_spending` `usas_search_psc_spending` `usas_search_cfda_spending` `usas_search_state_spending` `usas_search_federal_account_spending` `usas_search_recipients` `usas_get_recipient_profile` `usas_get_agency_profile` `usas_get_agency_awards_summary` `usas_get_agency_budget_function` `usas_list_toptier_agencies` `usas_lookup_agency` `usas_autocomplete_naics` `usas_autocomplete_recipient` `usas_naics_hierarchy` `usas_glossary` `usas_list_disaster_codes`(재난긴급자금코드(DEFC) 목록 — COVID-19·IIJA/인프라 등 긴급세출 태그) `usas_disaster_spending`(지정 DEFC의 재난/긴급자금 지출 지역별 분해 — 어느 주/카운티/선거구가 COVID/IIJA 구호금 수령) `fpds_search_awards` `gao_protest_lookup`
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
### **$4 trillion of public federal data, one `npm install` away.**
|
|
6
6
|
|
|
7
|
-
The most comprehensive **keyless-first** MCP server for US federal contracting + spending + regulation + partner vetting. **
|
|
7
|
+
The most comprehensive **keyless-first** MCP server for US federal **and state/local (SLED)** contracting + spending + regulation + partner vetting. **150 tools across 52 data sources** — keyless-first: only 4 sources (Census business-patterns, FRED, BEA, and DOL's data endpoint) need a free key; the other 48 need none. Works today, in any AI agent.
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@cliwant/mcp-sam-gov)
|
|
10
10
|
[](https://registry.modelcontextprotocol.io/v0/servers?search=cliwant)
|
|
@@ -50,7 +50,7 @@ The most comprehensive **keyless-first** MCP server for US federal contracting +
|
|
|
50
50
|
|---|---|
|
|
51
51
|
| GovWin: $30K-$100K/yr per seat | Free, MIT license |
|
|
52
52
|
| API key registration → wait 24h → quota tier shopping | `npm install` → working in 60s |
|
|
53
|
-
| 5+ separate vendor APIs / scrapers | 1 unified surface,
|
|
53
|
+
| 5+ separate vendor APIs / scrapers | 1 unified surface, 150 tools across 52 sources |
|
|
54
54
|
| LLMs hallucinate NAICS codes / agency names | Anti-hallucination autocomplete guards built-in |
|
|
55
55
|
| Brittle scraping breaks weekly | Daily live smoke test ([badge above](#)) |
|
|
56
56
|
| Procurement officer → IT ticket → 3-week wait | Claude Desktop double-click install |
|
|
@@ -77,9 +77,10 @@ The federal data this wraps is **public domain**. There is no good reason it sho
|
|
|
77
77
|
| 🏥 **Health & research funding** | "NIH/NSF grants on this topic; recruiting clinical trials; industry payments to this physician" | NIH RePORTER, NSF, ClinicalTrials.gov, CMS Open Payments, NPPES |
|
|
78
78
|
| 🛡 **Cyber compliance** | "Is this CVE on the CISA KEV must-patch list?" | NVD, CISA KEV |
|
|
79
79
|
| 🌐 **Trade, geo & disaster** | "HTS tariff for this product; Census tract for this address; FEMA declarations in this state" | USITC HTS, US Census, FEMA, Socrata, CKAN |
|
|
80
|
+
| 🏙 **State/local procurement bids (SLED)** | "What's open on this city's/county's procurement portal right now? Their checkbook, awarded contracts, vendor payments; state DOT bid/award registers" | OpenGov Procurement (525+ govs), Bonfire, ArcGIS (feature + Hub), Socrata (53 hosts) |
|
|
80
81
|
| 🎓 **Grants & datasets** | "Cybersecurity grants posted in the last 30 days; discover federal open datasets" | Grants.gov, data.gov |
|
|
81
82
|
|
|
82
|
-
**
|
|
83
|
+
**150 tools across 52 data sources — keyless-first: only 4 sources (Census business-patterns, FRED, BEA, and DOL's data endpoint) need a free key; the other 48 need none.** (An earlier 52-tool build measured roughly p50 ~0.25s / p95 ~0.8s against production federal APIs; latency varies by source and upstream load — treat it as fast, not a benchmarked guarantee.)
|
|
83
84
|
|
|
84
85
|
---
|
|
85
86
|
|
|
@@ -106,7 +107,7 @@ If you already use Claude Code (the CLI):
|
|
|
106
107
|
/plugin install cliwant/mcp-sam-gov
|
|
107
108
|
```
|
|
108
109
|
|
|
109
|
-
This installs the MCP server **plus** a [SKILL.md](./skills/sam-gov/SKILL.md) workflow guide that teaches Claude when + how to use each of the
|
|
110
|
+
This installs the MCP server **plus** a [SKILL.md](./skills/sam-gov/SKILL.md) workflow guide that teaches Claude when + how to use each of the 150 tools.
|
|
110
111
|
|
|
111
112
|
### 🔵 Path 3 — Manual install for any MCP host (Codex, Cursor, Continue, Gemini)
|
|
112
113
|
|
|
@@ -174,7 +175,7 @@ Then point your host config at the absolute path:
|
|
|
174
175
|
|
|
175
176
|
(Or skip this entirely — use Path 1's `.mcpb` and it auto-configures.)
|
|
176
177
|
|
|
177
|
-
Restart Claude Desktop fully (system tray quit on Windows / Quit menu on macOS), then look for the 🔨 icon. You should see "sam-gov (
|
|
178
|
+
Restart Claude Desktop fully (system tray quit on Windows / Quit menu on macOS), then look for the 🔨 icon. You should see "sam-gov (150 tools)".
|
|
178
179
|
|
|
179
180
|
### Claude Code
|
|
180
181
|
|
|
@@ -399,7 +400,7 @@ This server is built to **improve from real usage**. Because an AI agent (not a
|
|
|
399
400
|
|
|
400
401
|
You can also open one directly: [**New issue**](https://github.com/cliwant/mcp-sam-gov/issues/new/choose) — bug / feature / wrong-output templates.
|
|
401
402
|
|
|
402
|
-
## Tool catalog (
|
|
403
|
+
## Tool catalog (150 tools)
|
|
403
404
|
|
|
404
405
|
Grouped by workflow. Keyless-first — most tools need no key; Census business-patterns, FRED, BEA, and DOL's data endpoint require a free key, and a handful of others gain higher limits from an optional free key (noted above). Descriptions are condensed — each tool's own `inputSchema` carries the full contract and honesty caveats.
|
|
405
406
|
|
|
@@ -604,11 +605,22 @@ Grouped by workflow. Keyless-first — most tools need no key; Census business-p
|
|
|
604
605
|
- `fema_search_hazard_mitigation` — FEMA Hazard Mitigation Assistance projects (HMGP/FMA/PDM/BRIC mitigation grants to state/local/tribal subrecipients; disaster-resilience, distinct from Public Assistance recovery)
|
|
605
606
|
- `nws_active_alerts` — currently-active NWS weather alerts (watches/warnings/advisories; disaster/climate readiness, pairs with the FEMA tools)
|
|
606
607
|
- `socrata_discover_datasets` — find Socrata dataset 4x4 ids by keyword
|
|
607
|
-
- `socrata_query` — query rows from an allowlisted Socrata/SODA open-data portal
|
|
608
|
+
- `socrata_query` — query rows from an allowlisted Socrata/SODA open-data portal (**53 curated state/county/city + federal hosts** — checkbook, contracts, vendor payments, live solicitations across the SLED tier)
|
|
608
609
|
- `ckan_discover_datasets` — find CKAN datastore resource ids by keyword
|
|
609
610
|
- `ckan_query` — query rows from an allowlisted CKAN datastore resource (state/city spend/checkbook)
|
|
610
611
|
</details>
|
|
611
612
|
|
|
613
|
+
<details>
|
|
614
|
+
<summary><b>State/local procurement bids (SLED) — OpenGov · Bonfire · ArcGIS (6 tools)</b></summary>
|
|
615
|
+
|
|
616
|
+
- `opengov_list_governments` — directory of 525+ US state/local governments on **OpenGov Procurement** (filter by state/query)
|
|
617
|
+
- `opengov_search_solicitations` — a government's **live public solicitations** (title, status [open = accepting], deadline, portal link) — keyless anonymous endpoints
|
|
618
|
+
- `bonfire_list_organizations` — curated live-verified 186-org US seed directory of governments on **Bonfire (Euna)**
|
|
619
|
+
- `bonfire_search_opportunities` — an org's currently-open opportunities via keyless RSS (referenceNumber, name, closeDate, link); the RSS is the complete open set (exact total)
|
|
620
|
+
- `arcgis_hub_discover_datasets` — discover ArcGIS Hub datasets by keyword (the SLED GIS/infrastructure/permits/procurement layer Socrata & CKAN don't cover; a discovery aid with publisher surfaced for vetting)
|
|
621
|
+
- `arcgis_feature_query` — query rows from a curated allowlist of **23 US-gov ArcGIS REST feature layers**: DC OCP PASS live solicitations; local-gov checkbooks/contracts; **state DOT bid/award registers (TX / AK / IA / OK)**
|
|
622
|
+
</details>
|
|
623
|
+
|
|
612
624
|
<details>
|
|
613
625
|
<summary><b>Dataset & registry discovery — data.gov · get.gov (2 tools)</b></summary>
|
|
614
626
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* arcgis-feature.ts — generic ArcGIS REST FeatureServer/MapServer layer query
|
|
3
|
+
* over a CURATED service allowlist (loop — SLED bid campaign, 2026-07-19).
|
|
4
|
+
*
|
|
5
|
+
* WHAT IT ADDS: an enormous amount of US government data (esp. SLED procurement /
|
|
6
|
+
* GIS / infrastructure) is published as ArcGIS REST feature layers. This is the
|
|
7
|
+
* QUERY companion to `arcgis_hub_discover_datasets` (which DISCOVERS Hub datasets):
|
|
8
|
+
* it queries the ROWS of a curated set of high-value ArcGIS layers. First payload:
|
|
9
|
+
* the DC OCP "PASS" procurement layers (solicitations / contracts / purchase
|
|
10
|
+
* orders / payments) — DC's live open-solicitation feed with 46 fields, keyless.
|
|
11
|
+
*
|
|
12
|
+
* The module REUSES `getJson` (redirect:"error") / `driftError` / `num`·`str` /
|
|
13
|
+
* `withMeta`·`buildMeta`, mirroring socrata.ts (curated allowlist) + datagov-
|
|
14
|
+
* catalog.ts. KEYLESS.
|
|
15
|
+
*
|
|
16
|
+
* ★ SSRF: the caller supplies a `service` ENUM key (never a free host/URL); each
|
|
17
|
+
* allowlist entry is a FIXED, live-verified ArcGIS layer base URL. The query
|
|
18
|
+
* URL is built on that fixed base, and a post-construction assertion requires
|
|
19
|
+
* the built hostname === the allowlist entry's host (over https) BEFORE the
|
|
20
|
+
* fetch; `redirect:"error"`. `where`/`outFields`/`orderByFields` ride in
|
|
21
|
+
* URLSearchParams (encoded) — they filter/project the read-only layer and
|
|
22
|
+
* CANNOT alter the host (a malformed `where` ⇒ upstream 400 ⇒ invalid_input,
|
|
23
|
+
* surfaced, never silent). Adding a service later = an allowlist SOURCE edit +
|
|
24
|
+
* a live count/`/query` verification — NEVER a free runtime param.
|
|
25
|
+
*
|
|
26
|
+
* ★ HONESTY PILLARS (captured live 2026-07-19):
|
|
27
|
+
* P1: totalAvailable = the layer's EXACT match count (a `returnCountOnly=true`
|
|
28
|
+
* companion query), NEVER the page length. Best-effort: a count failure ⇒
|
|
29
|
+
* totalAvailable:null + a note (the rows are still returned) — never a fake
|
|
30
|
+
* total. `exceededTransferLimit` also forces hasMore.
|
|
31
|
+
* P2: getJson THROWS on 429/5xx/timeout; an ArcGIS `{error:{code,message}}`
|
|
32
|
+
* body (HTTP 200) is classified (400 ⇒ invalid_input, else upstream) and
|
|
33
|
+
* THROWN — never a fake empty. A genuine no-match (features:[], count:0) ⇒
|
|
34
|
+
* honest empty.
|
|
35
|
+
* P3: attributes pass through VERBATIM (they are the layer's own record). NOTE
|
|
36
|
+
* (disclosed every response): ArcGIS date fields are epoch MILLISECONDS and a
|
|
37
|
+
* negative/sentinel value (e.g. -2209093200000 ≈ year 1900) is a placeholder,
|
|
38
|
+
* not a real date — surfaced verbatim, never coerced.
|
|
39
|
+
* P4: `body.features` absent/non-array (and no error) ⇒ driftError; a 200
|
|
40
|
+
* non-JSON body ⇒ schema_drift via the catch-ladder.
|
|
41
|
+
*/
|
|
42
|
+
import { num } from "./coerce.js";
|
|
43
|
+
import { type MetaBundle } from "./meta.js";
|
|
44
|
+
export { num };
|
|
45
|
+
export type ArcgisService = {
|
|
46
|
+
key: string;
|
|
47
|
+
base: string;
|
|
48
|
+
label: string;
|
|
49
|
+
note: string;
|
|
50
|
+
};
|
|
51
|
+
export declare const ARCGIS_SERVICES: readonly ArcgisService[];
|
|
52
|
+
export type ArcgisFeatureQueryArgs = {
|
|
53
|
+
service: string;
|
|
54
|
+
where?: string;
|
|
55
|
+
outFields?: string;
|
|
56
|
+
orderByFields?: string;
|
|
57
|
+
limit?: number;
|
|
58
|
+
offset?: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Query rows from a curated ArcGIS REST feature layer. `service` is an allowlist
|
|
62
|
+
* enum; `where` (SQL-ish filter, default 1=1), `outFields` (default *),
|
|
63
|
+
* `orderByFields`, `limit`/`offset`. Returns curated record attributes + honest
|
|
64
|
+
* `_meta` (totalAvailable = the layer's exact match count via a returnCountOnly
|
|
65
|
+
* companion; epoch-ms date disclosure).
|
|
66
|
+
*/
|
|
67
|
+
export declare function featureQuery(args: ArcgisFeatureQueryArgs): Promise<MetaBundle>;
|
|
68
|
+
//# sourceMappingURL=arcgis-feature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arcgis-feature.d.ts","sourceRoot":"","sources":["../src/arcgis-feature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAIH,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAY,KAAK,UAAU,EAAqB,MAAM,WAAW,CAAC;AAEzE,OAAO,EAAE,GAAG,EAAE,CAAC;AAMf,MAAM,MAAM,aAAa,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACvF,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EA2B1C,CAAC;AAmDX,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmFpF"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* arcgis-feature.ts — generic ArcGIS REST FeatureServer/MapServer layer query
|
|
3
|
+
* over a CURATED service allowlist (loop — SLED bid campaign, 2026-07-19).
|
|
4
|
+
*
|
|
5
|
+
* WHAT IT ADDS: an enormous amount of US government data (esp. SLED procurement /
|
|
6
|
+
* GIS / infrastructure) is published as ArcGIS REST feature layers. This is the
|
|
7
|
+
* QUERY companion to `arcgis_hub_discover_datasets` (which DISCOVERS Hub datasets):
|
|
8
|
+
* it queries the ROWS of a curated set of high-value ArcGIS layers. First payload:
|
|
9
|
+
* the DC OCP "PASS" procurement layers (solicitations / contracts / purchase
|
|
10
|
+
* orders / payments) — DC's live open-solicitation feed with 46 fields, keyless.
|
|
11
|
+
*
|
|
12
|
+
* The module REUSES `getJson` (redirect:"error") / `driftError` / `num`·`str` /
|
|
13
|
+
* `withMeta`·`buildMeta`, mirroring socrata.ts (curated allowlist) + datagov-
|
|
14
|
+
* catalog.ts. KEYLESS.
|
|
15
|
+
*
|
|
16
|
+
* ★ SSRF: the caller supplies a `service` ENUM key (never a free host/URL); each
|
|
17
|
+
* allowlist entry is a FIXED, live-verified ArcGIS layer base URL. The query
|
|
18
|
+
* URL is built on that fixed base, and a post-construction assertion requires
|
|
19
|
+
* the built hostname === the allowlist entry's host (over https) BEFORE the
|
|
20
|
+
* fetch; `redirect:"error"`. `where`/`outFields`/`orderByFields` ride in
|
|
21
|
+
* URLSearchParams (encoded) — they filter/project the read-only layer and
|
|
22
|
+
* CANNOT alter the host (a malformed `where` ⇒ upstream 400 ⇒ invalid_input,
|
|
23
|
+
* surfaced, never silent). Adding a service later = an allowlist SOURCE edit +
|
|
24
|
+
* a live count/`/query` verification — NEVER a free runtime param.
|
|
25
|
+
*
|
|
26
|
+
* ★ HONESTY PILLARS (captured live 2026-07-19):
|
|
27
|
+
* P1: totalAvailable = the layer's EXACT match count (a `returnCountOnly=true`
|
|
28
|
+
* companion query), NEVER the page length. Best-effort: a count failure ⇒
|
|
29
|
+
* totalAvailable:null + a note (the rows are still returned) — never a fake
|
|
30
|
+
* total. `exceededTransferLimit` also forces hasMore.
|
|
31
|
+
* P2: getJson THROWS on 429/5xx/timeout; an ArcGIS `{error:{code,message}}`
|
|
32
|
+
* body (HTTP 200) is classified (400 ⇒ invalid_input, else upstream) and
|
|
33
|
+
* THROWN — never a fake empty. A genuine no-match (features:[], count:0) ⇒
|
|
34
|
+
* honest empty.
|
|
35
|
+
* P3: attributes pass through VERBATIM (they are the layer's own record). NOTE
|
|
36
|
+
* (disclosed every response): ArcGIS date fields are epoch MILLISECONDS and a
|
|
37
|
+
* negative/sentinel value (e.g. -2209093200000 ≈ year 1900) is a placeholder,
|
|
38
|
+
* not a real date — surfaced verbatim, never coerced.
|
|
39
|
+
* P4: `body.features` absent/non-array (and no error) ⇒ driftError; a 200
|
|
40
|
+
* non-JSON body ⇒ schema_drift via the catch-ladder.
|
|
41
|
+
*/
|
|
42
|
+
import { ToolErrorCarrier } from "./errors.js";
|
|
43
|
+
import { getJson, driftError } from "./datasource.js";
|
|
44
|
+
import { num } from "./coerce.js";
|
|
45
|
+
import { withMeta } from "./meta.js";
|
|
46
|
+
export { num };
|
|
47
|
+
export const ARCGIS_SERVICES = [
|
|
48
|
+
{ key: "dc_pass_solicitations", base: "https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Government_Operations/MapServer/19", label: "DC OCP PASS — Solicitations", note: "DC Office of Contracting & Procurement live solicitations (SOLICITATIONNUMBER, SOLICITATIONTITLE, DUE_DATE, OPENDATE, CLOSEDATE, NIGPCODE, CONTRACTINGOFFICER, AWARD_TO…). ~25k." },
|
|
49
|
+
{ key: "dc_pass_contracts", base: "https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Government_Operations/MapServer/37", label: "DC OCP PASS — Contracts", note: "DC awarded contracts. ~50k." },
|
|
50
|
+
{ key: "dc_pass_purchase_orders", base: "https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Government_Operations/MapServer/16", label: "DC OCP PASS — Purchase Orders", note: "DC purchase orders. ~275k." },
|
|
51
|
+
{ key: "dc_pass_payments", base: "https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Government_Operations/MapServer/17", label: "DC OCP PASS — Payments", note: "DC vendor payments. ~1.55M." },
|
|
52
|
+
// ── Additional US local-gov procurement layers (loop, 2026-07-19) — found via
|
|
53
|
+
// arcgis_hub_discover_datasets, each on a reachable Esri-hosted services*.
|
|
54
|
+
// arcgis.com endpoint (NOT WAF-gated) + live-verified returnCountOnly. ──
|
|
55
|
+
{ key: "asheville_purchase_orders", base: "https://services.arcgis.com/aJ16ENn1AaqdFlqx/ArcGIS/rest/services/Financials/FeatureServer/9", label: "Asheville NC — Purchase Order Line Items", note: "City of Asheville NC purchase-order line items. ~62.8k." },
|
|
56
|
+
{ key: "asheville_po_summary", base: "https://services.arcgis.com/aJ16ENn1AaqdFlqx/ArcGIS/rest/services/Financials/FeatureServer/8", label: "Asheville NC — Purchase Order Summary", note: "City of Asheville NC purchase-order summary. ~18.7k." },
|
|
57
|
+
{ key: "bellevue_vendor_payments", base: "https://services1.arcgis.com/EYzEZbDhXZjURPbP/arcgis/rest/services/YTD_Vendor_Payments/FeatureServer/0", label: "Bellevue WA — YTD Vendor Payments", note: "City of Bellevue WA year-to-date vendor payments. ~15.8k." },
|
|
58
|
+
{ key: "bellevue_awarded_contracts", base: "https://services1.arcgis.com/EYzEZbDhXZjURPbP/arcgis/rest/services/Annual_Awarded_Contracts/FeatureServer/0", label: "Bellevue WA — Annual Awarded Contracts", note: "City of Bellevue WA annual awarded contracts. ~2.0k." },
|
|
59
|
+
{ key: "miamidade_purchase_orders_2017", base: "https://services.arcgis.com/8Pc9XBTAsYuxx9Ny/arcgis/rest/services/miamidade_procurement_data_2017/FeatureServer/0", label: "Miami-Dade County FL — Purchase Orders (ADPICS) 2017", note: "Miami-Dade County FL purchase orders — a 2017 snapshot (historical, disclosed). ~94.8k." },
|
|
60
|
+
{ key: "miamidade_purchase_orders_2025", base: "https://services.arcgis.com/8Pc9XBTAsYuxx9Ny/arcgis/rest/services/miamidade_procurement_data_informs_2025/FeatureServer/0", label: "Miami-Dade County FL — Purchase Orders (INFORMS) 2025", note: "Miami-Dade County FL purchase orders — CURRENT (2025 INFORMS). ~25k." },
|
|
61
|
+
{ key: "suffolk_county_ny_contracts_2018", base: "https://services.arcgis.com/JsDD4qdG5r2a7hR5/arcgis/rest/services/County_Contracts_2018/FeatureServer/0", label: "Suffolk County NY — County Contracts 2018", note: "Suffolk County NY contracts — a 2018 snapshot (historical, disclosed). ~1.4k." },
|
|
62
|
+
{ key: "matsu_borough_ak_checkbook", base: "https://services.arcgis.com/fX5IGselyy1TirdY/arcgis/rest/services/Logos_Checkbook_Data/FeatureServer/0", label: "Matanuska-Susitna Borough AK — Checkbook", note: "Matanuska-Susitna Borough AK checkbook (vendor spend). ~1.2k." },
|
|
63
|
+
{ key: "lasvegas_checkbook", base: "https://services1.arcgis.com/F1v0ufATbBQScMtY/arcgis/rest/services/Processed_Checkbook_Table_View/FeatureServer/0", label: "City of Las Vegas NV — Open Checkbook", note: "City of Las Vegas NV checkbook (DEPARTMENT/VENDOR/TRANSACTION_AMOUNT/TRANSACTION_DATE). ~373k." },
|
|
64
|
+
{ key: "baltimore_checkbook", base: "https://services1.arcgis.com/UWYHeuuJISiGmgXx/arcgis/rest/services/OpenCheckbookFY2022_Through_Present/FeatureServer/0", label: "Baltimore City MD — Open Checkbook (FY2022–present)", note: "Baltimore City MD checkbook, FY2022 through present (Supplier_Name/Payment_Amount/Supplier_Contract_Number/Agency). ~367k." },
|
|
65
|
+
{ key: "naperville_vendor_payments", base: "https://services1.arcgis.com/rXJ6QApc2sOtl1Pd/arcgis/rest/services/Expenditures_2018_to_Current_Year/FeatureServer/0", label: "City of Naperville IL — Vendor Payments (2018–current)", note: "City of Naperville IL vendor payments, 2018 to current year (Vendor_Name/Payment_Amount/Purch_Order_No/Check_Date). ~127k." },
|
|
66
|
+
{ key: "worcester_ma_checkbook_fy25", base: "https://services1.arcgis.com/j8dqo2DJE7mVUBU1/arcgis/rest/services/Fiscal_Year_2025_Open_Checkbook/FeatureServer/0", label: "City of Worcester MA — Open Checkbook FY2025", note: "City of Worcester MA open checkbook, FY2025 (Payee/Pmt_Amount/Departments/Spend_Categories/Pmt_Date). ~38k." },
|
|
67
|
+
{ key: "lasvegas_purchasing_contracts", base: "https://services1.arcgis.com/F1v0ufATbBQScMtY/arcgis/rest/services/Purchasing_Contracts__view/FeatureServer/0", label: "City of Las Vegas NV — Purchasing Contracts", note: "City of Las Vegas NV purchasing contract register (Project_Number/Project_Name/Supplier_Name/Award_Date/Termination_Date). ~3.4k, all with a supplier. Complements lasvegas_checkbook (payments)." },
|
|
68
|
+
{ key: "txdot_construction_projects", base: "https://services.arcgis.com/KTcxiTD9dsQw4r7Z/arcgis/rest/services/TxDOT_Projects_Info_All/FeatureServer/0", label: "Texas DOT — Projects (with awarded construction company)", note: "Texas Department of Transportation highway projects (CNSTR_CMPNY_NM awarded construction company/CNSTR_NTPD_DT notice-to-proceed/TYPE_OF_WORK/HWY_NBR). ~85k rows, ~14.1k with an awarded contractor (filter CNSTR_CMPNY_NM IS NOT NULL for awards)." },
|
|
69
|
+
{ key: "akdot_construction_awards", base: "https://services.arcgis.com/r4A0V7UzH9fcLVvv/arcgis/rest/services/AWARDS_DASHBOARD_AWARDS_TABLE_POINTS/FeatureServer/0", label: "Alaska DOT&PF — Construction Bid Awards", note: "Alaska Department of Transportation & Public Facilities construction bid awards (ContractID/Contractor/Bids_Received/Engineer_Est/Award_Amount/Advertised_Date/Bid_Opening_Date/Reg_Award_Date/DOT_Region). ~1.1k." },
|
|
70
|
+
{ key: "akdot_aashtoware_proposals", base: "https://services.arcgis.com/r4A0V7UzH9fcLVvv/arcgis/rest/services/AASHTOWARE_Proposals_Points/FeatureServer/0", label: "Alaska DOT&PF — AASHTOWARE Proposals/Lettings", note: "Alaska DOT&PF AASHTOWARE proposals & lettings with awarded vendor (ProposalId/LettingId/StateProjectNumber/RefVendor_LongName/RefVendor_DBECertStatus/AwardedAmount/Contract_ID/FundType). ~1k, ~1,035 with an AwardedAmount>0. Complements akdot_construction_awards." },
|
|
71
|
+
{ key: "iowadot_public_bid_awards", base: "https://services.arcgis.com/8lRhdTsQyJpO52F1/arcgis/rest/services/Project_Scheduling_Public_Bid_Point_View/FeatureServer/0", label: "Iowa DOT — Public Bid / Project Scheduling", note: "Iowa Department of Transportation public bid & project scheduling (PROJECT_NUMBER/WORK_DESC/LETTING_FISCAL_YEAR/PROGRAM_ESTIMATE/CONTRACT_AWARDED/AWARDED/FINAL_CONTRACT/CONTRACTOR/CONTRACT_ID/STATUS). ~360." },
|
|
72
|
+
{ key: "okdot_cirb_contract_status", base: "https://services6.arcgis.com/RBtoEUQ2lmN0K3GY/arcgis/rest/services/CIRB_Project_Status/FeatureServer/0", label: "Oklahoma DOT — CIRB Contract Status", note: "Oklahoma Department of Transportation County Improvements for Roads & Bridges (CIRB) contract status (T_PROJECT/JP_DESCRIPTION/A_CONTRACT_AMOUNT/A_AMOUNT_EARNED/A_AMOUNT_PAID/D_LET_DATE/D_CONTRACT_AWARD_DATE/D_WORK_ORDER_DATE). ~780." },
|
|
73
|
+
{ key: "topeka_checkbook_aggregate", base: "https://services1.arcgis.com/EvtgI3PZ9PyCGJZS/arcgis/rest/services/Checkbook_Aggregate/FeatureServer/0", label: "City of Topeka KS — Open Checkbook (aggregate FY2015–2023)", note: "City of Topeka KS open checkbook, all years aggregated FY2015–2023 (fiscal_year/fiscal_period/department/program/fund/vendor_name/description/dollars). ~332k rows, ~323.6k with dollars>0." },
|
|
74
|
+
];
|
|
75
|
+
const SERVICE_BY_KEY = new Map(ARCGIS_SERVICES.map((s) => [s.key, s]));
|
|
76
|
+
const DATE_NOTE = "ArcGIS date fields are epoch MILLISECONDS (e.g. DUE_DATE, OPENDATE, CLOSEDATE); a negative/sentinel value (≈ year 1900) is a placeholder, not a real date — surfaced verbatim, parse client-side.";
|
|
77
|
+
// ─── SSRF-guarded fetch (fixed allowlist base + hostname assertion) ──
|
|
78
|
+
async function getArcgisQuery(svc, params) {
|
|
79
|
+
const url = `${svc.base}/query?${params.toString()}`;
|
|
80
|
+
const allowedHost = new URL(svc.base).hostname;
|
|
81
|
+
const built = new URL(url);
|
|
82
|
+
if (built.hostname !== allowedHost || built.protocol !== "https:") {
|
|
83
|
+
throw new ToolErrorCarrier({
|
|
84
|
+
kind: "invalid_input",
|
|
85
|
+
message: `Constructed ArcGIS URL host ${JSON.stringify(built.hostname)} (${built.protocol}) does not match the allowlisted service host ${JSON.stringify(allowedHost)} over https — refusing to fetch (SSRF safety).`,
|
|
86
|
+
retryable: false,
|
|
87
|
+
upstreamEndpoint: `arcgis:${svc.key}`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return getJson(url, { label: `arcgis:${svc.key}`, redirect: "error" });
|
|
91
|
+
}
|
|
92
|
+
// ArcGIS returns HTTP 200 + `{error:{code,message}}` for BOTH a bad query AND a
|
|
93
|
+
// transient server hiccup, and the messages OVERLAP (live-verified 2026-07-19):
|
|
94
|
+
// - "Failed to execute query." ⇒ a bad column/field/where (the caller's query).
|
|
95
|
+
// - "Unable to complete operation." ⇒ AMBIGUOUS — a bad SQL syntax OR a transient
|
|
96
|
+
// server blip (observed intermittently on a valid query).
|
|
97
|
+
// So classify a clearly-input message as invalid_input (non-retryable), but treat
|
|
98
|
+
// the ambiguous/generic one as upstream_unavailable (RETRYABLE) — misclassifying a
|
|
99
|
+
// server blip as invalid_input would falsely blame the caller for an outage.
|
|
100
|
+
const ARCGIS_INPUT_ERROR_RE = /failed to execute query|invalid|parameter|field|syntax|parse|not supported|does not exist|cannot find|out of range/i;
|
|
101
|
+
/** An ArcGIS `{error:{code,message}}` body (HTTP 200) ⇒ throw the right kind. */
|
|
102
|
+
function throwIfArcgisError(svc, body) {
|
|
103
|
+
const e = body?.error;
|
|
104
|
+
if (e && typeof e === "object") {
|
|
105
|
+
const code = num(e.code);
|
|
106
|
+
const msg = String(e.message ?? "ArcGIS query error");
|
|
107
|
+
const inputish = code === 400 && ARCGIS_INPUT_ERROR_RE.test(msg);
|
|
108
|
+
throw new ToolErrorCarrier({
|
|
109
|
+
kind: inputish ? "invalid_input" : "upstream_unavailable",
|
|
110
|
+
message: `ArcGIS ${svc.key} error${code !== null ? ` (${code})` : ""}: ${msg}`.slice(0, 300),
|
|
111
|
+
retryable: !inputish,
|
|
112
|
+
upstreamEndpoint: `arcgis:${svc.key}`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Query rows from a curated ArcGIS REST feature layer. `service` is an allowlist
|
|
118
|
+
* enum; `where` (SQL-ish filter, default 1=1), `outFields` (default *),
|
|
119
|
+
* `orderByFields`, `limit`/`offset`. Returns curated record attributes + honest
|
|
120
|
+
* `_meta` (totalAvailable = the layer's exact match count via a returnCountOnly
|
|
121
|
+
* companion; epoch-ms date disclosure).
|
|
122
|
+
*/
|
|
123
|
+
export async function featureQuery(args) {
|
|
124
|
+
const svc = SERVICE_BY_KEY.get(args.service);
|
|
125
|
+
if (!svc) {
|
|
126
|
+
throw new ToolErrorCarrier({
|
|
127
|
+
kind: "invalid_input",
|
|
128
|
+
message: `Unknown ArcGIS service ${JSON.stringify(args.service)}. Allowed: ${ARCGIS_SERVICES.map((s) => s.key).join(", ")}.`,
|
|
129
|
+
retryable: false,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const limit = args.limit ?? 50;
|
|
133
|
+
const offset = args.offset ?? 0;
|
|
134
|
+
const where = args.where && args.where.trim() ? args.where.trim() : "1=1";
|
|
135
|
+
const outFields = args.outFields && args.outFields.trim() ? args.outFields.trim() : "*";
|
|
136
|
+
const filtersApplied = ["service"];
|
|
137
|
+
if (args.where && args.where.trim())
|
|
138
|
+
filtersApplied.push("where");
|
|
139
|
+
// ── Primary rows query. ──
|
|
140
|
+
const rowParams = new URLSearchParams();
|
|
141
|
+
rowParams.set("where", where);
|
|
142
|
+
rowParams.set("outFields", outFields);
|
|
143
|
+
rowParams.set("returnGeometry", "false");
|
|
144
|
+
rowParams.set("resultOffset", String(offset));
|
|
145
|
+
rowParams.set("resultRecordCount", String(limit));
|
|
146
|
+
if (args.orderByFields && args.orderByFields.trim())
|
|
147
|
+
rowParams.set("orderByFields", args.orderByFields.trim());
|
|
148
|
+
rowParams.set("f", "json");
|
|
149
|
+
let body;
|
|
150
|
+
try {
|
|
151
|
+
body = await getArcgisQuery(svc, rowParams);
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
if (e instanceof ToolErrorCarrier)
|
|
155
|
+
throw e;
|
|
156
|
+
if (e instanceof SyntaxError)
|
|
157
|
+
throw driftError(`arcgis:${svc.key}`, "ArcGIS returned a non-JSON body at HTTP 200 — schema drift.");
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
throwIfArcgisError(svc, body); // P2: a 200 {error} body ⇒ throw (never a fake empty)
|
|
161
|
+
const b = (body ?? {});
|
|
162
|
+
// P4: features MUST be an array (a missing/non-array, with no error, is drift).
|
|
163
|
+
if (!Array.isArray(b.features)) {
|
|
164
|
+
throw driftError(`arcgis:${svc.key}`, "ArcGIS shape drift — response.features must be an array.");
|
|
165
|
+
}
|
|
166
|
+
const records = b.features.map((f) => f?.attributes ?? {});
|
|
167
|
+
const returned = records.length;
|
|
168
|
+
// ── P1: totalAvailable = the layer's exact match count (returnCountOnly
|
|
169
|
+
// companion). BEST-EFFORT: any count failure ⇒ null + note (rows kept). ──
|
|
170
|
+
let totalAvailable = null;
|
|
171
|
+
let countNote = null;
|
|
172
|
+
try {
|
|
173
|
+
const countParams = new URLSearchParams();
|
|
174
|
+
countParams.set("where", where);
|
|
175
|
+
countParams.set("returnCountOnly", "true");
|
|
176
|
+
countParams.set("f", "json");
|
|
177
|
+
const cbody = await getArcgisQuery(svc, countParams);
|
|
178
|
+
throwIfArcgisError(svc, cbody);
|
|
179
|
+
const c = num(cbody?.count);
|
|
180
|
+
if (c !== null)
|
|
181
|
+
totalAvailable = c;
|
|
182
|
+
else
|
|
183
|
+
countNote = "The returnCountOnly companion returned an unexpected shape — totalAvailable is unknown (null); the rows are still complete.";
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
countNote = "The returnCountOnly companion failed (transient) — totalAvailable is unknown (null); the rows are still returned.";
|
|
187
|
+
}
|
|
188
|
+
const exceeded = b.exceededTransferLimit === true;
|
|
189
|
+
const hasMore = totalAvailable !== null ? offset + returned < totalAvailable : (exceeded || returned >= limit);
|
|
190
|
+
const nextOffset = hasMore ? offset + returned : null;
|
|
191
|
+
const notes = [`Source: ${svc.label} (ArcGIS REST feature layer, keyless). ${svc.note}`, DATE_NOTE];
|
|
192
|
+
if (countNote)
|
|
193
|
+
notes.push(countNote);
|
|
194
|
+
return withMeta({ service: svc.key, records }, {
|
|
195
|
+
source: `${new URL(svc.base).hostname} via ArcGIS REST (keyless)`,
|
|
196
|
+
keylessMode: true,
|
|
197
|
+
returned,
|
|
198
|
+
totalAvailable,
|
|
199
|
+
filtersApplied,
|
|
200
|
+
filtersDropped: [],
|
|
201
|
+
fieldsUnavailable: [],
|
|
202
|
+
pagination: { offset, limit, hasMore, nextOffset },
|
|
203
|
+
notes,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=arcgis-feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arcgis-feature.js","sourceRoot":"","sources":["../src/arcgis-feature.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* arcgis-hub.ts — ArcGIS Hub dataset DISCOVERY (`hub.arcgis.com/api/v3/datasets`),
|
|
3
|
+
* a NEW keyless-first SLED-discovery platform (loop cycle 9).
|
|
4
|
+
*
|
|
5
|
+
* WHAT IT ADDS: a large fraction of US state/local/regional/tribal (SLED) open
|
|
6
|
+
* data — especially GIS / infrastructure / permits / boundaries / procurement —
|
|
7
|
+
* is published on ArcGIS Hub, NOT on Socrata or CKAN. This tool DISCOVERS those
|
|
8
|
+
* datasets (keyword search over the whole Hub) so a B2G researcher can find what
|
|
9
|
+
* fragmented local data exists. It is the ArcGIS sibling of
|
|
10
|
+
* `socrata_discover_datasets` / `datagov_search_datasets`.
|
|
11
|
+
*
|
|
12
|
+
* The module writes ZERO fetch/coercion/error/meta code — it REUSES `getJson`
|
|
13
|
+
* (redirect:"error") / `driftError` / `num`·`str` (coerce.ts, null-never-0 /
|
|
14
|
+
* null-never-empty-string) / `withMeta`·`buildMeta`, mirroring datagov-catalog.ts.
|
|
15
|
+
* KEYLESS: no key seam (no token is ever read/sent).
|
|
16
|
+
*
|
|
17
|
+
* ★ SSRF: the host is a compile-time literal (`ARCGIS_HUB_HOST`). Every input
|
|
18
|
+
* (`q` / `filter[openData]` / `page[size]` / `page[start]`) rides in a
|
|
19
|
+
* MODULE-BUILT `URLSearchParams` assembled key-by-key from validated typed args
|
|
20
|
+
* — NO raw-query / raw-host passthrough (this is a FIXED-host catalog search, so
|
|
21
|
+
* there is no per-jurisdiction host vector like socrata_query has). A
|
|
22
|
+
* post-construction hostname/protocol assertion + `redirect:"error"` lock it.
|
|
23
|
+
*
|
|
24
|
+
* ★ PROVENANCE (the crux — different trust posture from our other sources): ArcGIS
|
|
25
|
+
* Hub is a GLOBAL, OPEN publishing platform. Anyone — a US city, a foreign
|
|
26
|
+
* government, an NGO, a company — can publish, so results are NOT all US and NOT
|
|
27
|
+
* all governmental. This tool is therefore explicitly a DISCOVERY aid, NOT a
|
|
28
|
+
* curated official-source allowlist (unlike `socrata_query`, whose hosts are a
|
|
29
|
+
* vetted allowlist). Each result surfaces `owner`/`orgName`/`source`/`region`
|
|
30
|
+
* VERBATIM so the consumer can VET the publisher, and every response carries the
|
|
31
|
+
* global-platform disclosure. `openDataOnly` (default true) biases toward items
|
|
32
|
+
* the publisher designated as open data. DISCOVERY ONLY — to read rows, follow
|
|
33
|
+
* the dataset on its own ArcGIS endpoint (a guarded row-query tool is a planned
|
|
34
|
+
* addition; ArcGIS feature services live on arbitrary hosts, which needs its own
|
|
35
|
+
* SSRF design).
|
|
36
|
+
*
|
|
37
|
+
* ★ HONESTY PILLARS (captured live 2026-07-19):
|
|
38
|
+
* P1 (real total): the v3 response carries `meta.total` (== `meta.stats.totalCount`)
|
|
39
|
+
* — the EXACT match count across the Hub. `totalAvailable = num(meta.total)`
|
|
40
|
+
* (NEVER data.length); a page is `truncated` when `offset + returned < total`.
|
|
41
|
+
* Pagination is a 1-based record offset (`page[start] = offset + 1`).
|
|
42
|
+
* P2: getJson→fetchWithRetry THROWS on 429 (rate_limited) / 5xx
|
|
43
|
+
* (upstream_unavailable) / timeout — NEVER a fake empty. A genuine no-match
|
|
44
|
+
* (`data:[]`, total 0) ⇒ honest empty (datasets:[], returned:0, total:0,
|
|
45
|
+
* complete:true).
|
|
46
|
+
* P3: every scalar via `str` (null-never-empty) / booleans preserved / `num`
|
|
47
|
+
* for counts (null-never-0). A missing owner/source/region is null, never "".
|
|
48
|
+
* P4: `body.data` absent/non-array ⇒ driftError; a 200 non-JSON body ⇒
|
|
49
|
+
* schema_drift via the catch-ladder (ToolErrorCarrier rethrow FIRST so a
|
|
50
|
+
* 429/5xx keeps its taxonomy → SyntaxError→driftError → bare rethrow).
|
|
51
|
+
*/
|
|
52
|
+
import { num } from "./coerce.js";
|
|
53
|
+
import { type MetaBundle } from "./meta.js";
|
|
54
|
+
export { num };
|
|
55
|
+
export declare const ARCGIS_HUB_HOST = "hub.arcgis.com";
|
|
56
|
+
export type HubDataset = {
|
|
57
|
+
id: string | null;
|
|
58
|
+
name: string | null;
|
|
59
|
+
description: string | null;
|
|
60
|
+
owner: string | null;
|
|
61
|
+
orgName: string | null;
|
|
62
|
+
source: string | null;
|
|
63
|
+
region: string | null;
|
|
64
|
+
type: string | null;
|
|
65
|
+
sector: string | null;
|
|
66
|
+
keywords: string[];
|
|
67
|
+
downloadable: boolean | null;
|
|
68
|
+
hasApi: boolean | null;
|
|
69
|
+
created: string | null;
|
|
70
|
+
modified: string | null;
|
|
71
|
+
landingPage: string | null;
|
|
72
|
+
itemId: string | null;
|
|
73
|
+
};
|
|
74
|
+
export type ArcgisHubDiscoverArgs = {
|
|
75
|
+
query: string;
|
|
76
|
+
openDataOnly?: boolean;
|
|
77
|
+
limit?: number;
|
|
78
|
+
offset?: number;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Search ArcGIS Hub datasets by keyword. Filters: `query` (→q, REQUIRED, ≥2
|
|
82
|
+
* non-whitespace chars), `openDataOnly` (default true → filter[openData]=true,
|
|
83
|
+
* biases toward publisher-designated open data), `limit` (→page[size]), `offset`
|
|
84
|
+
* (→page[start]=offset+1, 1-based). The query is MODULE-BUILT from validated typed
|
|
85
|
+
* args (NO raw passthrough). Returns curated dataset rows + honest `_meta`:
|
|
86
|
+
* totalAvailable = the EXACT Hub match count (meta.total, P1), the global-platform
|
|
87
|
+
* provenance disclosure, and per-row publisher fields for vetting.
|
|
88
|
+
*/
|
|
89
|
+
export declare function discoverDatasets(args: ArcgisHubDiscoverArgs): Promise<MetaBundle>;
|
|
90
|
+
//# sourceMappingURL=arcgis-hub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arcgis-hub.d.ts","sourceRoot":"","sources":["../src/arcgis-hub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAIH,OAAO,EAAE,GAAG,EAAO,MAAM,aAAa,CAAC;AACvC,OAAO,EAAY,KAAK,UAAU,EAAqB,MAAM,WAAW,CAAC;AAIzE,OAAO,EAAE,GAAG,EAAE,CAAC;AAGf,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAahD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAkEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,UAAU,CAAC,CA6FrB"}
|