From 25713a4e5796a27590aaf6ea0cddb18046b2433a Mon Sep 17 00:00:00 2001 From: "Mericio \"Hablo\" Salazar" <218162243+simihablo@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:35:24 -0500 Subject: [PATCH 01/13] fix(schemas): derive every wire shape from @meshery/schemas, repair three drifts Full schema-consumer audit of sistent. Every local declaration of a meshery/schemas-owned construct is now derived from the canonical type instead of hand-copied, and three shapes that had already drifted off the wire are repaired. Sistent is upstream of Meshery UI, Layer5 Cloud UI and Kanvas, so a shape copied here propagates to all of them and an upstream rename arrives as a silent `undefined` rather than an error. Live defects fixed - ShareModal posted `{grant_access, revoke_access, notify_users}` with `{actor_id, actor_type}` actors. meshery-cloud flipped that contract to `{grantAccess, revokeAccess, notifyUsers}` / `{actorId, actorType}` on 2026-04-28 and decodes it with a strict `json.Unmarshal` into `omitempty` structs, then answers 200 regardless - so every share since has reported success and granted nothing. The payload now has its own module with a test pinning the literal key names. - TeamTable's bulk-delete read `teamId` / `team_name` off a team record. Neither field exists: meshery-cloud aliases its Team straight to the canonical v1beta2 construct, which identifies by `id` / `name`. Both pushed `undefined`. - WorkspaceCard typed a workspace `id` as `number` where the canonical is a uuid string, and Pattern typed `createdAt` / `updatedAt` as `Date` where the wire carries RFC 3339 strings - the two read sites had grown `.toString()` calls to paper over it. Also removes `src/types/meshery-schemas.d.ts`, three ambient `declare module`s that shadowed the canonical subpath declarations with a mapping to a *different* version's schema object; the package exports `./constructs/*` with types and this repo resolves with `moduleResolution: "bundler"`, so they were redundant and wrong. Fixes two MUI v7 prop removals (`imgProps`, `secondaryTypographyProps`) surfaced by the dts build along the way. Guards, each proven to fail against its own defect first: - src/__testing__/resourceAccessPayload.test.ts pins the share payload keys. - src/__testing__/schemaConstructAliasTypes.test.ts compiles a fixture that asserts every omitted or narrowed key still exists on its canonical construct - `Omit` where `T` lacks `gone` is a silent no-op, so deriving from the canonical does not by itself survive the rename it guards against. Kept deliberately narrower, each with a filed upstream issue linked from the type's doc comment: meshery/schemas#1142 (catalogData declares `class` / `snapshotURL`; every server emits `contentClass` / `imageURL`), #1143 (v1beta3 getTeamsOfWorkspace still $refs the snake_case v1beta1 TeamPage), `avatarUrl`). Adds `buildGrantAccessPayload`, `buildRevokeAccessPayload`, `toResourceAccessActors` and their types to the public API so hosts stop hand-rolling the body that caused the share bug. Signed-off-by: Mericio "Hablo" Salazar <218162243+simihablo@users.noreply.github.com> --- AGENTS.md | 28 +++ .../fixtures/schemaConstructAliases.ts | 176 ++++++++++++++++++ .../tsconfig.schemaConstructAliases.json | 7 + src/__testing__/resourceAccessPayload.test.ts | 89 +++++++++ .../schemaConstructAliasTypes.test.ts | 82 ++++++++ src/custom/CatalogDetail/UserInfo.tsx | 8 +- src/custom/CatalogDetail/types.ts | 24 ++- src/custom/CustomCatalog/CustomCard.tsx | 95 +++++++--- .../WorkspaceActivityWidget.tsx | 24 ++- src/custom/ShareModal/ShareModal.tsx | 57 +++--- src/custom/ShareModal/index.tsx | 7 + .../ShareModal/resourceAccessPayload.ts | 52 ++++++ .../TeamTable/TeamTableConfiguration.tsx | 19 +- src/custom/Workspaces/WorkspaceCard.tsx | 42 +++-- .../Workspaces/WorkspaceContentMoveModal.tsx | 9 +- .../WorkspaceEnvironmentSelection.tsx | 9 +- .../WorkspaceRecentActivityModal.tsx | 31 ++- src/custom/Workspaces/types.ts | 81 +++++--- src/index.tsx | 15 ++ src/types/meshery-schemas.d.ts | 17 -- src/utils/user.ts | 50 +++-- 21 files changed, 736 insertions(+), 186 deletions(-) create mode 100644 src/__testing__/fixtures/schemaConstructAliases.ts create mode 100644 src/__testing__/fixtures/tsconfig.schemaConstructAliases.json create mode 100644 src/__testing__/resourceAccessPayload.test.ts create mode 100644 src/__testing__/schemaConstructAliasTypes.test.ts create mode 100644 src/custom/ShareModal/resourceAccessPayload.ts delete mode 100644 src/types/meshery-schemas.d.ts diff --git a/AGENTS.md b/AGENTS.md index 5f60a3ded..30cc5f208 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -146,6 +146,34 @@ sheet's human-readable category + function text, while the UUID is stable. Editi typo fix, a plural made singular - renames the exported constant and orphans the old one. That is how `1.3.35 -> 1.3.36` renamed 10 keys with every UUID unchanged, in a patch release. +## Wire shapes are derived from `@meshery/schemas`, never re-declared + +Any type that is decoded from or encoded to a Meshery/Layer5 API is owned by `meshery/schemas`. +Sistent is upstream of every Meshery UI, so a shape hand-copied here propagates to all of them and a +rename upstream reaches consumers as a silent `undefined` rather than an error. Derive from the +canonical construct instead - `import type { components } from '@meshery/schemas/constructs///'` +- and express any divergence as an explicit `Pick`/`Omit`/`&` carrying the reason. + +**`Omit` where `T` has no `gone` is a silent no-op**, so derivation alone does not survive +the rename it was adopted to catch: the omit stops removing anything and the override quietly becomes +an addition. [`src/__testing__/fixtures/schemaConstructAliases.ts`](src/__testing__/fixtures/schemaConstructAliases.ts) +closes that by asserting every omitted/narrowed key still exists upstream, and is the source of truth +for which local types are bound to which construct and why each divergence is kept. Read it before +adding or widening one. It is compiled by a `tsc` guard, not by `jest` - see the `tsc`-over-a-fixture +note under "Repo state that looks broken but is pre-existing". + +When the canonical is the wrong one, keep the narrower local shape, link a filed `meshery/schemas` +issue from the type's doc comment, and verify the claim against the actual server struct before +filing - open examples: [#1142](https://github.com/meshery/schemas/issues/1142) (catalog data), +[#1143](https://github.com/meshery/schemas/issues/1143), [#1144](https://github.com/meshery/schemas/issues/1144) +(share/revoke), [#1145](https://github.com/meshery/schemas/issues/1145). + +A wire mismatch here is not loud. meshery-cloud decodes request bodies with a strict `json.Unmarshal` +into `omitempty` structs and still answers 200, so a stale outbound key name is a successful no-op - +which is how sistent's share modal granted nothing for three months after the Phase 4 camelCase flip. +Outbound payload shapes therefore get their own module and a test pinning the literal key names, as +[`src/custom/ShareModal/resourceAccessPayload.ts`](src/custom/ShareModal/resourceAccessPayload.ts) does. + ## `disabled` on a MUI `MenuItem` does not stop a click MUI enforces `disabled` on non-`