feat(sdk): add TypeScript SDK for AP2 mandates and receipts#305
feat(sdk): add TypeScript SDK for AP2 mandates and receipts#305wakqasahmed wants to merge 2 commits into
Conversation
Adds code/sdk/typescript, a publishable @ap2-protocol/sdk package with Zod schemas and TypeScript types for AP2's mandate and receipt models (PaymentMandate, CheckoutMandate, OpenPaymentMandate, OpenCheckoutMandate, PaymentReceipt, CheckoutReceipt, and their shared types), generated directly from code/sdk/schemas/ap2 via a generator script (scripts/generate.ts) that mirrors the role of code/sdk/schemas/generate.py on the Python side. The generator fixes a correctness gap in the underlying json-schema-to-zod library: schemas where a oneOf sits alongside properties/required (payment_receipt.json, checkout_receipt.json) had their branch-specific required fields silently dropped, so a 'Success' payment receipt without confirmation IDs would incorrectly validate. materializeSiblingOneOf merges outer and branch properties/required before generation to fix this; covered by a regression test. Addresses the TS types + validation half of google-agentic-commerce#67. Scoped to the type/validation layer only -- SD-JWT signing, mandate chain builders, and JWT/JWK helpers from ap2.sdk are left for a follow-up PR. Unrelated to google-agentic-commerce#144, which is a sample application with inline, non-reusable schema definitions rather than a publishable SDK.
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
- generate.ts hardcoded singleQuote: true instead of reading the repo's .prettierrc, so generated output diverged from the repo's actual formatting (double quotes) and failed the Prettier check. Now resolves the project's own config via prettier.resolveConfig(). - Re-ran generate + prettier --write to bring all generated files and hand-written source into line with the resolved config. - Added protocol-specific terms (PISP, IDAS, QWAC, PKIX, Genkit, apidevtools, subschema) to .cspell/custom-words.txt; these are legitimate terms from AP2's own JSON Schemas and package names, not typos in this PR's code. - Fixed a markdownlint MD018 violation in the SDK README (line starting with "google-agentic-commerce#67" was parsed as an empty heading).
|
Fixed the spellcheck/Prettier/markdownlint findings from the Two remaining |
Description
Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
CONTRIBUTINGGuide.Addresses #67 🦕
What this adds
code/sdk/typescript, a publishable@ap2-protocol/sdknpm package: Zod schemas + TypeScript types for AP2's mandate and receipt models, generated directly from the canonical JSON Schemas incode/sdk/schemas/ap2(the same source of truthcode/sdk/schemas/generate.pygenerates the Python SDK from).Exports
PaymentMandate,CheckoutMandate,OpenPaymentMandate,OpenCheckoutMandate,PaymentReceipt,CheckoutReceipt, plus the shared types (Amount,Merchant,Pisp,PaymentInstrument,Jwk,Item,ReceiptStatus) — each as both a Zod validator and its inferred TS type.npm run generate(scripts/generate.ts) dereferences every schema undercode/sdk/schemas/ap2and emits the matching Zod code, so this can't drift from the protocol the way hand-maintained TS types would (the exact risk the issue calls out under "alternatives considered").A correctness bug found and fixed along the way
payment_receipt.json/checkout_receipt.jsoneach put aoneOfalongsideproperties/requiredat the schema root (Success branch requirespsp_confirmation_id/network_confirmation_id; Error branch requireserror/error_description). The underlyingjson-schema-to-zodgenerator only reads each branch's discriminatorconstand silently drops each branch's ownrequiredlist in this "oneOf as sibling constraint" shape — so astatus: "Success"receipt with no confirmation IDs generated as valid.materializeSiblingOneOfinscripts/generate.tsmerges outer + branchproperties/requiredbefore generation (the same shape the generator already handles correctly when branches are fully self-contained, e.g.OpenPaymentMandate.constraints). Covered by a regression test intest/schemas.test.ts.Scope
This covers the TS types + validation half of #67 ("mirrors the AP2 IntentMandate, CartMandate, PaymentMandate ... models with validation, e.g. zod"). It intentionally does not port
ap2.sdk's SD-JWT signing/verification, mandate chain builders, or JWT/JWK helpers — that's cryptography-sensitive code better reviewed on its own. Also unrelated to #144: that PR is a sample application (Genkit + A2A agents) with its own inline, non-reusable schema types, not a publishable library — this package is the standalone SDK #67 is asking for, and the sample could depend on it in a follow-up.Known limitations (documented in the package README)
containsisn't enforced. Two schemas usecontainsto require "at least one array element matching a specific alternative" (e.g.OpenCheckoutMandate.constraintsshould include acheckout.line_itemsentry).json-schema-to-zoddoesn't supportcontains; it's silently dropped rather than hand-patched into generated output. Flagged in the README rather than papered over — happy to follow up with a.refine()-emitting fix if that's the preferred direction.oneOf-branch schemas (PaymentReceipt,CheckoutReceipt,OpenPaymentMandate.constraintsentries) — generated asz.object(...).and(z.any().superRefine(...)), and TS collapsesT & anytoany. Runtime validation is correct and tested; only static narrowing is coarser than the flat schemas.Testing
All pass locally.
dist/is gitignored (not committed), matching a standard npm package layout;package-lock.jsonis committed, matchingcode/web-client.CLA
I'll sign the Google CLA via the bot's prompt on this PR.