@brianfunk/areapi 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017-2026 Brian Funk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # areapi
2
+
3
+ [![npm](https://img.shields.io/npm/v/@brianfunk/areapi)](https://www.npmjs.com/package/@brianfunk/areapi)
4
+ [![ci](https://github.com/brianfunk/areapi/actions/workflows/ci.yml/badge.svg)](https://github.com/brianfunk/areapi/actions/workflows/ci.yml)
5
+ [![Netlify Status](https://api.netlify.com/api/v1/badges/c0e102e0-2493-4e3e-b67a-63708ba7756c/deploy-status)](https://app.netlify.com/projects/areapi/deploys)
6
+ [![license](https://img.shields.io/github/license/brianfunk/areapi)](LICENSE)
7
+
8
+ **Which FCC market area is this point in?**
9
+
10
+ Give it a latitude and longitude, get back the Cellular Market Area, Basic Trading Area, Major Trading Area, Economic Area, Major Economic Area, Regional Economic Area Grouping and Partial Economic Area that contain it. These are the geographies the FCC uses to license wireless spectrum.
11
+
12
+ - **Website:** https://areapi.netlify.app
13
+ - **API:** https://areapi.netlify.app/api/find?lat=38.9907&lon=-77.0261
14
+ - **npm:** `npm install @brianfunk/areapi` or `npx @brianfunk/areapi 38.9907 -77.0261`
15
+
16
+ [![areapi map page showing the seven FCC market areas containing a point in Washington, DC](docs/screenshot.jpg)](https://areapi.netlify.app/?lat=38.9907&lon=-77.0261)
17
+
18
+ No database, no server-side state, zero runtime dependencies. The polygons are simplified GeoJSON shipped with the package (about 3 MB for all seven types) and the point-in-polygon test is forty lines of ray casting.
19
+
20
+ ```
21
+ $ npx @brianfunk/areapi 38.9907 -77.0261
22
+ point 38.9907, -77.0261
23
+ status OK
24
+ CMA 8 Washington, DC-MD-VA
25
+ BTA 461 Washington, DC
26
+ MTA 10 Washington-Baltimore
27
+ EA 13 Washington-Baltimore, DC-MD-VA
28
+ MEA 5 Washington
29
+ REAG 2 Southeast
30
+ PEA 5 Baltimore, MD-Washington, DC
31
+ ```
32
+
33
+ ## Area types
34
+
35
+ | type | name | count | vintage | defined by |
36
+ | --- | --- | ---: | --- | --- |
37
+ | `cma` | Cellular Market Area | 734 | 1990 | 306 MSAs (incl. Gulf of Mexico) + 428 RSAs, FCC PN CL-92-40 |
38
+ | `bta` | Basic Trading Area | 493 | 1992 | Rand McNally Commercial Atlas, as modified by the FCC |
39
+ | `mta` | Major Trading Area | 51 | 1992 | Rand McNally Commercial Atlas, as modified by the FCC |
40
+ | `ea` | Economic Area | 176 | 1995 | BEA Economic Areas 1-172 + FCC 173-176 |
41
+ | `mea` | Major Economic Area | 52 | 1995 | 47 CFR 27.6 |
42
+ | `reag` | Regional Economic Area Grouping | 12 | 1995 | 47 CFR 27.6 |
43
+ | `pea` | Partial Economic Area | 416 | 2014 | FCC PN DA 14-759 |
44
+
45
+ All of them are complete, including Puerto Rico, the U.S. Virgin Islands, Guam, the Northern Mariana Islands and American Samoa. The Gulf of Mexico (CMA 306, EA 176, MEA 52, REAG 12) is a water-only market; its polygon is the U.S. part of the Gulf from Marine Regions, which runs from the coastline out to the EEZ limit. (The FCC draws the EA/MEA/REAG Gulf boundary 12 nautical miles offshore rather than at the coast; that strip is attributed to the Gulf here.)
46
+
47
+ ## HTTP API
48
+
49
+ ```
50
+ GET /api/find?lat=<lat>&lon=<lon>[&types=cma,bta,...][&format=json|xml|jsonp][&callback=fn]
51
+ GET /api/<type>/find?latitude=<lat>&longitude=<lon>
52
+ GET /api/types
53
+ ```
54
+
55
+ | parameter | required | values | default |
56
+ | --- | --- | --- | --- |
57
+ | `lat` (or `latitude`) | yes | -90 to 90 | |
58
+ | `lon` (or `longitude`, `lng`) | yes | -180 to 180 | |
59
+ | `types` | no | comma-separated subset of the types above | all |
60
+ | `format` | no | `json`, `xml`, `jsonp` | `json` |
61
+ | `callback` | no | JSONP callback name | `callback` |
62
+
63
+ ```json
64
+ {
65
+ "status": "OK",
66
+ "point": { "lat": 38.9907, "lon": -77.0261 },
67
+ "types": ["cma", "bta"],
68
+ "areas": [
69
+ { "type": "cma", "id": "8", "name": "Washington, DC-MD-VA", "vintage": "1990" },
70
+ { "type": "bta", "id": "461", "name": "Washington, DC", "vintage": "1992" }
71
+ ],
72
+ "executionTime": 1.2
73
+ }
74
+ ```
75
+
76
+ `status` is `OK`, `NONE` (no area contains the point) or `ERROR` (HTTP 400 with an `error` message). Responses are CORS-enabled and cacheable for a day. The 2017 URL shape `/api/<type>/<year>/find` still works; the year is ignored.
77
+
78
+ ## Library
79
+
80
+ ```js
81
+ import { find, feature, types } from '@brianfunk/areapi';
82
+
83
+ const r = await find({ lat: 38.9907, lon: -77.0261 }); // every type
84
+ const r = await find({ lat: 38.9907, lon: -77.0261 }, { types: 'cma' }); // one or more
85
+ const f = await feature('cma', 8); // GeoJSON Feature with geometry and bbox, for drawing
86
+ const m = await types(); // manifest: counts, vintages, sources
87
+ ```
88
+
89
+ Ships TypeScript declarations. Works in Node 20+ and in the browser. In the browser, call `setDataUrl('/path/to/data/')` so it knows where to fetch the `<type>.json` files from; they are loaded lazily, one type at a time, and cached.
90
+
91
+ ## CLI
92
+
93
+ ```
94
+ areapi <lat> <lon> [--types cma,bta,...] [--format table|json|xml]
95
+ areapi --list
96
+ ```
97
+
98
+ Prints a table on a terminal and JSON when piped. Exit code 0 when at least one area matched, 3 when none did, 2 on bad input.
99
+
100
+ ## How the data is built
101
+
102
+ Every FCC market area is an aggregation of county-equivalents, so the polygons are built by dissolving county boundaries with the FCC's own county-to-market crosswalk rather than by redistributing the FCC shapefiles (which the FCC no longer publishes for most types).
103
+
104
+ | input | source |
105
+ | --- | --- |
106
+ | County boundaries | U.S. Census Bureau, Census 2000 generalized counties (`co99_d00`), plus the 2020 1:500k cartographic file for the four territories missing from the 2000 file |
107
+ | County → market crosswalk | FCC OET `FCCCNTY2K.txt` (CMA, BTA, MTA, EA, MEA, REA per county FIPS) |
108
+ | PEA polygons | FCC `FCC_PEAs_Website.zip` shapefile |
109
+ | Gulf of Mexico | Marine Regions (VLIZ) EEZ × IHO sea areas, "United States part of the Gulf of Mexico" (MRGID 25281) |
110
+ | Market names | FCC Universal Licensing System public data (`l_market.zip`, market table) |
111
+
112
+ To rebuild from scratch:
113
+
114
+ ```sh
115
+ mkdir -p data/raw && cd data/raw
116
+ curl -O https://www2.census.gov/geo/tiger/PREVGENZ/co/co00shp/co99_d00_shp.zip
117
+ curl -O https://www2.census.gov/geo/tiger/GENZ2020/shp/cb_2020_us_county_500k.zip
118
+ curl -O https://transition.fcc.gov/bureaus/oet/info/maps/areas/data/2000/FCCCNTY2K.txt
119
+ curl -O https://transition.fcc.gov/bureaus/oet/info/maps/areas/data/FCC_PEAs_Website.zip
120
+ curl -O https://data.fcc.gov/download/pub/uls/complete/l_market.zip
121
+ curl -o eez_iho_gulf.json "https://geo.vliz.be/geoserver/MarineRegions/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=MarineRegions:eez_iho&outputFormat=json&CQL_FILTER=marregion%20ILIKE%20%27%25Gulf%20of%20Mexico%25%27"
122
+ unzip -p l_market.zip MK.dat | awk -F'|' '{print $6 "|" $9}' | sort -u > uls-markets.txt
123
+ cd ../..
124
+ node scripts/extract-names.js # -> scripts/names.json
125
+ npm run build:data # -> data/*.json, data/manifest.json
126
+ ```
127
+
128
+ Geometry is simplified (`SIMPLIFY=5%` by default, visvalingam weighted, shapes preserved) and rounded to 4 decimal places, which is about 11 m. That is plenty for deciding which market a point is in, and is what keeps the whole dataset at 3 MB. `data/manifest.json` records the sources, counts, and the ids that have no polygon.
129
+
130
+ ## Development
131
+
132
+ ```sh
133
+ npm install
134
+ npm test # node:test, no framework
135
+ npm run build:site # bundle src/ for the browser + copy data into site/
136
+ npm run dev # netlify dev: site + API function at http://localhost:8888
137
+ ```
138
+
139
+ Deployed on Netlify from the `dev` branch. The site is static files; the API is one Netlify Function wrapping the same library.
140
+
141
+ ## License
142
+
143
+ MIT