[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83438":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":12,"contributorsCount":12,"subscribersCount":12,"size":12,"stars1d":12,"stars7d":12,"stars30d":12,"stars90d":12,"forks30d":12,"starsTrendScore":12,"compositeScore":14,"rankGlobal":9,"rankLanguage":9,"license":15,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":18,"hasPages":16,"topics":19,"createdAt":9,"pushedAt":9,"updatedAt":20,"readmeContent":21,"aiSummary":9,"trendingCount":12,"starSnapshotCount":12,"syncStatus":22,"lastSyncTime":23,"discoverSource":24},83438,"spc-cpp","Reddimus\u002Fspc-cpp","Reddimus","Open-source C++23 SDK for NOAA SPC severe-weather outlooks (convective, fire weather, watches, mesoscale discussions, storm reports) — static GeoJSON + ArcGIS MapServer + IEM archive.",null,"C++",117,0,121,40,"MIT License",false,"main",true,[],"2026-06-12 04:01:41","# spc-cpp\n\n[![CI](https:\u002F\u002Fgithub.com\u002FReddimus\u002Fspc-cpp\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002FReddimus\u002Fspc-cpp\u002Factions\u002Fworkflows\u002Fci.yml)\n[![Release](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002FReddimus\u002Fspc-cpp)](https:\u002F\u002Fgithub.com\u002FReddimus\u002Fspc-cpp\u002Freleases)\n[![C++23](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FC%2B%2B-23-blue.svg)](https:\u002F\u002Fen.cppreference.com\u002Fw\u002Fcpp\u002F23)\n[![License: MIT](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-MIT-yellow.svg)](https:\u002F\u002Fopensource.org\u002Flicenses\u002FMIT)\n\nC++23 SDK for [NOAA Storm Prediction Center](https:\u002F\u002Fwww.spc.noaa.gov\u002F)\n(SPC) severe-weather products: convective outlooks (Day 1-3 categorical &\nprobabilistic, Day 4-8, conditional intensity), fire-weather outlooks,\nactive watches, mesoscale discussions, and storm reports.\n\nTyped, `std::expected`-based access over three sources: the **ArcGIS\nMapServer** (`mapservices.weather.noaa.gov`, primary — contract-stable),\nthe static **`www.spc.noaa.gov` GeoJSON feeds** (fallback), and the\n**IEM archive** (`mesonet.agron.iastate.edu`, historical backfill). No\nAPI key required.\n\n## Quick Start\n\n```cpp\n#include \"spc\u002Fspc.hpp\"\n#include \u003Ciostream>\n\nint main() {\n    spc::HttpClient http; \u002F\u002F absolute-URL pass-through; serves SPC\u002FArcGIS\u002FIEM\n\n    spc::Result\u003Cspc::HttpResponse> r = http.get(\n        \"https:\u002F\u002Fwww.spc.noaa.gov\u002Fproducts\u002Foutlook\u002Fday1otlk_cat.nolyr.geojson\");\n    if (!r) {\n        std::cerr \u003C\u003C r.error().message \u003C\u003C \"\\n\";\n        return 1;\n    }\n    if (r->status_code == 404) {\n        \u002F\u002F SPC's normal \"no active outlook\" state — clear, don't error.\n        return 0;\n    }\n\n    const spc::CategoricalOutlookPayload p =\n        spc::parse_categorical(r->body, \u002F*day_offset=*\u002F1);\n    for (const spc::OutlookFeature& f : p.features) {\n        std::cout \u003C\u003C f.label \u003C\u003C \" (severity \" \u003C\u003C static_cast\u003Cint>(f.severity)\n                  \u003C\u003C \") rings=\" \u003C\u003C f.rings.size() \u003C\u003C \"\\n\";\n    }\n}\n```\n\n## Features\n\n- **C++23** with `Result\u003CT> = std::expected\u003CT, Error>` for all fallible\n  APIs (no exceptions across the public surface).\n- **Convective outlooks**: Day 1-3 categorical + probabilistic\n  (tornado\u002Fhail\u002Fwind), Day 4-8, conditional intensity.\n- **Fire weather, watches, mesoscale discussions, storm reports**\n  (the mesoscale-discussion narrative is exposed raw — not parsed).\n- **Three sources, one client**: `ArcGISClient` (+ `ArcGISPager` for\n  the 2000-record transfer limit), `StaticFeedClient`, `ArchiveClient`\n  (IEM, conservative rate\u002Fretry).\n- Ray-cast **point-in-polygon** + Polygon\u002FMultiPolygon geometry.\n- Battle-tested NOAA-GeoJSON parsing: case-variant keys\n  (`LABEL`\u002F`label`\u002F`dn`), numeric-as-string labels, polymorphic\n  geometry — lifted verbatim from a production ingestion service.\n\n## Install\n\n### CMake `find_package`\n\n```bash\ncmake -B build -DCMAKE_BUILD_TYPE=Release\ncmake --build build\ncmake --install build --prefix \u002Fyour\u002Fprefix\n```\n\n```cmake\nfind_package(spc 0.1.0 REQUIRED)\ntarget_link_libraries(myapp PRIVATE spc::spc)\n```\n\n### FetchContent\n\n```cmake\nFetchContent_Declare(spc_cpp\n    GIT_REPOSITORY https:\u002F\u002Fgithub.com\u002FReddimus\u002Fspc-cpp.git\n    GIT_TAG v0.1.0  # pin a tagged release\n)\nFetchContent_MakeAvailable(spc_cpp)\ntarget_link_libraries(myapp PRIVATE spc::spc)\n```\n\n## Architecture\n\n```mermaid\ngraph LR\n    spc_core[\"spc_core\u003Cbr\u002F>\u003Csmall>error, geometry, rate_limit, retry, pagination\u003C\u002Fsmall>\"]\n    spc_http[\"spc_http\u003Cbr\u002F>\u003Csmall>libcurl GET client (abs-URL pass-through)\u003C\u002Fsmall>\"]\n    spc_models[\"spc_models\u003Cbr\u002F>\u003Csmall>glz::generic parsers\u003Cbr\u002F>+ GeoJSON\u002FEsri shapes\u003C\u002Fsmall>\"]\n    spc_api[\"spc_api\u003Cbr\u002F>\u003Csmall>StaticFeed \u002F ArcGIS \u002F Archive clients\u003C\u002Fsmall>\"]\n    spc[\"spc\u003Cbr\u002F>\u003Csmall>INTERFACE\u003C\u002Fsmall>\"]\n    spc_core --> spc_http --> spc_models --> spc_api --> spc\n```\n\nLayered static libraries with `install(EXPORT)` and a `spc::` namespace.\n\n## JSON library: Glaze (divergence note)\n\n**spc-cpp parses JSON with [Glaze](https:\u002F\u002Fgithub.com\u002Fstephenberry\u002Fglaze)\nv7.6.0, not `nlohmann\u002Fjson`.** This is a deliberate divergence from the\nsibling Reddimus SDKs `nws-cpp` and `ncei-cpp`, which use\n`nlohmann\u002Fjson`.\n\nWhy: SPC's GeoJSON `properties` block is shape-loose — the same logical\nfield appears as `LABEL`, `label`, or `dn` depending on the product; a\nprobabilistic label is sometimes the string `\"5\"` and sometimes the\nnumber `5`; timestamps are a compact `YYYYMMDDHHMM`; and geometry is\npolymorphic (`Polygon` vs `MultiPolygon`). A compile-time\n`glz::meta` schema would either reject these or force tagged-variant\ngymnastics. Instead the parser walks a `glz::generic` AST with\nnull-safe extractors (missing\u002Fnull\u002Ftype-mismatch → default-constructed\nvalue). This is the exact, audit-clean code path proven in the internal\n`spc-data` ingestion service; it is lifted **verbatim** so a downstream\nconsumer that swaps its in-tree copy for this SDK gets byte-identical\nparse output. Net-new product models reuse the same `glz::generic`\nhelpers but **do not** reuse the convective `severity_from_label`\n(different label sets — they carry product-specific severity mappers).\n\nIf you vendor multiple Reddimus SDKs via FetchContent, note that\nspc-cpp pins the **same** glaze `v7.6.0` tag the rest of the estate\nuses, so a combined build dedupes to a single `glaze::glaze` target.\n\n## Build & Test\n\n```bash\nmake build      # Release\nmake test       # ctest\nmake lint       # clang-format --dry-run + cpp_auto_audit\nmake coverage   # lcov report\n```\n\n## Dependencies\n\n| Dependency | Purpose | Source |\n| ---------- | ------- | ------ |\n| [Glaze](https:\u002F\u002Fgithub.com\u002Fstephenberry\u002Fglaze) v7.6.0 | JSON (generic-AST parse of shape-loose SPC GeoJSON) | `FetchContent` |\n| libcurl | HTTP GET | system (`find_package(CURL)`) |\n| GoogleTest v1.15.2 | Unit testing | `FetchContent` |\n\n## References\n\n- [SPC Products](https:\u002F\u002Fwww.spc.noaa.gov\u002Fproducts\u002F)\n- [NWS ArcGIS MapServer — SPC outlooks](https:\u002F\u002Fmapservices.weather.noaa.gov\u002Fvector\u002Frest\u002Fservices\u002Foutlooks\u002FSPC_wx_outlks\u002FMapServer)\n- [IEM SPC archive](https:\u002F\u002Fmesonet.agron.iastate.edu\u002F)\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",2,"2026-06-11 04:11:09","CREATED_QUERY"]