feat: store and display resources by HTTP method#947
Merged
Conversation
Same URL with different HTTP methods (e.g. GET /agent/credits vs POST /agent/credits) are now distinct resources throughout the system. DB: add `method` column to Resources with @@unique([resource, method]). Registration: thread method through registerResource, registerSiwxResource, and deprecateStaleResources. UI: pass DiscoveredResource[] (with method) through the discovery hook and show method badges when duplicate URLs appear.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The x402 probe always returns POST (payment protocol), but the OpenAPI spec has the correct method (GET vs POST). Prefer discovery method when registering, and use the DB method column on the resource listing page instead of inferring from the schema.
NOT: [{cond1}, {cond2}] (array) is the standard Prisma way to express
"NOT cond1 AND NOT cond2", equivalent to "NOT (cond1 OR cond2)". The
previous NOT: { OR: [...] } nested syntax may not generate correct SQL.
The x402 probe always returns POST (payment protocol), which is not the endpoint's actual HTTP method. Only use the discovery method or default to GET.
The active resources list for deprecation was built from the full discovery input (68 endpoints for iris), including 65 unprotected endpoints that were skipped during registration. This prevented old stale rows (like GET /campaigns defaulted from migration) from being deprecated, since they appeared in the "don't deprecate" list. Now only resources that were actually registered (paid + siwx) are included in the active list.
The deprecation active list was filtering discovery resources by URL, but the same URL can appear with different methods (e.g. GET /campaigns is unprotected, POST /campaigns is paid). Matching by URL alone included the unprotected GET version in the active list, preventing deprecation of stale GET rows from the migration. Now successfulResults and siwxResults carry the method that was actually registered, so the active list is built directly from results without re-deriving from discovery input.
Existing resources should not change display behavior. Empty string means "legacy — infer method from schema" (preserves current behavior). Non-empty values (GET, POST, etc.) are set by new discovery-based registrations going forward. No backfill needed. Also removes debug logging from previous commit.
Replace complex Prisma NOT:[{cond1},{cond2},...] pattern with a simple
indexed query + application-side comparison. Fetch all active resources
for the origin, compare keys in code, update stale ones by ID.
…arMethod - resourceKey: composite keys, empty string handling, distinct keys for different methods on same URL - upsertResourceSchema: method defaults to empty string, preserves explicit method - getBazaarMethod: method inference from schema (explicit, body→POST, queryParams→GET, null→GET fallback)
fmhall
approved these changes
Jun 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Same URL with different HTTP methods (e.g.
GET /agent/creditsvsPOST /agent/credits) are now stored and displayed as distinct resources, matching how mppscan handles this.DB
methodcolumn toResourceswith@@unique([resource, method])""(empty string) — no display change for existing resources, no backfill needed"GET","POST")upsertResource,registerResource,registerSiwxResourceall use compound key(resource, method)Registration
preferredMethodparam, the probe-determined method was being stored directly. Now we explicitly pass the discovery method throughoptions.methodand use that for DB storage.""— preserves legacy behaviorDeprecation
deprecateStaleResourcesrefactored: simple indexed query + application-side comparison instead of complex PrismaNOT:[array]patternmethod::urlkeys in code, updates stale IDsGET /campaignsunprotected +POST /campaignspaid) from shielding stale rowsmethod=""rows are deprecated when an origin is re-registered with method-specific rowsUI
use-discovery.tsreturnsDiscoveredResource[](with method) instead ofstring[]POST /campaigns,GET /agent/credits) when duplicate URLs existRegisterModeResourceListshows a Method column when neededmethod=""rowsMETHOD::urlkeys viaresourceKey()utilityOther
checkRegisteredtRPC route accepts{url, method}[]for compound-key matchingFailedResourcetype includes optionalmethodTest plan
api.iris-ai.devon register page — shows 3 distinct resources with method badgesmethod=""rowspnpm format && pnpm lintpassresourceKey,upsertResourceSchemamethod handling, andgetBazaarMethodinference