@@ -19,6 +19,7 @@ import type {
1919 CollectionValue ,
2020 ItemMethod ,
2121 ListMethod ,
22+ MethodParameter ,
2223 TypeDiscriminatorToType ,
2324 PropNames ,
2425} from "./metadata.js" ;
@@ -1326,20 +1327,28 @@ export class ModelApiClient<TModel extends Model<ModelType>> extends ApiClient<
13261327 ) : ItemResultPromise < TModel > {
13271328 const { fields, ...params } = parameters ?? new SaveParameters < TModel > ( ) ;
13281329
1329- const paramsMeta = Object . fromEntries ( [
1330- [
1331- "$type" ,
1332- {
1333- type : "string" ,
1334- name : "$type" ,
1335- displayName : "$type" ,
1330+ // The item is fully serialized to a DTO here (respecting `fields` for
1331+ // surgical saves). Declare the resulting fields as passthrough `unknown`
1332+ // params so that `getRequestBody` does not serialize them a *second* time.
1333+ // A double serialization is not idempotent for polymorphic child objects
1334+ // (their type discriminator is a `$type` string once serialized, not a
1335+ // `$metadata` reference), which would downgrade them to their base type.
1336+ const dto = mapToDtoFiltered ( item , fields ) ! ;
1337+
1338+ // Order the params by `$type` (if present) followed by metadata declaration
1339+ // order so that the serialized request body's field order is stable and
1340+ // matches what it was when each field was individually re-serialized.
1341+ const paramsMeta : { [ name : string ] : MethodParameter } = { } ;
1342+ for ( const name of [ "$type" , ...Object . keys ( this . $metadata . props ) ] ) {
1343+ if ( name in dto ) {
1344+ paramsMeta [ name ] = {
1345+ type : "unknown" ,
1346+ name,
1347+ displayName : name ,
13361348 role : "value" ,
1337- } ,
1338- ] ,
1339- ...Object . entries ( this . $metadata . props ) . filter (
1340- ( p ) => ! p [ 1 ] . dontSerialize ,
1341- ) ,
1342- ] ) ;
1349+ } ;
1350+ }
1351+ }
13431352
13441353 return this . $invoke (
13451354 {
@@ -1350,7 +1359,7 @@ export class ModelApiClient<TModel extends Model<ModelType>> extends ApiClient<
13501359 params : paramsMeta ,
13511360 return : this . $itemValueMeta ,
13521361 } ,
1353- mapToDtoFiltered ( item , fields ) ! ,
1362+ dto ,
13541363 config ,
13551364 params ,
13561365 ) ;
0 commit comments