Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/bazaar/challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ import type { CheckResult, ChallengeFetchResult } from "./types.js";
export interface ChallengeFetchOptions {
/**
* When true, also validate that the 402 body contains
* `extensions.bazaar` with the minimum fields `name` and
* `description`. Default `true` — bazaar-check is, by name, about
* bazaar.
* `extensions.bazaar` in either supported discovery variant.
* Default `true` — bazaar-check is, by name, about bazaar.
*/
readonly expectBazaar?: boolean;
}
Expand Down
12 changes: 7 additions & 5 deletions src/bazaar/well-known.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,16 @@ export async function checkWellKnown(
}

if (issues.length > 0) {
const bazaarFix =
bazaarVariant === "body-discovery"
? "Services opted into bazaar body-discovery need extensions.bazaar.info.input, extensions.bazaar.info.output, and extensions.bazaar.schema as non-null objects."
: `Services opted into bazaar discovery (extensions.bazaar present, or discovery_extension: "bazaar") additionally need extensions.bazaar.{name, description} as non-empty strings — empty strings render as blank listing cards on the mapper.`;
return {
result: {
check: "well-known",
status: "fail",
message: `manifest at ${url} has ${issues.length} issue(s): ${issues.join(", ")}`,
fix: `fix each: every Bazaar-listable service needs a top-level name (string), description (string), and accepts (array of payment requirement objects). Services opted into bazaar discovery (extensions.bazaar present, or discovery_extension: "bazaar") additionally need extensions.bazaar.{name, description} as non-empty strings — empty strings render as blank listing cards on the mapper.`,
fix: `fix each: every Bazaar-listable service needs a top-level name (string), description (string), and accepts (array of payment requirement objects). ${bazaarFix}`,
detail: { issues },
},
manifest,
Expand Down Expand Up @@ -183,9 +187,7 @@ export async function checkWellKnown(
* object. Returns `undefined` when absent, null, or a non-object — those
* cases are handled by the caller's opt-in branch.
*/
function readBazaarExtension(
manifest: WellKnownManifest,
): { name?: unknown; description?: unknown } | undefined {
function readBazaarExtension(manifest: WellKnownManifest): Record<string, unknown> | undefined {
const ext = manifest.extensions;
if (typeof ext !== "object" || ext === null) {
return undefined;
Expand All @@ -194,5 +196,5 @@ function readBazaarExtension(
if (typeof bazaar !== "object" || bazaar === null) {
return undefined;
}
return bazaar as { name?: unknown; description?: unknown };
return bazaar as Record<string, unknown>;
}
2 changes: 2 additions & 0 deletions tests/unit/bazaar-well-known.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ describe("checkWellKnown", () => {
expect(result.detail?.issues).toEqual(
expect.arrayContaining([expect.stringMatching(/extensions\.bazaar\.info\.input/)]),
);
expect(result.fix).toContain("extensions.bazaar.info.input");
expect(result.fix).not.toContain("extensions.bazaar.{name, description}");
});

it("fails when body-discovery is missing schema (whole schema key non-object)", async () => {
Expand Down