|
1 | 1 | --- |
2 | 2 | name: shiny-httpserver |
3 | | -description: Generate code using Shiny.Net.HttpServer — a dependency-light, AOT/trim-clean HTTP/1.1, HTTP/2 & HTTP/3 server that runs anywhere .NET runs, including .NET MAUI and native tvOS, where ASP.NET Core cannot. Covers routing, middleware, source-generated typed endpoints, results and JSON, content negotiation with XML/MessagePack/protobuf formatters in both directions, static files and Blazor WASM, uploads/downloads, WebSockets, SSE, SignalR-style switchboards (real-time two-way calls over SSE with groups, an operator, client results, resumable lines, and a generated typed .NET client), sessions, OpenAPI, authentication (Basic/API key/cookie/JWT), authorization, CORS, rate limiting, IP filtering, TLS and self-signed certificates, tunnelling (relay, SSH, quick tunnels, Azure Relay, and supervised cloudflared/ngrok/tailscale agents), serving a directory over WebDAV, serving gRPC and gRPC-Web, hosting an MCP server with RFC 9728 OAuth discovery, receiving the OAuth/OIDC loopback redirect so a desktop app or CLI can sign in through the system browser (RFC 8252), health checks, OpenTelemetry-shaped metrics and tracing, W3C access logs, request timeouts, output caching and conditional requests, request decompression, antiforgery and browser security headers, a reverse proxy with destination clusters, load balancing, health checks, session affinity, transforms, WebSocket forwarding and IConfiguration-driven routes, mDNS/Bonjour advertising and discovery, MAUI lifecycle (background/foreground, Android foreground service, network rebinding), host filtering against DNS rebinding, request localization, webhook signature verification (GitHub/Stripe/Slack/Standard Webhooks), idempotency keys, RFC 9530 content digests, 103 Early Hints, the PROXY protocol, RFC 6902 JSON Patch, API versioning with per-version OpenAPI, a Scalar API reference page, tus resumable uploads, CalDAV/CardDAV, automatic HTTPS via ACME (Let's Encrypt/ZeroSSL), and an in-memory test harness. |
| 3 | +description: Generate code using Shiny.Net.HttpServer — a dependency-light, AOT/trim-clean HTTP/1.1, HTTP/2 & HTTP/3 server that runs anywhere .NET runs, including .NET MAUI and native tvOS, where ASP.NET Core cannot. Covers routing, middleware, source-generated typed endpoints, results and JSON, content negotiation with XML/MessagePack/protobuf formatters in both directions, static files and Blazor WASM, uploads/downloads, WebSockets, SSE, SignalR-style switchboards (real-time two-way calls over SSE with groups, an operator, client results, resumable lines, and a generated typed .NET client), sessions, OpenAPI, authentication (Basic/API key/cookie/JWT), authorization, CORS, rate limiting, IP filtering, TLS and self-signed certificates, tunnelling (relay, SSH, quick tunnels, Azure Relay, and supervised cloudflared/ngrok/tailscale agents), serving a directory over WebDAV, serving gRPC and gRPC-Web, hosting an MCP server with RFC 9728 OAuth discovery, receiving the OAuth/OIDC loopback redirect so a desktop app or CLI can sign in through the system browser (RFC 8252), health checks, OpenTelemetry-shaped metrics and tracing, W3C access logs, request timeouts, output caching and conditional requests, request decompression, antiforgery and browser security headers, a reverse proxy with destination clusters, load balancing, health checks, session affinity, transforms, WebSocket forwarding and IConfiguration-driven routes, mDNS/Bonjour advertising and discovery, MAUI lifecycle (background/foreground, Android foreground service, network rebinding), host filtering against DNS rebinding, request localization, webhook signature verification (GitHub/Stripe/Slack/Standard Webhooks), idempotency keys, RFC 9530 content digests, 103 Early Hints, the PROXY protocol, RFC 6902 JSON Patch, API versioning with per-version OpenAPI, a Scalar API reference page, tus resumable uploads, CalDAV/CardDAV, a private NuGet feed (V3 protocol with push), automatic HTTPS via ACME (Let's Encrypt/ZeroSSL), and an in-memory test harness. |
4 | 4 | auto_invoke: true |
5 | 5 | triggers: |
6 | 6 | - Shiny.Net.HttpServer |
@@ -374,6 +374,23 @@ triggers: |
374 | 374 | - tus-js-client |
375 | 375 | - Uppy |
376 | 376 | - TusDotNetClient |
| 377 | +- Shiny.Net.HttpServer.NuGet |
| 378 | +- MapNuGetFeed |
| 379 | +- NuGetFeedOptions |
| 380 | +- NuGetFeedMountBuilder |
| 381 | +- INuGetPackageStore |
| 382 | +- DiskNuGetPackageStore |
| 383 | +- NuGetPackage |
| 384 | +- NuGetDeleteBehavior |
| 385 | +- NuGetPushContext |
| 386 | +- NuGetApiKeyContext |
| 387 | +- nuget feed |
| 388 | +- nuget server |
| 389 | +- private nuget feed |
| 390 | +- package feed |
| 391 | +- host nuget packages |
| 392 | +- dotnet nuget push |
| 393 | +- X-NuGet-ApiKey |
377 | 394 | - Idempotency-Key |
378 | 395 | - AddIdempotency |
379 | 396 | - UseIdempotency |
@@ -488,6 +505,7 @@ Invoke this skill when the user wants to: |
488 | 505 | - Cache responses, honour conditional requests, bound how long a handler may take, or forward a |
489 | 506 | route to another server |
490 | 507 | - Test endpoints without binding a port |
| 508 | +- Host a private NuGet feed that `dotnet nuget push` and `dotnet restore` talk to |
491 | 509 | - Sign a desktop app or CLI in through the system browser (the OAuth/OIDC loopback redirect, |
492 | 510 | what VS Code and `gh auth login` do) without `HttpListener` |
493 | 511 |
|
@@ -525,6 +543,7 @@ dotnet add package Shiny.Net.HttpServer.Testing # in-memory HttpClient |
525 | 543 | dotnet add package Shiny.Net.HttpServer.Tunnels # cloudflared / ngrok / tailscale agents (desktop + CLI only) |
526 | 544 | dotnet add package Shiny.Net.HttpServer.OAuthLoopback # OAuth/OIDC loopback redirect receiver (desktop + CLI only) |
527 | 545 | dotnet add package Shiny.Net.HttpServer.Tus # tus 1.0.0 resumable uploads |
| 546 | +dotnet add package Shiny.Net.HttpServer.NuGet # a private NuGet V3 feed (push, restore, search) |
528 | 547 | dotnet add package Shiny.Net.HttpServer.CalDav # calendars & contacts over CalDAV/CardDAV |
529 | 548 | dotnet add package Shiny.Net.HttpServer.Acme # automatic HTTPS via Let's Encrypt/ZeroSSL (public hosts, not phones) |
530 | 549 |
|
@@ -1367,6 +1386,47 @@ app.UseCors(p => p.WithOrigins("https://app.example.com").WithTusHeaders()); // |
1367 | 1386 | - `RemoveExpiredUploadsAsync()` on the returned builder runs cleanup from a platform background job. |
1368 | 1387 | - The routes are excluded from OpenAPI. Do not describe them. |
1369 | 1388 |
|
| 1389 | +### A private NuGet feed |
| 1390 | + |
| 1391 | +`MapNuGetFeed` serves the NuGet V3 server API, so `dotnet restore`, `dotnet nuget push`, |
| 1392 | +`dotnet package search`, Visual Studio and Rider work against it as a plain package source. Reach for it |
| 1393 | +when the user says *NuGet server*, *private feed*, *package feed*, or *host our packages*. Tier 1: |
| 1394 | +nine raw routes mapped in one call (package `Shiny.Net.HttpServer.NuGet`; versions via the official |
| 1395 | +`NuGet.Versioning`). |
| 1396 | + |
| 1397 | +```csharp |
| 1398 | +app.MapNuGetFeed("/nuget", o => |
| 1399 | +{ |
| 1400 | + o.Store = new DiskNuGetPackageStore(Path.Combine(dataDir, "packages")); // required |
| 1401 | + o.ApiKeys.Add(config["NuGet:ApiKey"]!); // X-NuGet-ApiKey, compared in constant time |
| 1402 | + o.DeleteBehavior = NuGetDeleteBehavior.Unlist; // default; .Delete removes files |
| 1403 | + o.OnBeforePushAsync = ctx => |
| 1404 | + { |
| 1405 | + if (!ctx.Package.Id.StartsWith("Contoso.")) ctx.Reject(403, "Only Contoso.* packages."); |
| 1406 | + return ValueTask.CompletedTask; |
| 1407 | + }; |
| 1408 | +}) |
| 1409 | +.ForReads(r => r.RequireAuthorization()); // optional: a private feed (Basic creds in nuget.config) |
| 1410 | +
|
| 1411 | +// client: dotnet nuget add source http://host:5000/nuget/v3/index.json -n team --allow-insecure-connections |
| 1412 | +// dotnet nuget push My.Pkg.1.0.0.nupkg -s team -k <key> |
| 1413 | +``` |
| 1414 | + |
| 1415 | +- The package source URL is always `{prefix}/v3/index.json`. Give users that URL, not the prefix. |
| 1416 | +- A writable feed with no `ApiKeys` and no `ValidateApiKeyAsync` throws when mapped. Use |
| 1417 | + `ReadOnly = true` for a feed nobody pushes to, or `RequireApiKey = false` only when `ForWrites(...)` |
| 1418 | + adds authorization. |
| 1419 | +- NuGet refuses plain-HTTP sources unless `allowInsecureConnections="true"` is set on the source. On a |
| 1420 | + public host, serve it with TLS or ACME. |
| 1421 | +- Push size: `MaxPackageSize` (250 MB) **and** `Limits.MaxRequestBodySize` (30 MB) both apply. Raise |
| 1422 | + the server limit for big packages. |
| 1423 | +- Behind a proxy that rewrites the host, set `PublicBaseUrl`. Every link in the protocol is absolute. |
| 1424 | +- `DiskNuGetPackageStore` uses NuGet's own folder-feed layout (`{id}/{version}/{id}.{version}.nupkg`), |
| 1425 | + so the directory is also a local source and can be seeded by copying files in (call `Reload()`). |
| 1426 | +- Not supported: `.snupkg` symbol packages, the catalog, download counts, the V2/OData API. Do not |
| 1427 | + promise them. |
| 1428 | +- The routes are excluded from OpenAPI. Do not describe them. |
| 1429 | + |
1370 | 1430 | ## Realtime |
1371 | 1431 |
|
1372 | 1432 | ```csharp |
|
0 commit comments