fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #2870 from hey-api/copilot/fix-valibot-additional-properties

authored by

Lubos and committed by
GitHub
02295510 a71d840f

+691 -337
+5
.changeset/violet-pets-care.md
··· 1 + --- 2 + "@hey-api/openapi-ts": patch 3 + --- 4 + 5 + fix(valibot): improve handling of additionalProperties type
+2 -2
packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format-valibot/valibot.gen.ts
··· 12 12 id: v.string() 13 13 }); 14 14 15 - export const vBar = v.object({ 15 + export const vBar = v.objectWithRest({ 16 16 foo: v.pipe(v.number(), v.integer()) 17 - }); 17 + }, v.pipe(v.number(), v.integer())); 18 18 19 19 export const vPostFooData = v.object({ 20 20 body: v.optional(v.never()),
+12 -8
packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/valibot/default/valibot.gen.ts
··· 123 123 /** 124 124 * This is a string dictionary 125 125 */ 126 - export const vDictionaryWithString = v.object({}); 126 + export const vDictionaryWithString = v.record(v.string(), v.string()); 127 127 128 128 /** 129 129 * This is a string dictionary 130 130 */ 131 - export const vDictionaryWithDictionary = v.record(v.string(), v.object({})); 131 + export const vDictionaryWithDictionary = v.record(v.string(), v.record(v.string(), v.string())); 132 132 133 133 /** 134 134 * This is a complex dictionary ··· 184 184 /** 185 185 * This is a complex dictionary 186 186 */ 187 - export const vDictionaryWithArray = v.object({}); 187 + export const vDictionaryWithArray = v.record(v.string(), v.array(vModelWithString)); 188 188 189 189 /** 190 190 * This is a model with one string property ··· 239 239 * This is a model with nested enums 240 240 */ 241 241 export const vModelWithNestedEnums = v.object({ 242 - dictionaryWithEnum: v.optional(v.object({})), 243 - dictionaryWithEnumFromDescription: v.optional(v.object({})), 242 + dictionaryWithEnum: v.optional(v.record(v.string(), v.picklist([ 243 + 'Success', 244 + 'Warning', 245 + 'Error' 246 + ]))), 247 + dictionaryWithEnumFromDescription: v.optional(v.record(v.string(), v.pipe(v.number(), v.integer()))), 244 248 arrayWithEnum: v.optional(v.array(v.picklist([ 245 249 'Success', 246 250 'Warning', ··· 262 266 * This is a model with one property containing a dictionary 263 267 */ 264 268 export const vModelWithDictionary = v.object({ 265 - prop: v.optional(v.object({})) 269 + prop: v.optional(v.record(v.string(), v.string())) 266 270 }); 267 271 268 272 /** ··· 714 718 parameterString: v.optional(v.string(), 'default'), 715 719 parameterBoolean: v.optional(v.boolean(), true), 716 720 parameterArray: v.array(v.string()), 717 - parameterDictionary: v.object({}), 721 + parameterDictionary: v.record(v.string(), v.unknown()), 718 722 parameterEnum: v.picklist([ 719 723 'Success', 720 724 'Warning', ··· 727 731 v.number(), 728 732 v.string(), 729 733 v.boolean(), 730 - v.object({}) 734 + v.record(v.string(), v.unknown()) 731 735 ]); 732 736 733 737 export const vComplexTypesData = v.object({
+2 -2
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format-valibot/valibot.gen.ts
··· 12 12 id: v.string() 13 13 }); 14 14 15 - export const vBar = v.object({ 15 + export const vBar = v.objectWithRest({ 16 16 foo: v.pipe(v.number(), v.integer()) 17 - }); 17 + }, v.pipe(v.number(), v.integer())); 18 18 19 19 export const vPostFooData = v.object({ 20 20 body: v.optional(v.never()),
+40 -36
packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/valibot/default/valibot.gen.ts
··· 164 164 /** 165 165 * This is a string dictionary 166 166 */ 167 - export const vDictionaryWithString = v.object({}); 167 + export const vDictionaryWithString = v.record(v.string(), v.string()); 168 168 169 - export const vDictionaryWithPropertiesAndAdditionalProperties = v.object({ 169 + export const vDictionaryWithPropertiesAndAdditionalProperties = v.objectWithRest({ 170 170 foo: v.optional(v.number()), 171 171 bar: v.optional(v.boolean()) 172 - }); 172 + }, v.string()); 173 173 174 174 /** 175 175 * This is a string dictionary 176 176 */ 177 - export const vDictionaryWithDictionary = v.record(v.string(), v.object({})); 177 + export const vDictionaryWithDictionary = v.record(v.string(), v.record(v.string(), v.string())); 178 178 179 179 /** 180 180 * This is a complex dictionary ··· 228 228 /** 229 229 * This is a complex dictionary 230 230 */ 231 - export const vDictionaryWithArray = v.object({}); 231 + export const vDictionaryWithArray = v.record(v.string(), v.array(vModelWithString)); 232 232 233 233 /** 234 234 * This is a model with one string property ··· 311 311 * This is a model with nested enums 312 312 */ 313 313 export const vModelWithNestedEnums = v.object({ 314 - dictionaryWithEnum: v.optional(v.object({})), 315 - dictionaryWithEnumFromDescription: v.optional(v.object({})), 314 + dictionaryWithEnum: v.optional(v.record(v.string(), v.picklist([ 315 + 'Success', 316 + 'Warning', 317 + 'Error' 318 + ]))), 319 + dictionaryWithEnumFromDescription: v.optional(v.record(v.string(), v.pipe(v.number(), v.integer()))), 316 320 arrayWithEnum: v.optional(v.array(v.picklist([ 317 321 'Success', 318 322 'Warning', ··· 340 344 * This is a model with one property containing a dictionary 341 345 */ 342 346 export const vModelWithDictionary = v.object({ 343 - prop: v.optional(v.object({})) 347 + prop: v.optional(v.record(v.string(), v.string())) 344 348 }); 345 349 346 350 /** ··· 501 505 export const vCompositionWithOneOfAndSimpleDictionary = v.object({ 502 506 propA: v.optional(v.union([ 503 507 v.boolean(), 504 - v.object({}) 508 + v.record(v.string(), v.number()) 505 509 ])) 506 510 }); 507 511 ··· 511 515 export const vCompositionWithOneOfAndSimpleArrayDictionary = v.object({ 512 516 propA: v.optional(v.union([ 513 517 v.boolean(), 514 - v.object({}) 518 + v.record(v.string(), v.array(v.boolean())) 515 519 ])) 516 520 }); 517 521 ··· 521 525 export const vCompositionWithOneOfAndComplexArrayDictionary = v.object({ 522 526 propA: v.optional(v.union([ 523 527 v.boolean(), 524 - v.object({}) 528 + v.record(v.string(), v.array(v.unknown())) 525 529 ])) 526 530 }); 527 531 ··· 709 713 /** 710 714 * This is a free-form object without additionalProperties. 711 715 */ 712 - export const vFreeFormObjectWithoutAdditionalProperties = v.object({}); 716 + export const vFreeFormObjectWithoutAdditionalProperties = v.record(v.string(), v.unknown()); 713 717 714 718 /** 715 719 * This is a free-form object with additionalProperties: true. 716 720 */ 717 - export const vFreeFormObjectWithAdditionalPropertiesEqTrue = v.object({}); 721 + export const vFreeFormObjectWithAdditionalPropertiesEqTrue = v.record(v.string(), v.unknown()); 718 722 719 723 /** 720 724 * This is a free-form object with additionalProperties: {}. 721 725 */ 722 - export const vFreeFormObjectWithAdditionalPropertiesEqEmptyObject = v.object({}); 726 + export const vFreeFormObjectWithAdditionalPropertiesEqEmptyObject = v.record(v.string(), v.unknown()); 723 727 724 728 export const vModelWithConst = v.object({ 725 729 String: v.optional(v.picklist([ ··· 735 739 /** 736 740 * This is a model with one property and additionalProperties: true 737 741 */ 738 - export const vModelWithAdditionalPropertiesEqTrue = v.object({ 742 + export const vModelWithAdditionalPropertiesEqTrue = v.objectWithRest({ 739 743 prop: v.optional(v.string()) 740 - }); 744 + }, v.unknown()); 741 745 742 746 export const vNestedAnyOfArraysNullable = v.object({ 743 747 nullableArray: v.optional(v.union([ ··· 987 991 }) 988 992 ]); 989 993 990 - export const vAdditionalPropertiesIntegerIssue = v.object({ 994 + export const vAdditionalPropertiesIntegerIssue = v.objectWithRest({ 991 995 value: v.pipe(v.number(), v.integer()) 992 - }); 996 + }, v.pipe(v.number(), v.integer())); 993 997 994 - export const vGenericSchemaDuplicateIssue1SystemBoolean = v.object({ 998 + export const vGenericSchemaDuplicateIssue1SystemBoolean = v.objectWithRest({ 995 999 item: v.optional(v.boolean()), 996 1000 error: v.optional(v.union([ 997 1001 v.string(), 998 1002 v.null() 999 1003 ])), 1000 1004 hasError: v.optional(v.pipe(v.boolean(), v.readonly())), 1001 - data: v.optional(v.object({})) 1002 - }); 1005 + data: v.optional(v.record(v.string(), v.never())) 1006 + }, v.never()); 1003 1007 1004 - export const vGenericSchemaDuplicateIssue1SystemString = v.object({ 1008 + export const vGenericSchemaDuplicateIssue1SystemString = v.objectWithRest({ 1005 1009 item: v.optional(v.union([ 1006 1010 v.string(), 1007 1011 v.null() ··· 1011 1015 v.null() 1012 1016 ])), 1013 1017 hasError: v.optional(v.pipe(v.boolean(), v.readonly())) 1014 - }); 1018 + }, v.never()); 1015 1019 1016 1020 export const vOneOfAllOfIssue = v.union([ 1017 1021 v.intersect([ ··· 1113 1117 vGenericSchemaDuplicateIssue1SystemString 1114 1118 ]); 1115 1119 1116 - export const vGenericSchemaDuplicateIssue1SystemBooleanWritable = v.object({ 1120 + export const vGenericSchemaDuplicateIssue1SystemBooleanWritable = v.objectWithRest({ 1117 1121 item: v.optional(v.boolean()), 1118 1122 error: v.optional(v.union([ 1119 1123 v.string(), 1120 1124 v.null() 1121 1125 ])), 1122 - data: v.optional(v.object({})) 1123 - }); 1126 + data: v.optional(v.record(v.string(), v.never())) 1127 + }, v.never()); 1124 1128 1125 - export const vGenericSchemaDuplicateIssue1SystemStringWritable = v.object({ 1129 + export const vGenericSchemaDuplicateIssue1SystemStringWritable = v.objectWithRest({ 1126 1130 item: v.optional(v.union([ 1127 1131 v.string(), 1128 1132 v.null() ··· 1131 1135 v.string(), 1132 1136 v.null() 1133 1137 ])) 1134 - }); 1138 + }, v.never()); 1135 1139 1136 1140 /** 1137 1141 * This is a reusable parameter ··· 1140 1144 1141 1145 export const vCompositionWithOneOfAndProperties = v.intersect([ 1142 1146 v.union([ 1143 - v.object({ 1147 + v.objectWithRest({ 1144 1148 foo: vSimpleParameter 1145 - }), 1146 - v.object({ 1149 + }, v.never()), 1150 + v.objectWithRest({ 1147 1151 bar: vNonAsciiStringæøåÆøÅöôêÊ字符串 1148 - }) 1152 + }, v.never()) 1149 1153 ]), 1150 1154 v.object({ 1151 1155 baz: v.union([ ··· 1316 1320 1317 1321 export const vCallWithParametersData = v.object({ 1318 1322 body: v.union([ 1319 - v.object({}), 1323 + v.record(v.string(), v.unknown()), 1320 1324 v.null() 1321 1325 ]), 1322 1326 path: v.object({ ··· 1627 1631 v.null() 1628 1632 ]), true), 1629 1633 parameterObject: v.optional(v.union([ 1630 - v.object({}), 1634 + v.record(v.string(), v.unknown()), 1631 1635 v.null() 1632 1636 ]), null), 1633 1637 parameterArray: v.union([ ··· 1635 1639 v.null() 1636 1640 ]), 1637 1641 parameterDictionary: v.union([ 1638 - v.object({}), 1642 + v.record(v.string(), v.unknown()), 1639 1643 v.null() 1640 1644 ]), 1641 1645 parameterEnum: v.picklist([ ··· 1650 1654 v.number(), 1651 1655 v.string(), 1652 1656 v.boolean(), 1653 - v.object({}) 1657 + v.record(v.string(), v.unknown()) 1654 1658 ]); 1655 1659 1656 1660 export const vUploadFileData = v.object({
+2 -2
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format-valibot/valibot.gen.ts
··· 12 12 id: v.string() 13 13 }); 14 14 15 - export const vBar = v.object({ 15 + export const vBar = v.objectWithRest({ 16 16 foo: v.pipe(v.number(), v.integer()) 17 - }); 17 + }, v.pipe(v.number(), v.integer())); 18 18 19 19 export const vPostFooData = v.object({ 20 20 body: v.optional(v.never()),
+40 -36
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/valibot/default/valibot.gen.ts
··· 167 167 /** 168 168 * This is a string dictionary 169 169 */ 170 - export const vDictionaryWithString = v.object({}); 170 + export const vDictionaryWithString = v.record(v.string(), v.string()); 171 171 172 - export const vDictionaryWithPropertiesAndAdditionalProperties = v.object({ 172 + export const vDictionaryWithPropertiesAndAdditionalProperties = v.objectWithRest({ 173 173 foo: v.optional(v.number()), 174 174 bar: v.optional(v.boolean()) 175 - }); 175 + }, v.string()); 176 176 177 177 /** 178 178 * This is a string dictionary 179 179 */ 180 - export const vDictionaryWithDictionary = v.record(v.string(), v.object({})); 180 + export const vDictionaryWithDictionary = v.record(v.string(), v.record(v.string(), v.string())); 181 181 182 182 /** 183 183 * This is a complex dictionary ··· 231 231 /** 232 232 * This is a complex dictionary 233 233 */ 234 - export const vDictionaryWithArray = v.object({}); 234 + export const vDictionaryWithArray = v.record(v.string(), v.array(vModelWithString)); 235 235 236 236 /** 237 237 * This is a model with one string property ··· 314 314 * This is a model with nested enums 315 315 */ 316 316 export const vModelWithNestedEnums = v.object({ 317 - dictionaryWithEnum: v.optional(v.object({})), 318 - dictionaryWithEnumFromDescription: v.optional(v.object({})), 317 + dictionaryWithEnum: v.optional(v.record(v.string(), v.picklist([ 318 + 'Success', 319 + 'Warning', 320 + 'Error' 321 + ]))), 322 + dictionaryWithEnumFromDescription: v.optional(v.record(v.string(), v.pipe(v.number(), v.integer()))), 319 323 arrayWithEnum: v.optional(v.array(v.picklist([ 320 324 'Success', 321 325 'Warning', ··· 343 347 * This is a model with one property containing a dictionary 344 348 */ 345 349 export const vModelWithDictionary = v.object({ 346 - prop: v.optional(v.object({})) 350 + prop: v.optional(v.record(v.string(), v.string())) 347 351 }); 348 352 349 353 /** ··· 496 500 export const vCompositionWithOneOfAndSimpleDictionary = v.object({ 497 501 propA: v.optional(v.union([ 498 502 v.boolean(), 499 - v.object({}) 503 + v.record(v.string(), v.number()) 500 504 ])) 501 505 }); 502 506 ··· 506 510 export const vCompositionWithOneOfAndSimpleArrayDictionary = v.object({ 507 511 propA: v.optional(v.union([ 508 512 v.boolean(), 509 - v.object({}) 513 + v.record(v.string(), v.array(v.boolean())) 510 514 ])) 511 515 }); 512 516 ··· 516 520 export const vCompositionWithOneOfAndComplexArrayDictionary = v.object({ 517 521 propA: v.optional(v.union([ 518 522 v.boolean(), 519 - v.object({}) 523 + v.record(v.string(), v.array(v.unknown())) 520 524 ])) 521 525 }); 522 526 ··· 704 708 /** 705 709 * This is a free-form object without additionalProperties. 706 710 */ 707 - export const vFreeFormObjectWithoutAdditionalProperties = v.object({}); 711 + export const vFreeFormObjectWithoutAdditionalProperties = v.record(v.string(), v.unknown()); 708 712 709 713 /** 710 714 * This is a free-form object with additionalProperties: true. 711 715 */ 712 - export const vFreeFormObjectWithAdditionalPropertiesEqTrue = v.object({}); 716 + export const vFreeFormObjectWithAdditionalPropertiesEqTrue = v.record(v.string(), v.unknown()); 713 717 714 718 /** 715 719 * This is a free-form object with additionalProperties: {}. 716 720 */ 717 - export const vFreeFormObjectWithAdditionalPropertiesEqEmptyObject = v.object({}); 721 + export const vFreeFormObjectWithAdditionalPropertiesEqEmptyObject = v.record(v.string(), v.unknown()); 718 722 719 723 export const vModelWithConst = v.object({ 720 724 String: v.optional(v.literal('String')), ··· 726 730 /** 727 731 * This is a model with one property and additionalProperties: true 728 732 */ 729 - export const vModelWithAdditionalPropertiesEqTrue = v.object({ 733 + export const vModelWithAdditionalPropertiesEqTrue = v.objectWithRest({ 730 734 prop: v.optional(v.string()) 731 - }); 735 + }, v.unknown()); 732 736 733 737 export const vNestedAnyOfArraysNullable = v.object({ 734 738 nullableArray: v.optional(v.union([ ··· 985 989 }) 986 990 ]); 987 991 988 - export const vAdditionalPropertiesIntegerIssue = v.object({ 992 + export const vAdditionalPropertiesIntegerIssue = v.objectWithRest({ 989 993 value: v.pipe(v.number(), v.integer()) 990 - }); 994 + }, v.pipe(v.number(), v.integer())); 991 995 992 - export const vGenericSchemaDuplicateIssue1SystemBoolean = v.object({ 996 + export const vGenericSchemaDuplicateIssue1SystemBoolean = v.objectWithRest({ 993 997 item: v.optional(v.boolean()), 994 998 error: v.optional(v.union([ 995 999 v.string(), 996 1000 v.null() 997 1001 ])), 998 1002 hasError: v.optional(v.pipe(v.boolean(), v.readonly())), 999 - data: v.optional(v.object({})) 1000 - }); 1003 + data: v.optional(v.record(v.string(), v.never())) 1004 + }, v.never()); 1001 1005 1002 - export const vGenericSchemaDuplicateIssue1SystemString = v.object({ 1006 + export const vGenericSchemaDuplicateIssue1SystemString = v.objectWithRest({ 1003 1007 item: v.optional(v.union([ 1004 1008 v.string(), 1005 1009 v.null() ··· 1009 1013 v.null() 1010 1014 ])), 1011 1015 hasError: v.optional(v.pipe(v.boolean(), v.readonly())) 1012 - }); 1016 + }, v.never()); 1013 1017 1014 1018 export const vOneOfAllOfIssue = v.union([ 1015 1019 v.intersect([ ··· 1117 1121 vGenericSchemaDuplicateIssue1SystemString 1118 1122 ]); 1119 1123 1120 - export const vGenericSchemaDuplicateIssue1SystemBooleanWritable = v.object({ 1124 + export const vGenericSchemaDuplicateIssue1SystemBooleanWritable = v.objectWithRest({ 1121 1125 item: v.optional(v.boolean()), 1122 1126 error: v.optional(v.union([ 1123 1127 v.string(), 1124 1128 v.null() 1125 1129 ])), 1126 - data: v.optional(v.object({})) 1127 - }); 1130 + data: v.optional(v.record(v.string(), v.never())) 1131 + }, v.never()); 1128 1132 1129 - export const vGenericSchemaDuplicateIssue1SystemStringWritable = v.object({ 1133 + export const vGenericSchemaDuplicateIssue1SystemStringWritable = v.objectWithRest({ 1130 1134 item: v.optional(v.union([ 1131 1135 v.string(), 1132 1136 v.null() ··· 1135 1139 v.string(), 1136 1140 v.null() 1137 1141 ])) 1138 - }); 1142 + }, v.never()); 1139 1143 1140 1144 /** 1141 1145 * This is a reusable parameter ··· 1144 1148 1145 1149 export const vCompositionWithOneOfAndProperties = v.intersect([ 1146 1150 v.union([ 1147 - v.object({ 1151 + v.objectWithRest({ 1148 1152 foo: vSimpleParameter 1149 - }), 1150 - v.object({ 1153 + }, v.never()), 1154 + v.objectWithRest({ 1151 1155 bar: vNonAsciiStringæøåÆøÅöôêÊ字符串 1152 - }) 1156 + }, v.never()) 1153 1157 ]), 1154 1158 v.object({ 1155 1159 baz: v.union([ ··· 1329 1333 1330 1334 export const vCallWithParametersData = v.object({ 1331 1335 body: v.union([ 1332 - v.object({}), 1336 + v.record(v.string(), v.unknown()), 1333 1337 v.null() 1334 1338 ]), 1335 1339 path: v.object({ ··· 1640 1644 v.null() 1641 1645 ]), true), 1642 1646 parameterObject: v.optional(v.union([ 1643 - v.object({}), 1647 + v.record(v.string(), v.unknown()), 1644 1648 v.null() 1645 1649 ]), null), 1646 1650 parameterArray: v.union([ ··· 1648 1652 v.null() 1649 1653 ]), 1650 1654 parameterDictionary: v.union([ 1651 - v.object({}), 1655 + v.record(v.string(), v.unknown()), 1652 1656 v.null() 1653 1657 ]), 1654 1658 parameterEnum: v.union([ ··· 1664 1668 v.number(), 1665 1669 v.string(), 1666 1670 v.boolean(), 1667 - v.object({}) 1671 + v.record(v.string(), v.unknown()) 1668 1672 ]); 1669 1673 1670 1674 export const vUploadFileData = v.object({
+1 -1
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/schema-const/valibot.gen.ts
··· 14 14 v.literal('foo'), 15 15 v.literal(true) 16 16 ])), 17 - corge: v.optional(v.object({})), 17 + corge: v.optional(v.record(v.string(), v.unknown())), 18 18 garply: v.optional(v.literal(BigInt('10'))), 19 19 numberInt8: v.optional(v.literal(100)), 20 20 numberInt16: v.optional(v.literal(1000)),
+4 -4
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-circular-ref-2/valibot.gen.ts
··· 2 2 3 3 import * as v from 'valibot'; 4 4 5 - export const vBar: v.GenericSchema = v.object({ 5 + export const vBar: v.GenericSchema = v.objectWithRest({ 6 6 bar: v.union([ 7 7 v.array(v.lazy(() => { 8 8 return vBar; 9 9 })), 10 10 v.null() 11 11 ]) 12 - }); 12 + }, v.never()); 13 13 14 - export const vFoo = v.object({ 14 + export const vFoo = v.objectWithRest({ 15 15 foo: vBar 16 - }); 16 + }, v.never());
+236 -236
packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/webhooks/valibot.gen.ts
··· 3 3 import * as v from 'valibot'; 4 4 5 5 export const vSessionUserPhoneCalloutRingingWebhookRequest = v.object({ 6 - body: v.optional(v.object({ 6 + body: v.optional(v.objectWithRest({ 7 7 event: v.string(), 8 8 event_ts: v.pipe(v.union([ 9 9 v.number(), 10 10 v.string(), 11 11 v.bigint() 12 12 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 13 - payload: v.object({ 13 + payload: v.objectWithRest({ 14 14 account_id: v.string(), 15 - object: v.object({ 15 + object: v.objectWithRest({ 16 16 id: v.optional(v.pipe(v.union([ 17 17 v.number(), 18 18 v.string(), ··· 24 24 session_key: v.string(), 25 25 user_key: v.string(), 26 26 host_id: v.string(), 27 - participant: v.object({ 27 + participant: v.objectWithRest({ 28 28 invitee_name: v.string(), 29 29 phone_number: v.pipe(v.union([ 30 30 v.number(), ··· 36 36 v.string(), 37 37 v.bigint() 38 38 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')) 39 - }) 40 - }) 41 - }) 42 - })), 39 + }, v.never()) 40 + }, v.never()) 41 + }, v.never()) 42 + }, v.never())), 43 43 path: v.optional(v.never()), 44 44 query: v.optional(v.never()) 45 45 }); 46 46 47 47 export const vSessionUserRoomSystemCalloutRingingWebhookRequest = v.object({ 48 - body: v.optional(v.object({ 48 + body: v.optional(v.objectWithRest({ 49 49 event: v.string(), 50 50 event_ts: v.pipe(v.union([ 51 51 v.number(), 52 52 v.string(), 53 53 v.bigint() 54 54 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 55 - payload: v.object({ 55 + payload: v.objectWithRest({ 56 56 account_id: v.string(), 57 - object: v.object({ 57 + object: v.objectWithRest({ 58 58 id: v.optional(v.pipe(v.union([ 59 59 v.number(), 60 60 v.string(), ··· 66 66 host_id: v.string(), 67 67 message_id: v.string(), 68 68 inviter_name: v.string(), 69 - participant: v.object({ 69 + participant: v.objectWithRest({ 70 70 call_type: v.string(), 71 71 device_ip: v.string() 72 - }) 73 - }) 74 - }) 75 - })), 72 + }, v.unknown()) 73 + }, v.never()) 74 + }, v.never()) 75 + }, v.never())), 76 76 path: v.optional(v.never()), 77 77 query: v.optional(v.never()) 78 78 }); 79 79 80 80 export const vSessionRecordingStartedWebhookRequest = v.object({ 81 - body: v.optional(v.object({ 81 + body: v.optional(v.objectWithRest({ 82 82 event: v.picklist([ 83 83 'session.recording_started' 84 84 ]), ··· 87 87 v.string(), 88 88 v.bigint() 89 89 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 90 - payload: v.object({ 90 + payload: v.objectWithRest({ 91 91 account_id: v.string(), 92 - object: v.object({ 92 + object: v.objectWithRest({ 93 93 session_id: v.string(), 94 94 session_name: v.string(), 95 95 session_key: v.string(), ··· 99 99 recording_start: v.optional(v.string()), 100 100 recording_end: v.optional(v.string()) 101 101 }) 102 - }) 103 - }) 104 - })), 102 + }, v.never()) 103 + }, v.never()) 104 + }, v.never())), 105 105 path: v.optional(v.never()), 106 106 query: v.optional(v.never()) 107 107 }); 108 108 109 109 export const vSessionRecordingResumedWebhookRequest = v.object({ 110 - body: v.optional(v.object({ 110 + body: v.optional(v.objectWithRest({ 111 111 event: v.picklist([ 112 112 'session.recording_resumed' 113 113 ]), ··· 116 116 v.string(), 117 117 v.bigint() 118 118 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 119 - payload: v.object({ 119 + payload: v.objectWithRest({ 120 120 account_id: v.string(), 121 - object: v.object({ 121 + object: v.objectWithRest({ 122 122 session_id: v.string(), 123 123 session_name: v.string(), 124 124 session_key: v.string(), ··· 128 128 recording_start: v.optional(v.string()), 129 129 recording_end: v.optional(v.string()) 130 130 }) 131 - }) 132 - }) 133 - })), 131 + }, v.never()) 132 + }, v.never()) 133 + }, v.never())), 134 134 path: v.optional(v.never()), 135 135 query: v.optional(v.never()) 136 136 }); 137 137 138 138 export const vSessionLiveStreamingStoppedWebhookRequest = v.object({ 139 - body: v.optional(v.object({ 139 + body: v.optional(v.objectWithRest({ 140 140 event: v.picklist([ 141 141 'session.live_streaming_stopped' 142 142 ]), ··· 145 145 v.string(), 146 146 v.bigint() 147 147 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 148 - payload: v.object({ 148 + payload: v.objectWithRest({ 149 149 account_id: v.string(), 150 - object: v.object({ 150 + object: v.objectWithRest({ 151 151 id: v.string(), 152 152 session_id: v.string(), 153 153 session_name: v.string(), ··· 168 168 }), 169 169 date_time: v.pipe(v.string(), v.isoTimestamp()) 170 170 }) 171 - }) 172 - }) 173 - })), 171 + }, v.never()) 172 + }, v.never()) 173 + }, v.never())), 174 174 path: v.optional(v.never()), 175 175 query: v.optional(v.never()) 176 176 }); 177 177 178 178 export const vSessionStreamIngestionStoppedWebhookRequest = v.object({ 179 - body: v.optional(v.object({ 179 + body: v.optional(v.objectWithRest({ 180 180 event: v.picklist([ 181 181 'session.stream_ingestion_stopped' 182 182 ]), ··· 185 185 v.string(), 186 186 v.bigint() 187 187 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 188 - payload: v.object({ 188 + payload: v.objectWithRest({ 189 189 account_id: v.string(), 190 - object: v.object({ 190 + object: v.objectWithRest({ 191 191 session_id: v.string(), 192 192 session_name: v.string(), 193 193 session_key: v.optional(v.string()), ··· 199 199 stream_url: v.string(), 200 200 backup_stream_url: v.string() 201 201 }) 202 - }) 203 - }) 204 - })), 202 + }, v.never()) 203 + }, v.never()) 204 + }, v.never())), 205 205 path: v.optional(v.never()), 206 206 query: v.optional(v.never()) 207 207 }); 208 208 209 209 export const vSessionUserRoomSystemCalloutRejectedWebhookRequest = v.object({ 210 - body: v.optional(v.object({ 210 + body: v.optional(v.objectWithRest({ 211 211 event: v.string(), 212 212 event_ts: v.pipe(v.union([ 213 213 v.number(), 214 214 v.string(), 215 215 v.bigint() 216 216 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 217 - payload: v.object({ 217 + payload: v.objectWithRest({ 218 218 account_id: v.string(), 219 - object: v.object({ 219 + object: v.objectWithRest({ 220 220 id: v.optional(v.pipe(v.union([ 221 221 v.number(), 222 222 v.string(), ··· 228 228 host_id: v.string(), 229 229 message_id: v.string(), 230 230 inviter_name: v.string(), 231 - participant: v.object({ 231 + participant: v.objectWithRest({ 232 232 call_type: v.string(), 233 233 device_ip: v.string() 234 - }) 235 - }) 236 - }) 237 - })), 234 + }, v.unknown()) 235 + }, v.never()) 236 + }, v.never()) 237 + }, v.never())), 238 238 path: v.optional(v.never()), 239 239 query: v.optional(v.never()) 240 240 }); 241 241 242 242 export const vSessionAlertWebhookRequest = v.object({ 243 - body: v.optional(v.object({ 243 + body: v.optional(v.objectWithRest({ 244 244 event: v.picklist([ 245 245 'session.alert' 246 246 ]), ··· 249 249 v.string(), 250 250 v.bigint() 251 251 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 252 - payload: v.object({ 252 + payload: v.objectWithRest({ 253 253 account_id: v.string(), 254 - object: v.object({ 254 + object: v.objectWithRest({ 255 255 id: v.string(), 256 256 session_id: v.string(), 257 257 session_name: v.string(), ··· 263 263 'High CPU occupation', 264 264 'Call Reconnection' 265 265 ])) 266 - }) 267 - }) 268 - })), 266 + }, v.never()) 267 + }, v.never()) 268 + }, v.never())), 269 269 path: v.optional(v.never()), 270 270 query: v.optional(v.never()) 271 271 }); 272 272 273 273 export const vSessionSharingEndedWebhookRequest = v.object({ 274 - body: v.optional(v.object({ 274 + body: v.optional(v.objectWithRest({ 275 275 event: v.picklist([ 276 276 'session.sharing_ended' 277 277 ]), ··· 280 280 v.string(), 281 281 v.bigint() 282 282 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 283 - payload: v.object({ 283 + payload: v.objectWithRest({ 284 284 account_id: v.string(), 285 - object: v.object({ 285 + object: v.objectWithRest({ 286 286 id: v.string(), 287 287 session_id: v.string(), 288 288 session_name: v.string(), 289 289 session_key: v.optional(v.string()), 290 - user: v.object({ 290 + user: v.objectWithRest({ 291 291 id: v.string(), 292 292 name: v.string(), 293 293 user_key: v.optional(v.string()), 294 - sharing_details: v.object({ 294 + sharing_details: v.objectWithRest({ 295 295 content: v.picklist([ 296 296 'application', 297 297 'whiteboard', ··· 299 299 'unknown' 300 300 ]), 301 301 date_time: v.pipe(v.string(), v.isoTimestamp()) 302 - }) 303 - }) 304 - }) 305 - }) 306 - })), 302 + }, v.never()) 303 + }, v.never()) 304 + }, v.never()) 305 + }, v.never()) 306 + }, v.never())), 307 307 path: v.optional(v.never()), 308 308 query: v.optional(v.never()) 309 309 }); 310 310 311 311 export const vSessionRecordingPausedWebhookRequest = v.object({ 312 - body: v.optional(v.object({ 312 + body: v.optional(v.objectWithRest({ 313 313 event: v.picklist([ 314 314 'session.recording_paused' 315 315 ]), ··· 318 318 v.string(), 319 319 v.bigint() 320 320 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 321 - payload: v.object({ 321 + payload: v.objectWithRest({ 322 322 account_id: v.string(), 323 - object: v.object({ 323 + object: v.objectWithRest({ 324 324 session_id: v.string(), 325 325 session_name: v.string(), 326 326 session_key: v.string(), ··· 330 330 recording_start: v.optional(v.string()), 331 331 recording_end: v.optional(v.string()) 332 332 }) 333 - }) 334 - }) 335 - })), 333 + }, v.never()) 334 + }, v.never()) 335 + }, v.never())), 336 336 path: v.optional(v.never()), 337 337 query: v.optional(v.never()) 338 338 }); 339 339 340 340 export const vSessionEndedWebhookRequest = v.object({ 341 - body: v.optional(v.object({ 341 + body: v.optional(v.objectWithRest({ 342 342 event: v.picklist([ 343 343 'session.ended' 344 344 ]), ··· 347 347 v.string(), 348 348 v.bigint() 349 349 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 350 - payload: v.object({ 350 + payload: v.objectWithRest({ 351 351 account_id: v.string(), 352 - object: v.object({ 352 + object: v.objectWithRest({ 353 353 id: v.string(), 354 354 session_id: v.string(), 355 355 session_name: v.string(), 356 356 session_key: v.optional(v.string()), 357 357 start_time: v.pipe(v.string(), v.isoTimestamp()), 358 358 end_time: v.pipe(v.string(), v.isoTimestamp()) 359 - }) 360 - }) 361 - })), 359 + }, v.never()) 360 + }, v.never()) 361 + }, v.never())), 362 362 path: v.optional(v.never()), 363 363 query: v.optional(v.never()) 364 364 }); 365 365 366 366 export const vSessionStartedWebhookRequest = v.object({ 367 - body: v.optional(v.object({ 367 + body: v.optional(v.objectWithRest({ 368 368 event: v.picklist([ 369 369 'session.started' 370 370 ]), ··· 373 373 v.string(), 374 374 v.bigint() 375 375 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 376 - payload: v.object({ 376 + payload: v.objectWithRest({ 377 377 account_id: v.string(), 378 - object: v.object({ 378 + object: v.objectWithRest({ 379 379 id: v.string(), 380 380 session_id: v.string(), 381 381 session_name: v.string(), 382 382 session_key: v.optional(v.string()), 383 383 start_time: v.pipe(v.string(), v.isoTimestamp()) 384 - }) 385 - }) 386 - })), 384 + }, v.never()) 385 + }, v.never()) 386 + }, v.never())), 387 387 path: v.optional(v.never()), 388 388 query: v.optional(v.never()) 389 389 }); 390 390 391 391 export const vSessionStreamIngestionUnbindWebhookRequest = v.object({ 392 - body: v.optional(v.object({ 392 + body: v.optional(v.objectWithRest({ 393 393 event: v.picklist([ 394 394 'session.stream_ingestion_unbind' 395 395 ]), ··· 398 398 v.string(), 399 399 v.bigint() 400 400 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 401 - payload: v.object({ 401 + payload: v.objectWithRest({ 402 402 account_id: v.string(), 403 - object: v.object({ 403 + object: v.objectWithRest({ 404 404 session_id: v.string(), 405 405 session_name: v.string(), 406 406 session_key: v.optional(v.string()), ··· 412 412 stream_url: v.string(), 413 413 backup_stream_url: v.string() 414 414 }) 415 - }) 416 - }) 417 - })), 415 + }, v.never()) 416 + }, v.never()) 417 + }, v.never())), 418 418 path: v.optional(v.never()), 419 419 query: v.optional(v.never()) 420 420 }); 421 421 422 422 export const vSessionLiveStreamingStartedWebhookRequest = v.object({ 423 - body: v.optional(v.object({ 423 + body: v.optional(v.objectWithRest({ 424 424 event: v.picklist([ 425 425 'session.live_streaming_started' 426 426 ]), ··· 429 429 v.string(), 430 430 v.bigint() 431 431 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 432 - payload: v.object({ 432 + payload: v.objectWithRest({ 433 433 account_id: v.string(), 434 - object: v.object({ 434 + object: v.objectWithRest({ 435 435 id: v.string(), 436 436 session_id: v.string(), 437 437 session_name: v.string(), ··· 452 452 }), 453 453 date_time: v.pipe(v.string(), v.isoTimestamp()) 454 454 }) 455 - }) 456 - }) 457 - })), 455 + }, v.never()) 456 + }, v.never()) 457 + }, v.never())), 458 458 path: v.optional(v.never()), 459 459 query: v.optional(v.never()) 460 460 }); 461 461 462 462 export const vSessionUserRoomSystemCalloutMissedWebhookRequest = v.object({ 463 - body: v.optional(v.object({ 463 + body: v.optional(v.objectWithRest({ 464 464 event: v.string(), 465 465 event_ts: v.pipe(v.union([ 466 466 v.number(), 467 467 v.string(), 468 468 v.bigint() 469 469 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 470 - payload: v.object({ 470 + payload: v.objectWithRest({ 471 471 account_id: v.string(), 472 - object: v.object({ 472 + object: v.objectWithRest({ 473 473 id: v.optional(v.pipe(v.union([ 474 474 v.number(), 475 475 v.string(), ··· 481 481 host_id: v.string(), 482 482 message_id: v.string(), 483 483 inviter_name: v.string(), 484 - participant: v.object({ 484 + participant: v.objectWithRest({ 485 485 call_type: v.string(), 486 486 device_ip: v.string() 487 - }) 488 - }) 489 - }) 490 - })), 487 + }, v.unknown()) 488 + }, v.never()) 489 + }, v.never()) 490 + }, v.never())), 491 491 path: v.optional(v.never()), 492 492 query: v.optional(v.never()) 493 493 }); 494 494 495 495 export const vSessionUserPhoneCalloutAcceptedWebhookRequest = v.object({ 496 - body: v.optional(v.object({ 496 + body: v.optional(v.objectWithRest({ 497 497 event: v.string(), 498 498 event_ts: v.pipe(v.union([ 499 499 v.number(), 500 500 v.string(), 501 501 v.bigint() 502 502 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 503 - payload: v.object({ 503 + payload: v.objectWithRest({ 504 504 account_id: v.string(), 505 - object: v.object({ 505 + object: v.objectWithRest({ 506 506 id: v.optional(v.pipe(v.union([ 507 507 v.number(), 508 508 v.string(), ··· 514 514 session_key: v.string(), 515 515 user_key: v.string(), 516 516 host_id: v.string(), 517 - participant: v.object({ 517 + participant: v.objectWithRest({ 518 518 invitee_name: v.string(), 519 519 phone_number: v.pipe(v.union([ 520 520 v.number(), ··· 526 526 v.string(), 527 527 v.bigint() 528 528 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')) 529 - }) 530 - }) 531 - }) 532 - })), 529 + }, v.never()) 530 + }, v.never()) 531 + }, v.never()) 532 + }, v.never())), 533 533 path: v.optional(v.never()), 534 534 query: v.optional(v.never()) 535 535 }); 536 536 537 537 export const vSessionUserLeftWebhookRequest = v.object({ 538 - body: v.optional(v.object({ 538 + body: v.optional(v.objectWithRest({ 539 539 event: v.picklist([ 540 540 'session.user_left' 541 541 ]), ··· 544 544 v.string(), 545 545 v.bigint() 546 546 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 547 - payload: v.object({ 547 + payload: v.objectWithRest({ 548 548 account_id: v.string(), 549 - object: v.object({ 549 + object: v.objectWithRest({ 550 550 id: v.string(), 551 551 session_id: v.string(), 552 552 session_name: v.string(), 553 553 session_key: v.optional(v.string()), 554 - user: v.object({ 554 + user: v.objectWithRest({ 555 555 id: v.string(), 556 556 name: v.string(), 557 557 leave_time: v.pipe(v.string(), v.isoTimestamp()), ··· 559 559 user_key: v.optional(v.string()), 560 560 phone_number: v.optional(v.string()), 561 561 participant_uuid: v.string() 562 - }) 563 - }) 564 - }) 565 - })), 562 + }, v.never()) 563 + }, v.never()) 564 + }, v.never()) 565 + }, v.never())), 566 566 path: v.optional(v.never()), 567 567 query: v.optional(v.never()) 568 568 }); 569 569 570 570 export const vSessionSharingStartedWebhookRequest = v.object({ 571 - body: v.optional(v.object({ 571 + body: v.optional(v.objectWithRest({ 572 572 event: v.picklist([ 573 573 'session.sharing_started' 574 574 ]), ··· 577 577 v.string(), 578 578 v.bigint() 579 579 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 580 - payload: v.object({ 580 + payload: v.objectWithRest({ 581 581 account_id: v.string(), 582 - object: v.object({ 582 + object: v.objectWithRest({ 583 583 id: v.string(), 584 584 session_id: v.string(), 585 585 session_name: v.string(), 586 586 session_key: v.optional(v.string()), 587 - user: v.object({ 587 + user: v.objectWithRest({ 588 588 id: v.string(), 589 589 name: v.string(), 590 590 user_key: v.optional(v.string()), 591 - sharing_details: v.object({ 591 + sharing_details: v.objectWithRest({ 592 592 content: v.picklist([ 593 593 'application', 594 594 'whiteboard', ··· 596 596 'unknown' 597 597 ]), 598 598 date_time: v.pipe(v.string(), v.isoTimestamp()) 599 - }) 600 - }) 601 - }) 602 - }) 603 - })), 599 + }, v.never()) 600 + }, v.never()) 601 + }, v.never()) 602 + }, v.never()) 603 + }, v.never())), 604 604 path: v.optional(v.never()), 605 605 query: v.optional(v.never()) 606 606 }); 607 607 608 608 export const vSessionUserPhoneCalloutCanceledWebhookRequest = v.object({ 609 - body: v.optional(v.object({ 609 + body: v.optional(v.objectWithRest({ 610 610 event: v.string(), 611 611 event_ts: v.pipe(v.union([ 612 612 v.number(), 613 613 v.string(), 614 614 v.bigint() 615 615 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 616 - payload: v.object({ 616 + payload: v.objectWithRest({ 617 617 account_id: v.string(), 618 - object: v.object({ 618 + object: v.objectWithRest({ 619 619 session_id: v.string(), 620 620 session_name: v.string(), 621 621 session_key: v.string(), 622 622 user_key: v.string(), 623 - participant: v.object({ 623 + participant: v.objectWithRest({ 624 624 invitee_name: v.string(), 625 625 phone_number: v.pipe(v.union([ 626 626 v.number(), ··· 632 632 v.string(), 633 633 v.bigint() 634 634 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')) 635 - }) 636 - }) 637 - }) 638 - })), 635 + }, v.never()) 636 + }, v.never()) 637 + }, v.never()) 638 + }, v.never())), 639 639 path: v.optional(v.never()), 640 640 query: v.optional(v.never()) 641 641 }); 642 642 643 643 export const vSessionRecordingTranscriptCompletedWebhookRequest = v.object({ 644 - body: v.optional(v.object({ 644 + body: v.optional(v.objectWithRest({ 645 645 event: v.picklist([ 646 646 'session.recording_transcript_completed' 647 647 ]), ··· 651 651 v.bigint() 652 652 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 653 653 download_token: v.string(), 654 - payload: v.object({ 654 + payload: v.objectWithRest({ 655 655 account_id: v.string(), 656 - object: v.object({ 656 + object: v.objectWithRest({ 657 657 session_id: v.string(), 658 658 session_name: v.string(), 659 659 session_key: v.string(), ··· 710 710 'chat_message' 711 711 ])) 712 712 })) 713 - }) 714 - }) 715 - })), 713 + }, v.never()) 714 + }, v.never()) 715 + }, v.never())), 716 716 path: v.optional(v.never()), 717 717 query: v.optional(v.never()) 718 718 }); 719 719 720 720 export const vSessionRecordingDeletedWebhookRequest = v.object({ 721 - body: v.optional(v.object({ 721 + body: v.optional(v.objectWithRest({ 722 722 event: v.picklist([ 723 723 'session.recording_deleted' 724 724 ]), ··· 727 727 v.string(), 728 728 v.bigint() 729 729 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 730 - payload: v.object({ 730 + payload: v.objectWithRest({ 731 731 account_id: v.string(), 732 732 operator: v.pipe(v.string(), v.email()), 733 733 operator_id: v.string(), 734 - object: v.object({ 734 + object: v.objectWithRest({ 735 735 session_id: v.string(), 736 736 session_name: v.string(), 737 737 session_key: v.string(), 738 738 start_time: v.pipe(v.string(), v.isoTimestamp()), 739 739 timezone: v.string() 740 - }) 741 - }) 742 - })), 740 + }, v.never()) 741 + }, v.never()) 742 + }, v.never())), 743 743 path: v.optional(v.never()), 744 744 query: v.optional(v.never()) 745 745 }); 746 746 747 747 export const vSessionUserRoomSystemCalloutFailedWebhookRequest = v.object({ 748 - body: v.optional(v.object({ 748 + body: v.optional(v.objectWithRest({ 749 749 event: v.string(), 750 750 event_ts: v.pipe(v.union([ 751 751 v.number(), 752 752 v.string(), 753 753 v.bigint() 754 754 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 755 - payload: v.object({ 755 + payload: v.objectWithRest({ 756 756 account_id: v.string(), 757 - object: v.object({ 757 + object: v.objectWithRest({ 758 758 id: v.optional(v.pipe(v.union([ 759 759 v.number(), 760 760 v.string(), ··· 767 767 message_id: v.string(), 768 768 inviter_name: v.string(), 769 769 reason_type: v.unknown(), 770 - participant: v.object({ 770 + participant: v.objectWithRest({ 771 771 call_type: v.string(), 772 772 device_ip: v.string() 773 - }) 774 - }) 775 - }) 776 - })), 773 + }, v.unknown()) 774 + }, v.never()) 775 + }, v.never()) 776 + }, v.never())), 777 777 path: v.optional(v.never()), 778 778 query: v.optional(v.never()) 779 779 }); 780 780 781 781 export const vSessionRecordingCompletedWebhookRequest = v.object({ 782 - body: v.optional(v.object({ 782 + body: v.optional(v.objectWithRest({ 783 783 event: v.picklist([ 784 784 'session.recording_completed' 785 785 ]), ··· 789 789 v.bigint() 790 790 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 791 791 download_token: v.string(), 792 - payload: v.object({ 792 + payload: v.objectWithRest({ 793 793 account_id: v.string(), 794 - object: v.object({ 794 + object: v.objectWithRest({ 795 795 session_id: v.string(), 796 796 session_name: v.string(), 797 797 session_key: v.string(), ··· 923 923 user_id: v.optional(v.string()), 924 924 user_key: v.optional(v.string()) 925 925 }))) 926 - }) 927 - }) 928 - })), 926 + }, v.never()) 927 + }, v.never()) 928 + }, v.never())), 929 929 path: v.optional(v.never()), 930 930 query: v.optional(v.never()) 931 931 }); 932 932 933 933 export const vSessionRecordingTranscriptFailedWebhookRequest = v.object({ 934 - body: v.optional(v.object({ 934 + body: v.optional(v.objectWithRest({ 935 935 event: v.picklist([ 936 936 'session.recording_transcript_failed' 937 937 ]), ··· 940 940 v.string(), 941 941 v.bigint() 942 942 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 943 - payload: v.object({ 943 + payload: v.objectWithRest({ 944 944 account_id: v.string(), 945 - object: v.object({ 945 + object: v.objectWithRest({ 946 946 session_id: v.string(), 947 947 session_name: v.string(), 948 948 session_key: v.string(), 949 949 start_time: v.pipe(v.string(), v.isoTimestamp()), 950 950 timezone: v.string() 951 - }) 952 - }) 953 - })), 951 + }, v.never()) 952 + }, v.never()) 953 + }, v.never())), 954 954 path: v.optional(v.never()), 955 955 query: v.optional(v.never()) 956 956 }); 957 957 958 958 export const vSessionRecordingTrashedWebhookRequest = v.object({ 959 - body: v.optional(v.object({ 959 + body: v.optional(v.objectWithRest({ 960 960 event: v.picklist([ 961 961 'session.recording_trashed' 962 962 ]), ··· 965 965 v.string(), 966 966 v.bigint() 967 967 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 968 - payload: v.object({ 968 + payload: v.objectWithRest({ 969 969 account_id: v.string(), 970 970 operator: v.pipe(v.string(), v.email()), 971 971 operator_id: v.string(), 972 - object: v.object({ 972 + object: v.objectWithRest({ 973 973 session_id: v.string(), 974 974 session_name: v.string(), 975 975 session_key: v.string(), 976 976 start_time: v.pipe(v.string(), v.isoTimestamp()), 977 977 timezone: v.string() 978 - }) 979 - }) 980 - })), 978 + }, v.never()) 979 + }, v.never()) 980 + }, v.never())), 981 981 path: v.optional(v.never()), 982 982 query: v.optional(v.never()) 983 983 }); 984 984 985 985 export const vSessionUserJoinedWebhookRequest = v.object({ 986 - body: v.optional(v.object({ 986 + body: v.optional(v.objectWithRest({ 987 987 event: v.picklist([ 988 988 'session.user_joined' 989 989 ]), ··· 992 992 v.string(), 993 993 v.bigint() 994 994 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 995 - payload: v.object({ 995 + payload: v.objectWithRest({ 996 996 account_id: v.string(), 997 - object: v.object({ 997 + object: v.objectWithRest({ 998 998 id: v.string(), 999 999 session_id: v.string(), 1000 1000 session_name: v.string(), 1001 1001 session_key: v.optional(v.string()), 1002 - user: v.object({ 1002 + user: v.objectWithRest({ 1003 1003 id: v.string(), 1004 1004 name: v.string(), 1005 1005 join_time: v.pipe(v.string(), v.isoTimestamp()), 1006 1006 user_key: v.optional(v.string()), 1007 1007 phone_number: v.optional(v.string()), 1008 1008 participant_uuid: v.string() 1009 - }) 1010 - }) 1011 - }) 1012 - })), 1009 + }, v.never()) 1010 + }, v.never()) 1011 + }, v.never()) 1012 + }, v.never())), 1013 1013 path: v.optional(v.never()), 1014 1014 query: v.optional(v.never()) 1015 1015 }); 1016 1016 1017 1017 export const vSessionStreamIngestionStartedWebhookRequest = v.object({ 1018 - body: v.optional(v.object({ 1018 + body: v.optional(v.objectWithRest({ 1019 1019 event: v.picklist([ 1020 1020 'session.stream_ingestion_started' 1021 1021 ]), ··· 1024 1024 v.string(), 1025 1025 v.bigint() 1026 1026 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1027 - payload: v.object({ 1027 + payload: v.objectWithRest({ 1028 1028 account_id: v.string(), 1029 - object: v.object({ 1029 + object: v.objectWithRest({ 1030 1030 session_id: v.string(), 1031 1031 session_name: v.string(), 1032 1032 session_key: v.optional(v.string()), ··· 1038 1038 stream_url: v.string(), 1039 1039 backup_stream_url: v.string() 1040 1040 }) 1041 - }) 1042 - }) 1043 - })), 1041 + }, v.never()) 1042 + }, v.never()) 1043 + }, v.never())), 1044 1044 path: v.optional(v.never()), 1045 1045 query: v.optional(v.never()) 1046 1046 }); 1047 1047 1048 1048 export const vSessionStreamIngestionConnectedWebhookRequest = v.object({ 1049 - body: v.optional(v.object({ 1049 + body: v.optional(v.objectWithRest({ 1050 1050 event: v.picklist([ 1051 1051 'session.stream_ingestion_connected' 1052 1052 ]), ··· 1055 1055 v.string(), 1056 1056 v.bigint() 1057 1057 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1058 - payload: v.object({ 1058 + payload: v.objectWithRest({ 1059 1059 account_id: v.string(), 1060 - object: v.object({ 1060 + object: v.objectWithRest({ 1061 1061 session_id: v.string(), 1062 1062 session_name: v.string(), 1063 1063 session_key: v.optional(v.string()), ··· 1069 1069 stream_url: v.string(), 1070 1070 backup_stream_url: v.string() 1071 1071 }) 1072 - }) 1073 - }) 1074 - })), 1072 + }, v.never()) 1073 + }, v.never()) 1074 + }, v.never())), 1075 1075 path: v.optional(v.never()), 1076 1076 query: v.optional(v.never()) 1077 1077 }); 1078 1078 1079 1079 export const vSessionStreamIngestionDisconnectedWebhookRequest = v.object({ 1080 - body: v.optional(v.object({ 1080 + body: v.optional(v.objectWithRest({ 1081 1081 event: v.picklist([ 1082 1082 'session.stream_ingestion_disconnected' 1083 1083 ]), ··· 1086 1086 v.string(), 1087 1087 v.bigint() 1088 1088 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1089 - payload: v.object({ 1089 + payload: v.objectWithRest({ 1090 1090 account_id: v.string(), 1091 - object: v.object({ 1091 + object: v.objectWithRest({ 1092 1092 session_id: v.string(), 1093 1093 session_name: v.string(), 1094 1094 session_key: v.optional(v.string()), ··· 1100 1100 stream_url: v.string(), 1101 1101 backup_stream_url: v.string() 1102 1102 }) 1103 - }) 1104 - }) 1105 - })), 1103 + }, v.never()) 1104 + }, v.never()) 1105 + }, v.never())), 1106 1106 path: v.optional(v.never()), 1107 1107 query: v.optional(v.never()) 1108 1108 }); 1109 1109 1110 1110 export const vSessionRecordingRecoveredWebhookRequest = v.object({ 1111 - body: v.optional(v.object({ 1111 + body: v.optional(v.objectWithRest({ 1112 1112 event: v.picklist([ 1113 1113 'session.recording_recovered' 1114 1114 ]), ··· 1117 1117 v.string(), 1118 1118 v.bigint() 1119 1119 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1120 - payload: v.object({ 1120 + payload: v.objectWithRest({ 1121 1121 account_id: v.string(), 1122 1122 operator: v.pipe(v.string(), v.email()), 1123 1123 operator_id: v.string(), 1124 - object: v.object({ 1124 + object: v.objectWithRest({ 1125 1125 session_id: v.string(), 1126 1126 session_name: v.string(), 1127 1127 session_key: v.string(), 1128 1128 start_time: v.pipe(v.string(), v.isoTimestamp()), 1129 1129 timezone: v.string() 1130 - }) 1131 - }) 1132 - })), 1130 + }, v.never()) 1131 + }, v.never()) 1132 + }, v.never())), 1133 1133 path: v.optional(v.never()), 1134 1134 query: v.optional(v.never()) 1135 1135 }); 1136 1136 1137 1137 export const vSessionUserPhoneCalloutMissedWebhookRequest = v.object({ 1138 - body: v.optional(v.object({ 1138 + body: v.optional(v.objectWithRest({ 1139 1139 event: v.string(), 1140 1140 event_ts: v.pipe(v.union([ 1141 1141 v.number(), 1142 1142 v.string(), 1143 1143 v.bigint() 1144 1144 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1145 - payload: v.object({ 1145 + payload: v.objectWithRest({ 1146 1146 account_id: v.string(), 1147 - object: v.object({ 1147 + object: v.objectWithRest({ 1148 1148 id: v.optional(v.pipe(v.union([ 1149 1149 v.number(), 1150 1150 v.string(), ··· 1156 1156 session_key: v.string(), 1157 1157 user_key: v.string(), 1158 1158 host_id: v.string(), 1159 - participant: v.object({ 1159 + participant: v.objectWithRest({ 1160 1160 invitee_name: v.string(), 1161 1161 phone_number: v.pipe(v.union([ 1162 1162 v.number(), ··· 1168 1168 v.string(), 1169 1169 v.bigint() 1170 1170 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')) 1171 - }) 1172 - }) 1173 - }) 1174 - })), 1171 + }, v.never()) 1172 + }, v.never()) 1173 + }, v.never()) 1174 + }, v.never())), 1175 1175 path: v.optional(v.never()), 1176 1176 query: v.optional(v.never()) 1177 1177 }); 1178 1178 1179 1179 export const vSessionUserPhoneCalloutRejectedWebhookRequest = v.object({ 1180 - body: v.optional(v.object({ 1180 + body: v.optional(v.objectWithRest({ 1181 1181 event: v.string(), 1182 1182 event_ts: v.pipe(v.union([ 1183 1183 v.number(), 1184 1184 v.string(), 1185 1185 v.bigint() 1186 1186 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1187 - payload: v.object({ 1187 + payload: v.objectWithRest({ 1188 1188 account_id: v.string(), 1189 - object: v.object({ 1189 + object: v.objectWithRest({ 1190 1190 id: v.optional(v.pipe(v.union([ 1191 1191 v.number(), 1192 1192 v.string(), ··· 1198 1198 session_key: v.string(), 1199 1199 user_key: v.string(), 1200 1200 host_id: v.string(), 1201 - participant: v.object({ 1201 + participant: v.objectWithRest({ 1202 1202 invitee_name: v.string(), 1203 1203 phone_number: v.pipe(v.union([ 1204 1204 v.number(), ··· 1210 1210 v.string(), 1211 1211 v.bigint() 1212 1212 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')) 1213 - }) 1214 - }) 1215 - }) 1216 - })), 1213 + }, v.never()) 1214 + }, v.never()) 1215 + }, v.never()) 1216 + }, v.never())), 1217 1217 path: v.optional(v.never()), 1218 1218 query: v.optional(v.never()) 1219 1219 }); 1220 1220 1221 1221 export const vSessionUserRoomSystemCalloutAcceptedWebhookRequest = v.object({ 1222 - body: v.optional(v.object({ 1222 + body: v.optional(v.objectWithRest({ 1223 1223 event: v.string(), 1224 1224 event_ts: v.pipe(v.union([ 1225 1225 v.number(), 1226 1226 v.string(), 1227 1227 v.bigint() 1228 1228 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1229 - payload: v.object({ 1229 + payload: v.objectWithRest({ 1230 1230 account_id: v.string(), 1231 - object: v.object({ 1231 + object: v.objectWithRest({ 1232 1232 id: v.optional(v.pipe(v.union([ 1233 1233 v.number(), 1234 1234 v.string(), ··· 1240 1240 host_id: v.string(), 1241 1241 message_id: v.string(), 1242 1242 inviter_name: v.string(), 1243 - participant: v.object({ 1243 + participant: v.objectWithRest({ 1244 1244 call_type: v.string(), 1245 1245 device_ip: v.string() 1246 - }) 1247 - }) 1248 - }) 1249 - })), 1246 + }, v.unknown()) 1247 + }, v.never()) 1248 + }, v.never()) 1249 + }, v.never())), 1250 1250 path: v.optional(v.never()), 1251 1251 query: v.optional(v.never()) 1252 1252 }); 1253 1253 1254 1254 export const vSessionRecordingStoppedWebhookRequest = v.object({ 1255 - body: v.optional(v.object({ 1255 + body: v.optional(v.objectWithRest({ 1256 1256 event: v.picklist([ 1257 1257 'session.recording_stopped' 1258 1258 ]), ··· 1261 1261 v.string(), 1262 1262 v.bigint() 1263 1263 ]), v.transform(x => BigInt(x)), v.minValue(BigInt('-9223372036854775808'), 'Invalid value: Expected int64 to be >= -2^63'), v.maxValue(BigInt('9223372036854775807'), 'Invalid value: Expected int64 to be <= 2^63-1')), 1264 - payload: v.object({ 1264 + payload: v.objectWithRest({ 1265 1265 account_id: v.string(), 1266 - object: v.object({ 1266 + object: v.objectWithRest({ 1267 1267 session_id: v.string(), 1268 1268 session_name: v.string(), 1269 1269 session_key: v.string(), ··· 1273 1273 recording_start: v.optional(v.string()), 1274 1274 recording_end: v.optional(v.string()) 1275 1275 }) 1276 - }) 1277 - }) 1278 - })), 1276 + }, v.never()) 1277 + }, v.never()) 1278 + }, v.never())), 1279 1279 path: v.optional(v.never()), 1280 1280 query: v.optional(v.never()) 1281 1281 });
+65
packages/openapi-ts-tests/main/test/plugins/valibot/spec/objectAdditionalProperties/additional-properties.yaml
··· 1 + openapi: '3.1.0' 2 + info: 3 + title: Object Additional Properties Test API 4 + version: '1.0.0' 5 + paths: {} 6 + components: 7 + schemas: 8 + # Test case from the issue: object with additionalProperties type string 9 + ObjectWithAdditionalPropertiesString: 10 + type: object 11 + properties: 12 + headers: 13 + type: object 14 + additionalProperties: 15 + type: string 16 + 17 + # Object with no properties, only additionalProperties with string type 18 + ObjectOnlyAdditionalPropertiesString: 19 + type: object 20 + additionalProperties: 21 + type: string 22 + 23 + # Object with no properties, only additionalProperties with number type 24 + ObjectOnlyAdditionalPropertiesNumber: 25 + type: object 26 + additionalProperties: 27 + type: number 28 + 29 + # Object with no properties, only additionalProperties with boolean type 30 + ObjectOnlyAdditionalPropertiesBoolean: 31 + type: object 32 + additionalProperties: 33 + type: boolean 34 + 35 + # Object with properties and additionalProperties number 36 + ObjectWithPropertiesAndAdditionalPropertiesNumber: 37 + type: object 38 + properties: 39 + id: 40 + type: string 41 + count: 42 + type: integer 43 + additionalProperties: 44 + type: number 45 + 46 + # Object with additionalProperties as object type 47 + ObjectWithAdditionalPropertiesObject: 48 + type: object 49 + properties: 50 + metadata: 51 + type: object 52 + additionalProperties: 53 + type: object 54 + properties: 55 + value: 56 + type: string 57 + 58 + # Already working case: object with no properties and additionalProperties object 59 + ObjectOnlyAdditionalPropertiesObject: 60 + type: object 61 + additionalProperties: 62 + type: object 63 + properties: 64 + name: 65 + type: string
+250
packages/openapi-ts-tests/main/test/plugins/valibot/test/objectAdditionalProperties/additional-properties.test.ts
··· 1 + import * as v from 'valibot'; 2 + import { beforeAll, describe, expect, it } from 'vitest'; 3 + 4 + import { setupValibotTest } from '../../test-helper'; 5 + 6 + describe('Object Additional Properties Tests', () => { 7 + let generatedSchemas: any; 8 + 9 + beforeAll(async () => { 10 + generatedSchemas = await setupValibotTest(); 11 + }); 12 + 13 + describe('ObjectWithAdditionalPropertiesString', () => { 14 + it('should preserve string additional properties in nested headers object', () => { 15 + const input = { 16 + headers: { 17 + Authorization: 'Bearer token', 18 + 'Content-Type': 'application/json', 19 + }, 20 + }; 21 + const result = v.safeParse( 22 + generatedSchemas.vObjectWithAdditionalPropertiesString, 23 + input, 24 + ); 25 + expect(result.success).toBe(true); 26 + if (result.success) { 27 + expect(result.output.headers).toEqual({ 28 + Authorization: 'Bearer token', 29 + 'Content-Type': 'application/json', 30 + }); 31 + } 32 + }); 33 + 34 + it('should reject non-string values in additional properties', () => { 35 + const input = { 36 + headers: { 37 + Authorization: 'Bearer token', 38 + Count: 123, // Invalid: should be string 39 + }, 40 + }; 41 + const result = v.safeParse( 42 + generatedSchemas.vObjectWithAdditionalPropertiesString, 43 + input, 44 + ); 45 + expect(result.success).toBe(false); 46 + }); 47 + 48 + it('should accept empty headers object', () => { 49 + const input = { 50 + headers: {}, 51 + }; 52 + const result = v.safeParse( 53 + generatedSchemas.vObjectWithAdditionalPropertiesString, 54 + input, 55 + ); 56 + expect(result.success).toBe(true); 57 + }); 58 + }); 59 + 60 + describe('ObjectOnlyAdditionalPropertiesString', () => { 61 + it('should preserve string additional properties', () => { 62 + const input = { 63 + key1: 'value1', 64 + key2: 'value2', 65 + key3: 'value3', 66 + }; 67 + const result = v.safeParse( 68 + generatedSchemas.vObjectOnlyAdditionalPropertiesString, 69 + input, 70 + ); 71 + expect(result.success).toBe(true); 72 + if (result.success) { 73 + expect(result.output).toEqual(input); 74 + } 75 + }); 76 + 77 + it('should reject non-string values', () => { 78 + const input = { 79 + key1: 'value1', 80 + key2: 123, // Invalid: should be string 81 + }; 82 + const result = v.safeParse( 83 + generatedSchemas.vObjectOnlyAdditionalPropertiesString, 84 + input, 85 + ); 86 + expect(result.success).toBe(false); 87 + }); 88 + }); 89 + 90 + describe('ObjectOnlyAdditionalPropertiesNumber', () => { 91 + it('should preserve number additional properties', () => { 92 + const input = { 93 + score1: 100, 94 + score2: 95.5, 95 + score3: 0, 96 + }; 97 + const result = v.safeParse( 98 + generatedSchemas.vObjectOnlyAdditionalPropertiesNumber, 99 + input, 100 + ); 101 + expect(result.success).toBe(true); 102 + if (result.success) { 103 + expect(result.output).toEqual(input); 104 + } 105 + }); 106 + 107 + it('should reject non-number values', () => { 108 + const input = { 109 + score1: 100, 110 + score2: 'invalid', // Invalid: should be number 111 + }; 112 + const result = v.safeParse( 113 + generatedSchemas.vObjectOnlyAdditionalPropertiesNumber, 114 + input, 115 + ); 116 + expect(result.success).toBe(false); 117 + }); 118 + }); 119 + 120 + describe('ObjectOnlyAdditionalPropertiesBoolean', () => { 121 + it('should preserve boolean additional properties', () => { 122 + const input = { 123 + flag1: true, 124 + flag2: false, 125 + flag3: true, 126 + }; 127 + const result = v.safeParse( 128 + generatedSchemas.vObjectOnlyAdditionalPropertiesBoolean, 129 + input, 130 + ); 131 + expect(result.success).toBe(true); 132 + if (result.success) { 133 + expect(result.output).toEqual(input); 134 + } 135 + }); 136 + 137 + it('should reject non-boolean values', () => { 138 + const input = { 139 + flag1: true, 140 + flag2: 'true', // Invalid: should be boolean 141 + }; 142 + const result = v.safeParse( 143 + generatedSchemas.vObjectOnlyAdditionalPropertiesBoolean, 144 + input, 145 + ); 146 + expect(result.success).toBe(false); 147 + }); 148 + }); 149 + 150 + describe('ObjectWithPropertiesAndAdditionalPropertiesNumber', () => { 151 + it('should preserve both named properties and additional properties', () => { 152 + const input = { 153 + count: 42, 154 + extra1: 1.5, 155 + extra2: 2.5, 156 + id: 'abc123', 157 + }; 158 + const result = v.safeParse( 159 + generatedSchemas.vObjectWithPropertiesAndAdditionalPropertiesNumber, 160 + input, 161 + ); 162 + if (!result.success) { 163 + console.log('Validation failed:', result.issues); 164 + } 165 + expect(result.success).toBe(true); 166 + if (result.success) { 167 + expect(result.output).toEqual(input); 168 + } 169 + }); 170 + 171 + it('should validate types of both named and additional properties', () => { 172 + const input = { 173 + count: 42, 174 + extra1: 'invalid', 175 + id: 'abc123', // Invalid: should be number 176 + }; 177 + const result = v.safeParse( 178 + generatedSchemas.vObjectWithPropertiesAndAdditionalPropertiesNumber, 179 + input, 180 + ); 181 + expect(result.success).toBe(false); 182 + }); 183 + 184 + it('should require named properties but allow empty additional properties', () => { 185 + const input = { 186 + count: 42, 187 + id: 'abc123', 188 + }; 189 + const result = v.safeParse( 190 + generatedSchemas.vObjectWithPropertiesAndAdditionalPropertiesNumber, 191 + input, 192 + ); 193 + expect(result.success).toBe(true); 194 + }); 195 + }); 196 + 197 + describe('ObjectWithAdditionalPropertiesObject', () => { 198 + it('should preserve nested object additional properties', () => { 199 + const input = { 200 + metadata: { 201 + field1: { value: 'test1' }, 202 + field2: { value: 'test2' }, 203 + }, 204 + }; 205 + const result = v.safeParse( 206 + generatedSchemas.vObjectWithAdditionalPropertiesObject, 207 + input, 208 + ); 209 + expect(result.success).toBe(true); 210 + if (result.success) { 211 + expect(result.output.metadata).toEqual({ 212 + field1: { value: 'test1' }, 213 + field2: { value: 'test2' }, 214 + }); 215 + } 216 + }); 217 + 218 + it('should validate nested object structure', () => { 219 + const input = { 220 + metadata: { 221 + field1: { value: 'test1' }, 222 + field2: { invalidKey: 'test2' }, // Object without required structure 223 + }, 224 + }; 225 + const result = v.safeParse( 226 + generatedSchemas.vObjectWithAdditionalPropertiesObject, 227 + input, 228 + ); 229 + // Should succeed as the nested object properties are optional 230 + expect(result.success).toBe(true); 231 + }); 232 + }); 233 + 234 + describe('ObjectOnlyAdditionalPropertiesObject', () => { 235 + it('should preserve object additional properties', () => { 236 + const input = { 237 + item1: { name: 'Item 1' }, 238 + item2: { name: 'Item 2' }, 239 + }; 240 + const result = v.safeParse( 241 + generatedSchemas.vObjectOnlyAdditionalPropertiesObject, 242 + input, 243 + ); 244 + expect(result.success).toBe(true); 245 + if (result.success) { 246 + expect(result.output).toEqual(input); 247 + } 248 + }); 249 + }); 250 + });
+32 -10
packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts
··· 72 72 plugin.api.selector('external', 'valibot.v'), 73 73 ); 74 74 75 + // Handle additionalProperties with a schema (not just true/false) 76 + // This supports objects with dynamic keys (e.g., Record<string, T>) 75 77 if ( 76 78 schema.additionalProperties && 77 - schema.additionalProperties.type === 'object' && 78 - !Object.keys(properties).length 79 + typeof schema.additionalProperties === 'object' && 80 + schema.additionalProperties.type !== undefined 79 81 ) { 80 82 const additionalAst = irSchemaToAst({ 81 83 plugin, ··· 88 90 if (additionalAst.hasLazyExpression) { 89 91 result.hasLazyExpression = true; 90 92 } 93 + 94 + // If there are no named properties, use v.record() directly 95 + if (!Object.keys(properties).length) { 96 + result.pipes = [ 97 + tsc.callExpression({ 98 + functionName: tsc.propertyAccessExpression({ 99 + expression: v.placeholder, 100 + name: identifiers.schemas.record, 101 + }), 102 + parameters: [ 103 + tsc.callExpression({ 104 + functionName: tsc.propertyAccessExpression({ 105 + expression: v.placeholder, 106 + name: identifiers.schemas.string, 107 + }), 108 + parameters: [], 109 + }), 110 + pipesToAst({ pipes: additionalAst.pipes, plugin }), 111 + ], 112 + }), 113 + ]; 114 + return result as Omit<Ast, 'typeName'>; 115 + } 116 + 117 + // If there are named properties, use v.objectWithRest() to validate both 118 + // The rest parameter is the schema for each additional property value 91 119 result.pipes = [ 92 120 tsc.callExpression({ 93 121 functionName: tsc.propertyAccessExpression({ 94 122 expression: v.placeholder, 95 - name: identifiers.schemas.record, 123 + name: identifiers.schemas.objectWithRest, 96 124 }), 97 125 parameters: [ 98 - tsc.callExpression({ 99 - functionName: tsc.propertyAccessExpression({ 100 - expression: v.placeholder, 101 - name: identifiers.schemas.string, 102 - }), 103 - parameters: [], 104 - }), 126 + ts.factory.createObjectLiteralExpression(properties, true), 105 127 pipesToAst({ pipes: additionalAst.pipes, plugin }), 106 128 ], 107 129 }),