From 6f78f4f186ab7ba436dd724b51943e25ff11e6fd Mon Sep 17 00:00:00 2001 From: kutluhaneth46 Date: Fri, 18 Sep 2026 23:31:25 +0000 Subject: [PATCH] fix(ack-pay): reject empty payment option network When network is present, require a non-empty string in both valibot and zod schemas. Omitting the field stays valid. Fixes #219. AI usage: Cursor assisted locating the gap, writing the schema change, parity tests, and changeset. I reviewed and understand the change. --- .changeset/reject-empty-network.md | 5 +++ .../src/schemas/payment-option.test.ts | 37 +++++++++++++++++++ packages/ack-pay/src/schemas/valibot.ts | 3 +- packages/ack-pay/src/schemas/zod.ts | 2 +- 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/reject-empty-network.md diff --git a/.changeset/reject-empty-network.md b/.changeset/reject-empty-network.md new file mode 100644 index 00000000..a07ca039 --- /dev/null +++ b/.changeset/reject-empty-network.md @@ -0,0 +1,5 @@ +--- +"@agentcommercekit/ack-pay": patch +--- + +Reject an empty `network` on payment options when the field is present. diff --git a/packages/ack-pay/src/schemas/payment-option.test.ts b/packages/ack-pay/src/schemas/payment-option.test.ts index 166b4496..c76cef27 100644 --- a/packages/ack-pay/src/schemas/payment-option.test.ts +++ b/packages/ack-pay/src/schemas/payment-option.test.ts @@ -35,3 +35,40 @@ describe("paymentOptionSchema amount", () => { }, ) }) + +describe.each([ + [ + "valibot", + (input: unknown) => v.safeParse(valibotPaymentOptionSchema, input).success, + ], + ["zod", (input: unknown) => zodPaymentOptionSchema.safeParse(input).success], +] as const)("%s paymentOptionSchema network", (_, accepts) => { + it("accepts a payment option with network omitted", () => { + expect( + accepts({ + ...paymentOption, + amount: 1, + }), + ).toBe(true) + }) + + it("accepts a payment option with a non-empty network", () => { + expect( + accepts({ + ...paymentOption, + amount: 1, + network: "eip155:8453", + }), + ).toBe(true) + }) + + it("rejects a payment option with an empty network", () => { + expect( + accepts({ + ...paymentOption, + amount: 1, + network: "", + }), + ).toBe(false) + }) +}) diff --git a/packages/ack-pay/src/schemas/valibot.ts b/packages/ack-pay/src/schemas/valibot.ts index 75fc9807..e7f96f41 100644 --- a/packages/ack-pay/src/schemas/valibot.ts +++ b/packages/ack-pay/src/schemas/valibot.ts @@ -4,6 +4,7 @@ import * as v from "valibot" const urlOrDidUri = v.union([v.pipe(v.string(), v.url()), didUriSchema]) const positiveIntegerString = v.pipe(v.string(), v.regex(/^[1-9]\d*$/)) +const nonEmptyString = v.pipe(v.string(), v.minLength(1)) const timestampSchema = v.pipe( v.union([v.date(), v.string()]), @@ -20,7 +21,7 @@ export const paymentOptionSchema = v.object({ decimals: v.pipe(v.number(), v.integer(), v.toMinValue(0)), currency: v.string(), recipient: v.string(), - network: v.optional(v.string()), + network: v.optional(nonEmptyString), paymentService: v.optional(urlOrDidUri), receiptService: v.optional(urlOrDidUri), }) diff --git a/packages/ack-pay/src/schemas/zod.ts b/packages/ack-pay/src/schemas/zod.ts index 05cfdca8..1a5e4fa6 100644 --- a/packages/ack-pay/src/schemas/zod.ts +++ b/packages/ack-pay/src/schemas/zod.ts @@ -27,7 +27,7 @@ export const paymentOptionSchema = z.object({ decimals: z.number().int().nonnegative(), currency: z.string(), recipient: z.string(), - network: z.string().optional(), + network: z.string().min(1).optional(), paymentService: urlOrDidUri.optional(), receiptService: urlOrDidUri.optional(), })