feat(web_core): add PayloadValidator, UAX 31 identifier checks, and full JSON Schema constraint parity - #2716
Open
gspencergoog wants to merge 6 commits into
Open
gspencergoog wants to merge 6 commits into
gspencergoog wants to merge 6 commits into
Conversation
gspencergoog
force-pushed
the
v1_0_ts_payload_validator
branch
from
September 21, 2026 23:27
7c0b5c7 to
abff58d
Compare
gspencergoog
force-pushed
the
v1_0_ts_payload_validator
branch
2 times, most recently
from
September 21, 2026 23:51
646cc38 to
b85abbd
Compare
gspencergoog
added this pull request to stack #2719
September 21, 2026 23:51
gspencergoog
removed this pull request from stack #2719
September 21, 2026 23:52
gspencergoog
added this pull request to stack #2720
September 21, 2026 23:52
gspencergoog
force-pushed
the
v1_0_ts_payload_validator
branch
from
September 22, 2026 16:38
b85abbd to
64ca2b9
Compare
gspencergoog
force-pushed
the
v1_0_ts_payload_validator
branch
3 times, most recently
from
September 22, 2026 18:42
1712e85 to
f9d617c
Compare
nan-yu
reviewed
Sep 22, 2026
gspencergoog
force-pushed
the
v1_0_ts_payload_validator
branch
from
September 22, 2026 21:56
f9d617c to
22a2e63
Compare
…full JSON Schema constraint parity Introduces `PayloadValidator` in `typescript/web_core/src/validation/payload-validator.ts`, scoped to a single `Catalog`, and extracts UAX #31 identifier validation into `typescript/web_core/src/common/uax31.ts` using the normative `XID_Start` / `XID_Continue` Unicode property classes. Closes all seven validation disparities between TypeScript's Zod-based validator and Python's `Draft202012Validator` / `PayloadValidator` without introducing an Ajv runtime dependency: 1. Recursively walks component property trees (`validateNestedFunctions`) to validate nested `{call, args}` function calls against their target catalog, resolving `catalogId` overrides via `availableCatalogs`. 2. Supports self-recursive `#/$defs/...` references (e.g. `TreeNode`) at arbitrary depth via `z.lazy` and per-branch `visitedPointers` sets. 3. Rejects unresolvable `#/$defs/...` pointers during validation instead of silently falling back to `z.unknown()`. 4. Preserves `DataBinding` and `FunctionCall` union branches when combined with `enum` in `oneOf` / `anyOf` schemas. 5. Translates JSON Schema bounds and literal constraints (`minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf`, `minLength`, `maxLength`, `minItems`, `maxItems`, `uniqueItems`, `const`, and `not`) into Zod refinements. 6. Enforces `additionalProperties: false` and `unevaluatedProperties: false` on inline nested `type: object` schemas via `.strict()`. 7. Enforces single-branch exclusivity (`matchCount === 1`) for `oneOf` schemas distinctly from `anyOf`. Also delegates component and theme validation in `MessageProcessor` and incoming function argument validation in `RpcHandler` to `PayloadValidator`, and strengthens `conformance/core/validator_v1_0.yaml` (`test_v10_uax31_invalid_identifier_error`) along with `expectError.message` assertions and `catalogPaths` basic-catalog ID aliasing in `conformance_test.mjs`.
…ema loader - Pipe raw input through superRefine before baseUnion in oneOf to check exclusivity on un-transformed values - Preserve raw args when defined in validateNestedFunctions to catch non-object payloads - Memoize local $defs compilation in convertPropertyToZod to avoid re-compilation on every z.lazy validation - Serialize array items with recursively sorted keys in canonicalJsonStringify for uniqueItems checking - Add regression tests for oneOf, non-object function args, and uniqueItems key ordering
…redundant Zod parsing
gspencergoog
force-pushed
the
v1_0_ts_payload_validator
branch
from
September 22, 2026 23:53
22a2e63 to
625a937
Compare
- Remove availableCatalogs parameter from PayloadValidator constructor and from MessageProcessor.validateComponentUpdate - In validateNestedFunctions, check UAX #31 identifier syntax on foreign-catalog calls but skip catalog schema validation, delegating function validation to runtime resolution in DataContext - Update unit tests in payload-validator.test.ts to assert single-catalog behavior and foreign-call identifier checks
Collaborator
Author
|
@nan-yu PTAL |
This branch has not been deployed
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
Adds catalog-scoped
PayloadValidatorand shared UAX#31identifier validation in@a2ui/web_core, and closes JSON Schema validation disparities with Python'sDraft202012Validatordirectly inschema_loader.tswithout an Ajv dependency.Part of Stack #2720 (stacked on #2715).
Reviewer Focus
src/validation/payload-validator.ts: VerifyvalidateFunction's@indexfallback toIndexApiwhen un-registered incatalog.functions, argument validation returning parsed records to eliminate duplicate parsing inRpcHandler, and recursivevalidateNestedFunctionstraversal withcatalogIdoverrides.src/catalog/schema_loader.ts: ScrutinizeconvertRefToZod(z.lazycycle handling withdefCachecaching),convertUnionToZod(oneOfexclusivity vsanyOf), and numeric/string/array constraint conversion.conformance/core/validator_v1_0.yamland schema type registrations insrc/types/can be safely skimmed.Changes
#31identifier validation (src/common/uax31.ts):isValidUax31IdentifierandassertUax31Identifierfromschema_loader.ts.ID_Start/ID_Continueto the specification'sXID_Start/XID_ContinueUnicode property classes.A2uiCatalogErroron invalid identifiers at catalog construction time.PayloadValidator(src/validation/payload-validator.ts):validateComponent,validateFunction, andvalidateThemescoped to a singleCatalog.#31identifier checks on component instance IDs, function names, and argument keys.@indexsystem function fallback (IndexApi) so custom v1.0 catalogs validate@indexcalls under strict validation.validateFunctionto avoid redundant second-pass parsing.{call, args}objects within component properties (validateNestedFunctions), resolvingcatalogIdoverrides againstavailableCatalogs.assertFunctionIdentifiersto maintain cognitive complexitysrc/catalog/schema_loader.ts):z.lazyrecursion and per-branchvisitedPointerssets so self-recursive#/$defs/...references (such asTreeNode) validate at arbitrary depth, caching compiled closures indefCache.z.unknown()fallbacks on unresolvable#/$defs/...references with a failingsuperRefinevalidator.DataBindingandFunctionCalltoCOMMON_TYPE_SCHEMAS, preserving union branches when combined withenuminoneOf/anyOf.minimum,maximum,minLength,maxLength,minItems,maxItems,uniqueItems,const,not)..strict()on inline nestedtype: objectschemas whenadditionalProperties: falseis set.oneOfsingle-branch exclusivity (matchCount === 1) distinctly fromanyOf.$refand union conversion into helper functions (convertRefToZod,convertUnionToZod).message-processor.ts,rpc-handler.ts):MessageProcessorand argument validation inRpcHandler.parseArgumentsthroughPayloadValidator.validator_v1_0.yaml,conformance_test.mjs):test_v10_uax31_invalid_identifier_errorwith a valid root component oncreateSurfaceand anexpectError.messagecheck.Impact & Risks
#31. Payloads targeting v0.9 catalogs remain unaffected.Catalog.fromSchemanow enforce bounds, recursive$defs, nestedadditionalProperties: false, andoneOfexclusivity at runtime.Testing
web_core(includinguax31.test.tsandpayload-validator.test.ts):yarn workspace @a2ui/web_core test