Two complementary capabilities. Feed subscriptions poll OGC SensorThings, SOS, GTFS-realtime, and Moving Features sources into a dedicated DuckDB for SQL analytics on the map. The Esri-conformant StreamServer exposes that same moving data — plus Meshtastic, TAK, and GNSS tracks — to ArcGIS Pro and the JS SDK as a native WebSocket StreamLayer.
Each feed type has its own adapter and writes rows into a dedicated feeds.duckdb registered under dbId = "feeds" — so feed tables flow through the existing OGC API Features / MVT / FeatureServer facades with no facade changes.
GetObservation, O&M 2.0.read_csv_auto with ST_MakeLine shapes; protobuf FeedMessage for live vehicle positions.LINESTRING trajectory view.PeriodicTimer, retention trimming, and DPAPI-encrypted feeds.json profiles.// subscribe to a SensorThings endpoint { "kind": "SensorThings", "url": "https://example/frost/v1.0", "intervalSeconds": 30, "retentionHours": 168 } // rows land in feeds.sensorthings_observations // → served at /api/spatial/feeds/collections/… ● polling · Polly-instrumented
Raw ASP.NET Core WebSockets — not SignalR — that speak the ArcGIS SDK's own JSON protocol. Paste the catalog URL into ArcGIS Pro or a JS SDK StreamLayer and it just connects.
Speaks the Esri JSON wire contract directly — camelCase via [JsonPropertyName], polymorphic messageType frames.
Subscribers push {messageType:"filter"} to update their where + geometry slice of the stream.
Parameterized-safe writes on a background thread so the hot path never blocks; historical query via /query.
Accepts either Esri {attributes,geometry} or GeoJSON FeatureCollection on /ingest.
RFC 6455 ping frames keep subscribers alive through proxies and idle networks.
Persisted to stream_layers.json with auto field discovery from the DuckDB table.
| Feature | Endpoint | Notes |
|---|---|---|
| Feeds | GET / POST /api/feeds | List / create a subscription |
| Feeds | POST /api/feeds/{id}/pause · /resume · /poll | Lifecycle control |
| Feeds | GET /api/spatial/feeds/collections/{c}/items | OGC API Features over feed tables |
| Stream | GET /api/stream/{layerId}/StreamServer | Catalog JSON with the ArcGIS StreamLayer URL |
| Stream | GET /api/stream/{layerId}/subscribe | The WebSocket the SDK opens |
| Stream | POST /api/stream/{layerId}/ingest | External push (Esri or GeoJSON) |
| Stream | GET /api/stream/{layerId}/query?startMs=&endMs= | Historical playback |
Sources: FeedRoutes.cs / FeedPollerService.cs (commit 5401b500f) and StreamServerRoutes.cs / StreamServerBroker.cs (commit 2570a8db5). GTFS-realtime uses the canonical Google proto (Protos/gtfs-realtime.proto).
From IoT sensors and transit feeds to Meshtastic and TAK tracks — subscribe, store, and stream into the Esri clients you already run.