diff --git a/src/VolcanicCore.Api/Endpoints/WebhookEndpoint.cs b/src/VolcanicCore.Api/Endpoints/WebhookEndpoint.cs index 954c83c..6d291f1 100644 --- a/src/VolcanicCore.Api/Endpoints/WebhookEndpoint.cs +++ b/src/VolcanicCore.Api/Endpoints/WebhookEndpoint.cs @@ -51,5 +51,51 @@ public static class WebhookEndpoint if (payload is null) return Results.NoContent(); return Results.Text(payload.Body, contentType: payload.ContentType, statusCode: payload.StatusCode); }); + + // Non-POST requests to the same path — without this, browsers clicking + // the webhook URL (GET) fall through to MapFallbackToFile("index.html") + // and land on the SPA instead of getting a useful hint. + app.MapMethods( + "/wh/{workflowId}/{**path}", + new[] { "GET", "HEAD", "PUT", "PATCH", "DELETE", "OPTIONS" }, + (string workflowId, string? path, HttpRequest req, HttpResponse res) => + { + res.Headers.Allow = "POST"; + var origin = $"{req.Scheme}://{req.Host}"; + var url = $"{origin}/wh/{workflowId}/{path ?? ""}"; + if (HttpMethods.IsHead(req.Method)) + return Results.StatusCode(405); + if (HttpMethods.IsGet(req.Method)) + { + // $$""" so single {/} are literal (CSS + curl JSON) and {{url}} interpolates. + var html = $$""" + +
You reached it with a browser (GET). To trigger the workflow, send a POST with a JSON body:
+curl -X POST -H 'content-type: application/json' \
+ -d '{"hello":"world"}' \
+ {{url}}
+ The workflow must be active for this endpoint to respond; + an inactive workflow returns 404 on POST.
+ + """; + return Results.Content(html, contentType: "text/html; charset=utf-8", statusCode: 405); + } + return Results.Json(new + { + error = "method_not_allowed", + message = "This endpoint accepts POST only.", + endpoint = url, + }, statusCode: 405); + }); } } diff --git a/tests/VolcanicCore.Tests/WebhookEndpointTests.cs b/tests/VolcanicCore.Tests/WebhookEndpointTests.cs index e5d460b..ff29291 100644 --- a/tests/VolcanicCore.Tests/WebhookEndpointTests.cs +++ b/tests/VolcanicCore.Tests/WebhookEndpointTests.cs @@ -19,6 +19,34 @@ public class WebhookEndpointTests : IClassFixture