diff --git a/docs-yml.schema.json b/docs-yml.schema.json index 71f6196be064..61b49185dc54 100644 --- a/docs-yml.schema.json +++ b/docs-yml.schema.json @@ -198,6 +198,19 @@ } ] }, + "translations": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/definitions/docs.TranslationConfig" + } + }, + { + "type": "null" + } + ] + }, "ai-chat": { "oneOf": [ { @@ -4265,6 +4278,28 @@ "tr" ] }, + "docs.TranslationConfig": { + "type": "object", + "properties": { + "lang": { + "$ref": "#/definitions/docs.Language" + }, + "default": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "lang" + ], + "additionalProperties": false + }, "docs.AIChatModel": { "type": "string", "enum": [ diff --git a/fern/apis/docs-yml/definition/docs.yml b/fern/apis/docs-yml/definition/docs.yml index 27c883b06d0a..e4d1c0fe10de 100644 --- a/fern/apis/docs-yml/definition/docs.yml +++ b/fern/apis/docs-yml/definition/docs.yml @@ -42,6 +42,13 @@ types: - sv - tr + TranslationConfig: + properties: + lang: Language + default: + type: optional + docs: Whether this language is the default. At most one entry should be marked as default. + AnalyticsConfig: properties: segment: optional @@ -273,6 +280,22 @@ types: languages: optional> + translations: + type: optional> + docs: | + Configuration for multi-language documentation. Each entry defines a locale + that the documentation supports. Use the `translations/` directory alongside + `docs.yml` to provide per-language content. + + Example: + ```yaml + translations: + - lang: en + default: true + - lang: ja + - lang: fr + ``` + # Deprecated "ai-chat": optional diff --git a/generators/go-v2/base/package.json b/generators/go-v2/base/package.json index d3590c621934..97bddfd1ccc2 100644 --- a/generators/go-v2/base/package.json +++ b/generators/go-v2/base/package.json @@ -43,7 +43,7 @@ "@fern-api/go-ast": "workspace:*", "@fern-api/logging-execa": "workspace:*", "@fern-fern/generator-exec-sdk": "catalog:", - "@fern-fern/ir-sdk": "66.0.0", + "@fern-fern/ir-sdk": "66.3.0", "@types/node": "catalog:", "dedent": "catalog:", "typescript": "catalog:", diff --git a/generators/go-v2/model/package.json b/generators/go-v2/model/package.json index 0a629702df01..a683980e3401 100644 --- a/generators/go-v2/model/package.json +++ b/generators/go-v2/model/package.json @@ -45,7 +45,7 @@ "@fern-api/fs-utils": "workspace:*", "@fern-api/go-ast": "workspace:*", "@fern-api/go-base": "workspace:*", - "@fern-fern/ir-sdk": "66.0.0", + "@fern-fern/ir-sdk": "66.3.0", "@types/node": "catalog:", "typescript": "catalog:", "vitest": "catalog:" diff --git a/generators/go-v2/sdk/package.json b/generators/go-v2/sdk/package.json index 3a9cb93ede35..0644583bd6fa 100644 --- a/generators/go-v2/sdk/package.json +++ b/generators/go-v2/sdk/package.json @@ -42,6 +42,7 @@ "@fern-api/base-generator": "workspace:*", "@fern-api/configs": "workspace:*", "@fern-api/core-utils": "workspace:*", + "@fern-api/dynamic-ir-sdk": "66.1.0", "@fern-api/fs-utils": "workspace:*", "@fern-api/go-ast": "workspace:*", "@fern-api/go-base": "workspace:*", @@ -50,11 +51,10 @@ "@fern-api/mock-utils": "workspace:*", "@fern-fern/generator-cli-sdk": "^0.1.5", "@fern-fern/generator-exec-sdk": "catalog:", - "@fern-fern/ir-sdk": "66.0.0", + "@fern-fern/ir-sdk": "66.3.0", "@types/node": "catalog:", "dedent": "catalog:", "typescript": "catalog:", - "vitest": "catalog:", - "@fern-api/dynamic-ir-sdk": "66.1.0" + "vitest": "catalog:" } } diff --git a/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts b/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts index b5aa77e6c5aa..b8fa87dab20d 100644 --- a/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts +++ b/generators/go-v2/sdk/src/readme/ReadmeSnippetBuilder.ts @@ -179,7 +179,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { return this.writeCode(dedent` // Specify default options applied on every request. ${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient( - option.WithToken(""), + option.WithToken("${this.getTokenPlaceholder()}"), option.WithHTTPClient( &http.Client{ Timeout: 5 * time.Second, @@ -190,7 +190,7 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { // Specify options for an individual request. response, err := ${this.getMethodCall(endpoint)}( ..., - option.WithToken(""), + option.WithToken("${this.getTokenPlaceholder()}"), ) `); } @@ -303,6 +303,28 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { `); } + private getTokenPlaceholder({ defaultValue = "" }: { defaultValue?: string } = {}): string { + if (this.context.ir.auth != null) { + for (const scheme of this.context.ir.auth.schemes) { + if (scheme.type === "bearer" && scheme.tokenPlaceholder != null) { + return scheme.tokenPlaceholder; + } + if (scheme.type === "header" && scheme.headerPlaceholder != null) { + return scheme.headerPlaceholder; + } + } + } + return defaultValue; + } + + private getOAuthClientIdPlaceholder(): string { + return ""; + } + + private getOAuthClientSecretPlaceholder(): string { + return ""; + } + private hasOAuthScheme(): boolean { if (this.context.ir.auth == null) { return false; @@ -315,14 +337,14 @@ export class ReadmeSnippetBuilder extends AbstractReadmeSnippetBuilder { // Option 1: Use client credentials (SDK will handle token fetching and refresh) ${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient( option.WithClientCredentials( - "", - "", + "${this.getOAuthClientIdPlaceholder()}", + "${this.getOAuthClientSecretPlaceholder()}", ), ) // Option 2: Use a pre-fetched token directly ${ReadmeSnippetBuilder.CLIENT_VARIABLE_NAME} := ${this.rootPackageClientName}.NewClient( - option.WithToken(""), + option.WithToken("${this.getTokenPlaceholder({ defaultValue: "" })}"), ) `); } diff --git a/generators/go-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts b/generators/go-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts index fedaf1d7ca8f..9047860fdda6 100644 --- a/generators/go-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts +++ b/generators/go-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts @@ -26,7 +26,9 @@ export class WireTestSetupGenerator { } public static getWiremockConfigContent(ir: FernIr.IntermediateRepresentation) { - return new WireMock().convertToWireMock(ir); + // ir-sdk versions may differ between go-sdk (66.3.0) and mock-utils (66.0.0); + // 66.3.0 is a strict superset (adds optional fields only), so this is safe. + return new WireMock().convertToWireMock(ir as Parameters[0]); } private generateWireMockConfigFile(): void { diff --git a/generators/go/sdk/changes/1.38.0/feat-auth-placeholder-snippets.yml b/generators/go/sdk/changes/1.38.0/feat-auth-placeholder-snippets.yml new file mode 100644 index 000000000000..e0b14c96920f --- /dev/null +++ b/generators/go/sdk/changes/1.38.0/feat-auth-placeholder-snippets.yml @@ -0,0 +1,4 @@ +- summary: | + Use auth scheme placeholder values in README snippets when configured via + `placeholder` field on auth schemes. + type: feat diff --git a/generators/go/sdk/versions.yml b/generators/go/sdk/versions.yml index 0fbaa8ecba58..c7a0c78daaf6 100644 --- a/generators/go/sdk/versions.yml +++ b/generators/go/sdk/versions.yml @@ -1,4 +1,12 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 1.38.0 + changelogEntry: + - summary: | + Use auth scheme placeholder values in README snippets when configured via + `placeholder` field on auth schemes. + type: feat + createdAt: "2026-04-27" + irVersion: 66 - version: 1.37.0 changelogEntry: - summary: | diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java index 19d08c495202..392b97ff6da9 100644 --- a/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/UndiscriminatedUnionGenerator.java @@ -29,6 +29,8 @@ import com.fern.ir.model.types.ContainerType; import com.fern.ir.model.types.DeclaredTypeName; import com.fern.ir.model.types.Literal; +import com.fern.ir.model.types.ObjectProperty; +import com.fern.ir.model.types.ObjectTypeDeclaration; import com.fern.ir.model.types.PrimitiveType; import com.fern.ir.model.types.PrimitiveTypeV1; import com.fern.ir.model.types.TypeDeclaration; @@ -54,6 +56,7 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeVariableName; +import com.squareup.javapoet.WildcardTypeName; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -604,6 +607,28 @@ private TypeSpec getDeserializer() { if (typeName.isPrimitive() || typeName.isBoxedPrimitive()) { continue; } + List requiredKeys = getRequiredWireKeys(member); + boolean hasRequiredKeyGuard = !requiredKeys.isEmpty(); + if (hasRequiredKeyGuard) { + ParameterizedTypeName mapWildcard = ParameterizedTypeName.get( + ClassName.get(Map.class), + WildcardTypeName.subtypeOf(Object.class), + WildcardTypeName.subtypeOf(Object.class)); + StringBuilder guard = new StringBuilder(); + guard.append("$L instanceof $T"); + for (String key : requiredKeys) { + guard.append(" && (($T) $L).containsKey($S)"); + } + List guardArgs = new ArrayList<>(); + guardArgs.add(VALUE_FIELD_SPEC.name); + guardArgs.add(mapWildcard); + for (String key : requiredKeys) { + guardArgs.add(mapWildcard); + guardArgs.add(VALUE_FIELD_SPEC.name); + guardArgs.add(key); + } + deserializeMethod.beginControlFlow("if (" + guard.toString() + ")", guardArgs.toArray()); + } if (shouldDeserializeWithTypeReference(member)) { deserializeMethod .beginControlFlow("try") @@ -629,6 +654,9 @@ private TypeSpec getDeserializer() { .nextControlFlow("catch($T e)", RuntimeException.class) .endControlFlow(); } + if (hasRequiredKeyGuard) { + deserializeMethod.endControlFlow(); + } } deserializeMethod.addStatement("throw new $T(p, $S)", JsonParseException.class, "Failed to deserialize"); return deserializerBuilder.addMethod(deserializeMethod.build()).build(); @@ -659,6 +687,76 @@ private boolean shouldDeserializeWithTypeReference(UndiscriminatedUnionMember me return false; } + /** + * Returns the wire keys of all required (non-optional, non-nullable, non-literal) properties for an object-typed + * union member. Returns an empty list for non-object members. This is used to emit key-presence guards in the + * deserializer so that trial-order deserialization doesn't misclassify payloads when the Jackson builder silently + * accepts missing fields. + */ + private List getRequiredWireKeys(UndiscriminatedUnionMember member) { + if (!member.getType().isNamed()) { + return Collections.emptyList(); + } + TypeId typeId = member.getType().getNamed().get().getTypeId(); + // Walk alias chains until we hit a non-alias type declaration. Guards against alias cycles + // with a visited-set keyed by TypeId. + Set visited = new HashSet<>(); + while (typeId != null && visited.add(typeId)) { + TypeDeclaration typeDeclaration = + generatorContext.getTypeDeclarations().get(typeId); + if (typeDeclaration == null) { + return Collections.emptyList(); + } + if (typeDeclaration.getShape().isObject()) { + ObjectTypeDeclaration objectType = + typeDeclaration.getShape().getObject().get(); + List requiredKeys = new ArrayList<>(); + collectRequiredWireKeys(objectType, requiredKeys); + return requiredKeys; + } + if (!typeDeclaration.getShape().isAlias()) { + // Enum / union / undiscriminated union / etc. — convertValue will reject a JSON + // object naturally for these, so no presence guard is needed. + return Collections.emptyList(); + } + com.fern.ir.model.types.ResolvedTypeReference resolved = + typeDeclaration.getShape().getAlias().get().getResolvedType(); + if (!resolved.isNamed()) { + // Resolved to primitive / container / unknown — not an object shape. + return Collections.emptyList(); + } + typeId = resolved.getNamed().get().getName().getTypeId(); + } + return Collections.emptyList(); + } + + private void collectRequiredWireKeys(ObjectTypeDeclaration objectType, List requiredKeys) { + for (ObjectProperty property : objectType.getProperties()) { + if (isRequiredProperty(property)) { + requiredKeys.add(NameUtils.getWireValue(property.getName())); + } + } + // Include required properties from extended types + for (DeclaredTypeName extendedType : objectType.getExtends()) { + TypeDeclaration extDeclaration = + generatorContext.getTypeDeclarations().get(extendedType.getTypeId()); + if (extDeclaration != null && extDeclaration.getShape().isObject()) { + collectRequiredWireKeys(extDeclaration.getShape().getObject().get(), requiredKeys); + } + } + } + + private static boolean isRequiredProperty(ObjectProperty property) { + com.fern.ir.model.types.TypeReference valueType = property.getValueType(); + if (valueType.isContainer()) { + ContainerType container = valueType.getContainer().get(); + if (container.isOptional() || container.isNullable() || container.isLiteral()) { + return false; + } + } + return true; + } + private static String visitorName(Set reservedTypeNames) { return reservedTypeNames.contains(VISITOR_CLASS_NAME) ? VISITOR_CLASS_NAME_UNDERSCORE : VISITOR_CLASS_NAME; } diff --git a/generators/java/generator-utils/src/main/java/com/fern/java/generators/tests/UndiscriminatedUnionDeserializationTestGenerator.java b/generators/java/generator-utils/src/main/java/com/fern/java/generators/tests/UndiscriminatedUnionDeserializationTestGenerator.java new file mode 100644 index 000000000000..ce3fc8fa987b --- /dev/null +++ b/generators/java/generator-utils/src/main/java/com/fern/java/generators/tests/UndiscriminatedUnionDeserializationTestGenerator.java @@ -0,0 +1,420 @@ +/* + * (c) Copyright 2023 Birch Solutions Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.fern.java.generators.tests; + +import com.fern.ir.model.commons.TypeId; +import com.fern.ir.model.types.ContainerType; +import com.fern.ir.model.types.DeclaredTypeName; +import com.fern.ir.model.types.ObjectProperty; +import com.fern.ir.model.types.ObjectTypeDeclaration; +import com.fern.ir.model.types.PrimitiveTypeV1; +import com.fern.ir.model.types.TypeDeclaration; +import com.fern.ir.model.types.UndiscriminatedUnionMember; +import com.fern.ir.model.types.UndiscriminatedUnionTypeDeclaration; +import com.fern.java.AbstractGeneratorContext; +import com.fern.java.generators.AbstractFileGenerator; +import com.fern.java.output.GeneratedJavaFile; +import com.fern.java.utils.NameUtils; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import javax.lang.model.element.Modifier; + +public final class UndiscriminatedUnionDeserializationTestGenerator extends AbstractFileGenerator { + + private static final String TEST_CLASS_NAME = "UndiscriminatedUnionTest"; + + public UndiscriminatedUnionDeserializationTestGenerator(AbstractGeneratorContext generatorContext) { + super( + ClassName.get(generatorContext.getPoetClassNameFactory().getRootPackage(), TEST_CLASS_NAME), + generatorContext); + } + + @Override + public GeneratedJavaFile generateFile() { + ClassName testAnnotation = ClassName.get("org.junit.jupiter.api", "Test"); + ClassName objectMappersClassName = + generatorContext.getPoetClassNameFactory().getObjectMapperClassName(); + + List testMethods = new ArrayList<>(); + + for (Map.Entry entry : + generatorContext.getTypeDeclarations().entrySet()) { + TypeDeclaration typeDeclaration = entry.getValue(); + if (!typeDeclaration.getShape().isUndiscriminatedUnion()) { + continue; + } + UndiscriminatedUnionTypeDeclaration union = + typeDeclaration.getShape().getUndiscriminatedUnion().get(); + ClassName unionClassName = + generatorContext.getPoetClassNameFactory().getTypeClassName(typeDeclaration.getName()); + + List testableVariants = getTestableVariants(union); + if (testableVariants.size() < 2) { + continue; + } + + for (TestableVariant variant : testableVariants) { + Optional method = buildTestMethod( + testAnnotation, objectMappersClassName, unionClassName, variant, testableVariants); + method.ifPresent(testMethods::add); + } + } + + TypeSpec.Builder testClassBuilder = + TypeSpec.classBuilder(TEST_CLASS_NAME).addModifiers(Modifier.PUBLIC, Modifier.FINAL); + + for (MethodSpec method : testMethods) { + testClassBuilder.addMethod(method); + } + + TypeSpec testTypeSpec = testClassBuilder.build(); + JavaFile testFile = JavaFile.builder(className.packageName(), testTypeSpec) + .addStaticImport(ClassName.get("org.junit.jupiter.api", "Assertions"), "*") + .build(); + + return GeneratedJavaFile.builder() + .className(className) + .javaFile(testFile) + .testFile(true) + .build(); + } + + public boolean hasTests() { + for (Map.Entry entry : + generatorContext.getTypeDeclarations().entrySet()) { + TypeDeclaration typeDeclaration = entry.getValue(); + if (!typeDeclaration.getShape().isUndiscriminatedUnion()) { + continue; + } + UndiscriminatedUnionTypeDeclaration union = + typeDeclaration.getShape().getUndiscriminatedUnion().get(); + if (getTestableVariants(union).size() >= 2) { + return true; + } + } + return false; + } + + private Optional buildTestMethod( + ClassName testAnnotation, + ClassName objectMappersClassName, + ClassName unionClassName, + TestableVariant variant, + List allVariants) { + + // Only generate a test when every earlier variant's guard will fail for this variant's payload. + // A guard fails when the payload is missing at least one of that variant's required keys. + boolean isDistinguishable = true; + for (TestableVariant other : allVariants) { + if (other == variant) { + break; + } + if (variant.requiredKeys.containsAll(other.requiredKeys)) { + isDistinguishable = false; + break; + } + } + if (!isDistinguishable) { + return Optional.empty(); + } + + String methodName = "test" + unionClassName.simpleName() + "_" + variant.variantClassName.simpleName(); + + MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName) + .addAnnotation(testAnnotation) + .addModifiers(Modifier.PUBLIC) + .addException(Exception.class); + + // Build JSON string with required keys + StringBuilder jsonBuilder = new StringBuilder("{"); + boolean first = true; + for (Map.Entry keyValue : variant.jsonKeyValues.entrySet()) { + if (!first) { + jsonBuilder.append(","); + } + jsonBuilder.append("\\\"").append(keyValue.getKey()).append("\\\":"); + jsonBuilder.append(keyValue.getValue()); + first = false; + } + jsonBuilder.append("}"); + + builder.addStatement( + "$T json = $S", + ClassName.get(String.class), + jsonBuilder.toString().replace("\\\"", "\"")); + builder.addStatement( + "$T union = $T.JSON_MAPPER.readValue(json, $T.class)", + unionClassName, + objectMappersClassName, + unionClassName); + builder.addStatement( + "assertTrue(union.get() instanceof $T, $S)", + variant.variantClassName, + "Expected " + variant.variantClassName.simpleName() + " but got different variant"); + + return Optional.of(builder.build()); + } + + private List getTestableVariants(UndiscriminatedUnionTypeDeclaration union) { + List variants = new ArrayList<>(); + for (UndiscriminatedUnionMember member : union.getMembers()) { + if (!member.getType().isNamed()) { + continue; + } + // Walk alias chains until we land on an object declaration (or bail). + // Use the resolved object declaration's name for variantClassName because + // when wrappedAliases is false (the default), alias types have no generated class. + TypeDeclaration objectDeclaration = + resolveToObjectDeclaration(member.getType().getNamed().get().getTypeId()); + if (objectDeclaration == null) { + continue; + } + ObjectTypeDeclaration objectType = + objectDeclaration.getShape().getObject().get(); + Map jsonKeyValues = new LinkedHashMap<>(); + Set requiredKeys = new LinkedHashSet<>(); + if (!collectRequiredJsonKeyValues(objectType, jsonKeyValues, requiredKeys)) { + continue; + } + if (requiredKeys.isEmpty()) { + continue; + } + ClassName variantClassName = + generatorContext.getPoetClassNameFactory().getTypeClassName(objectDeclaration.getName()); + variants.add(new TestableVariant(variantClassName, requiredKeys, jsonKeyValues)); + } + return variants; + } + + /** + * Walks alias chains starting at {@code typeId}, returning the first object-shaped declaration encountered. Returns + * {@code null} if the chain ends in a non-object shape (primitive, container, enum, union, etc.). Guards against + * alias cycles with a visited-set on TypeId. + */ + private TypeDeclaration resolveToObjectDeclaration(TypeId typeId) { + Set visited = new LinkedHashSet<>(); + while (typeId != null && visited.add(typeId)) { + TypeDeclaration typeDeclaration = + generatorContext.getTypeDeclarations().get(typeId); + if (typeDeclaration == null) { + return null; + } + if (typeDeclaration.getShape().isObject()) { + return typeDeclaration; + } + if (!typeDeclaration.getShape().isAlias()) { + return null; + } + com.fern.ir.model.types.ResolvedTypeReference resolved = + typeDeclaration.getShape().getAlias().get().getResolvedType(); + if (!resolved.isNamed()) { + return null; + } + typeId = resolved.getNamed().get().getName().getTypeId(); + } + return null; + } + + /** + * Collects required wire keys and their JSON test values. Returns false if any required property has a type we + * cannot generate a safe test value for. + */ + private boolean collectRequiredJsonKeyValues( + ObjectTypeDeclaration objectType, Map jsonKeyValues, Set requiredKeys) { + for (ObjectProperty property : objectType.getProperties()) { + if (!isRequiredProperty(property)) { + continue; + } + String wireKey = NameUtils.getWireValue(property.getName()); + String jsonValue = getJsonTestValue(property.getValueType()); + if (jsonValue == null) { + return false; + } + jsonKeyValues.put(wireKey, jsonValue); + requiredKeys.add(wireKey); + } + for (DeclaredTypeName extendedType : objectType.getExtends()) { + TypeDeclaration extDeclaration = + generatorContext.getTypeDeclarations().get(extendedType.getTypeId()); + if (extDeclaration != null && extDeclaration.getShape().isObject()) { + if (!collectRequiredJsonKeyValues( + extDeclaration.getShape().getObject().get(), jsonKeyValues, requiredKeys)) { + return false; + } + } + } + return true; + } + + private static boolean isRequiredProperty(ObjectProperty property) { + com.fern.ir.model.types.TypeReference valueType = property.getValueType(); + if (valueType.isContainer()) { + ContainerType container = valueType.getContainer().get(); + if (container.isOptional() || container.isNullable() || container.isLiteral()) { + return false; + } + } + return true; + } + + private String getJsonTestValue(com.fern.ir.model.types.TypeReference typeRef) { + if (typeRef.isPrimitive()) { + return typeRef.getPrimitive().get().getV1().visit(new PrimitiveJsonValueVisitor()); + } + if (typeRef.isContainer()) { + ContainerType container = typeRef.getContainer().get(); + if (container.isList() || container.isSet()) { + return "[]"; + } + if (container.isMap()) { + return "{}"; + } + return null; + } + if (typeRef.isNamed()) { + TypeId typeId = typeRef.getNamed().get().getTypeId(); + TypeDeclaration decl = generatorContext.getTypeDeclarations().get(typeId); + if (decl != null && decl.getShape().isObject()) { + return "{}"; + } + if (decl != null && decl.getShape().isAlias()) { + com.fern.ir.model.types.ResolvedTypeReference resolved = + decl.getShape().getAlias().get().getResolvedType(); + if (resolved.isPrimitive()) { + return resolved.getPrimitive().get().getV1().visit(new PrimitiveJsonValueVisitor()); + } + if (resolved.isContainer()) { + ContainerType container = resolved.getContainer().get(); + if (container.isList() || container.isSet()) { + return "[]"; + } + if (container.isMap()) { + return "{}"; + } + } + if (resolved.isUnknown()) { + return "{}"; + } + return null; + } + // Enums, unions, etc. are complex — skip + return null; + } + if (typeRef.isUnknown()) { + return "{}"; + } + return null; + } + + private static final class PrimitiveJsonValueVisitor implements PrimitiveTypeV1.Visitor { + @Override + public String visitInteger() { + return "1"; + } + + @Override + public String visitDouble() { + return "1.1"; + } + + @Override + public String visitString() { + return "\"test\""; + } + + @Override + public String visitBoolean() { + return "true"; + } + + @Override + public String visitLong() { + return "1"; + } + + @Override + public String visitDateTime() { + return "\"2024-01-01T00:00:00Z\""; + } + + @Override + public String visitDate() { + return "\"2024-01-01\""; + } + + @Override + public String visitUuid() { + return "\"d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32\""; + } + + @Override + public String visitBase64() { + return "\"dGVzdA==\""; + } + + @Override + public String visitBigInteger() { + return "\"1\""; + } + + @Override + public String visitUint() { + return "1"; + } + + @Override + public String visitUint64() { + return "1"; + } + + @Override + public String visitFloat() { + return "1.1"; + } + + @Override + public String visitDateTimeRfc2822() { + return "\"Sat, 01 Jan 2024 00:00:00 +0000\""; + } + + @Override + public String visitUnknown(String unknownType) { + return null; + } + } + + private static final class TestableVariant { + final ClassName variantClassName; + final Set requiredKeys; + final Map jsonKeyValues; + + TestableVariant(ClassName variantClassName, Set requiredKeys, Map jsonKeyValues) { + this.variantClassName = variantClassName; + this.requiredKeys = requiredKeys; + this.jsonKeyValues = jsonKeyValues; + } + } +} diff --git a/generators/java/sdk/changes/4.6.1/fix-undiscriminated-union-deserialization.yml b/generators/java/sdk/changes/4.6.1/fix-undiscriminated-union-deserialization.yml new file mode 100644 index 000000000000..6b6ec4618b95 --- /dev/null +++ b/generators/java/sdk/changes/4.6.1/fix-undiscriminated-union-deserialization.yml @@ -0,0 +1,7 @@ +- summary: | + Fix undiscriminated union deserializer misclassifying payloads. The generated + deserializer now checks that all required wire keys are present in the JSON + object before attempting to convert to each variant, preventing the first + variant from always winning when Jackson's builder silently accepts missing + required fields. + type: fix diff --git a/generators/java/sdk/changes/4.6.1/fix-websocket-dispatch.yml b/generators/java/sdk/changes/4.6.1/fix-websocket-dispatch.yml new file mode 100644 index 000000000000..15e40d3c2168 --- /dev/null +++ b/generators/java/sdk/changes/4.6.1/fix-websocket-dispatch.yml @@ -0,0 +1,7 @@ +- summary: | + Replace switch-on-type WebSocket message dispatch with shape-based trial + deserialization. Messages are now matched by checking required-field presence + and literal values before attempting Jackson conversion. This correctly handles + AsyncAPI channels where multiple message schemas share the same discriminator + value (e.g., two "History" variants with disjoint required fields). + type: fix diff --git a/generators/java/sdk/src/main/java/com/fern/java/client/Cli.java b/generators/java/sdk/src/main/java/com/fern/java/client/Cli.java index 0ff25428c861..6fab66a75250 100644 --- a/generators/java/sdk/src/main/java/com/fern/java/client/Cli.java +++ b/generators/java/sdk/src/main/java/com/fern/java/client/Cli.java @@ -84,6 +84,7 @@ import com.fern.java.generators.TypesGenerator.Result; import com.fern.java.generators.WrappedAliasGenerator; import com.fern.java.generators.tests.QueryStringMapperTestGenerator; +import com.fern.java.generators.tests.UndiscriminatedUnionDeserializationTestGenerator; import com.fern.java.output.GeneratedFile; import com.fern.java.output.GeneratedJavaFile; import com.fern.java.output.GeneratedObjectMapper; @@ -833,6 +834,11 @@ private void runInProjectModeHook( this.addGeneratedFile(testGenerator.generateFile()); StreamTestGenerator streamTestGenerator = new StreamTestGenerator(context); this.addGeneratedFile(streamTestGenerator.generateFile()); + UndiscriminatedUnionDeserializationTestGenerator unionDeserializationTestGenerator = + new UndiscriminatedUnionDeserializationTestGenerator(context); + if (unionDeserializationTestGenerator.hasTests()) { + this.addGeneratedFile(unionDeserializationTestGenerator.generateFile()); + } // Generate wire tests if enabled if (customConfig.enableWireTests()) { diff --git a/generators/java/sdk/src/main/java/com/fern/java/client/generators/websocket/AbstractWebSocketChannelWriter.java b/generators/java/sdk/src/main/java/com/fern/java/client/generators/websocket/AbstractWebSocketChannelWriter.java index a0b651a9aae9..9267a16af58d 100644 --- a/generators/java/sdk/src/main/java/com/fern/java/client/generators/websocket/AbstractWebSocketChannelWriter.java +++ b/generators/java/sdk/src/main/java/com/fern/java/client/generators/websocket/AbstractWebSocketChannelWriter.java @@ -21,6 +21,7 @@ import com.fern.ir.model.http.PathParameter; import com.fern.ir.model.ir.Subpackage; import com.fern.ir.model.types.ContainerType; +import com.fern.ir.model.types.DeclaredTypeName; import com.fern.ir.model.types.EnumValue; import com.fern.ir.model.types.Literal; import com.fern.ir.model.types.ObjectProperty; @@ -51,7 +52,12 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -103,6 +109,11 @@ public abstract class AbstractWebSocketChannelWriter { private static final String DISCRIMINANT_FIELD = "type"; + // Wire discriminant values shared by more than one server message. + // When a collision exists, handler/method names fall back to the message type ID + // instead of the wire discriminant value to avoid duplicate field declarations. + private final Set collidingDiscriminantValues; + // Connect options class name (present when channel has query parameters) protected final Optional connectOptionsClassName; @@ -193,6 +204,21 @@ public AbstractWebSocketChannelWriter( this.reconnectOptionsField = FieldSpec.builder( reconnectOptionsClassName, "reconnectOptions", Modifier.PRIVATE, Modifier.VOLATILE) .build(); + + // Detect wire discriminant value collisions among server messages + Map discriminantCounts = new HashMap<>(); + for (WebSocketMessage message : websocketChannel.getMessages()) { + if (message.getOrigin() == WebSocketMessageOrigin.SERVER) { + String wireValue = getWireDiscriminantValue(message); + discriminantCounts.merge(wireValue, 1, Integer::sum); + } + } + this.collidingDiscriminantValues = new HashSet<>(); + for (Map.Entry entry : discriminantCounts.entrySet()) { + if (entry.getValue() > 1) { + this.collidingDiscriminantValues.add(entry.getKey()); + } + } } public GeneratedJavaFile generateFile() { @@ -420,12 +446,18 @@ protected java.util.List getBinaryServerMessageHandlerFieldNames() { return result; } + /** + * Generates the handleIncomingMessage method that dispatches incoming WebSocket frames using shape-based trial + * deserialization. Instead of switching on a single "type" field, each message schema's required keys and literal + * values are checked against the JSON payload. Messages are tried in order of specificity (most constraints first) + * so that more specific schemas match before less specific ones. + */ protected MethodSpec generateHandleIncomingMessageHelper() { MethodSpec.Builder builder = MethodSpec.methodBuilder("handleIncomingMessage") .addModifiers(Modifier.PRIVATE) .addParameter(String.class, "json") .beginControlFlow("try") - // Fire generic onMessage handler before type dispatch + // Fire generic onMessage handler before dispatch .beginControlFlow("if ($N != null)", onMessageHandlerField) .addStatement("$N.accept(json)", onMessageHandlerField) .endControlFlow() @@ -436,67 +468,289 @@ protected MethodSpec generateHandleIncomingMessageHelper() { .beginControlFlow("if (node == null || node.isNull())") .addStatement( "throw new $T($S)", IllegalArgumentException.class, "Received null or invalid JSON message") - .endControlFlow() - .addStatement( - "$T typeNode = node.get($S)", - ClassName.get("com.fasterxml.jackson.databind", "JsonNode"), - "type") - .beginControlFlow("if (typeNode == null || typeNode.isNull())") - .addStatement("throw new $T($S)", IllegalArgumentException.class, "Message missing 'type' field") - .endControlFlow() - .addStatement("String type = typeNode.asText()"); - - // Switch on wire discriminant values extracted from each message body's literal/enum - // "type" property, rather than the Fern-internal message ID. - builder.beginControlFlow("switch (type)"); + .endControlFlow(); + // Collect server text messages with precomputed shape info + List serverTextMessages = new ArrayList<>(); + Map> requiredKeysById = new HashMap<>(); + Map> literalValuesById = new HashMap<>(); for (WebSocketMessage message : websocketChannel.getMessages()) { if (message.getOrigin() == WebSocketMessageOrigin.SERVER && !isMessageBodyBinary(message)) { - TypeName messageType = getMessageBodyType(message); - String handlerFieldName = getHandlerFieldName(message); - String wireDiscriminantValue = getWireDiscriminantValue(message); - - builder.addCode("case $S:\n", wireDiscriminantValue) - .beginControlFlow("if ($L != null)", handlerFieldName) - .addStatement( - "$T event = $N.treeToValue(node, $T.class)", - messageType, - objectMapperField, - messageType) - .beginControlFlow("if (event != null)") - .addStatement("$L.accept(event)", handlerFieldName) - .endControlFlow() - .endControlFlow() - .addStatement("break"); - } - } - - builder.addCode("default:\n"); - addUnknownTypeErrorHandler(builder); - builder.addStatement("break"); - - builder.endControlFlow() // end switch - .endControlFlow() // end try + serverTextMessages.add(message); + String id = message.getType().get(); + requiredKeysById.put(id, getMessageRequiredWireKeys(message)); + literalValuesById.put(id, getMessageLiteralValues(message)); + } + } + + // Sort by specificity (most constraints first) for correct dispatch ordering + serverTextMessages.sort((a, b) -> { + String idA = a.getType().get(); + String idB = b.getType().get(); + int specA = requiredKeysById.get(idA).size() + + literalValuesById.get(idA).size(); + int specB = requiredKeysById.get(idB).size() + + literalValuesById.get(idB).size(); + return Integer.compare(specB, specA); + }); + + // Emit shape-based trial deserialization for each server message + for (WebSocketMessage message : serverTextMessages) { + TypeName messageType = getMessageBodyType(message); + String handlerFieldName = getHandlerFieldName(message); + String id = message.getType().get(); + List requiredKeys = requiredKeysById.get(id); + Map literals = literalValuesById.get(id); + boolean hasGuards = !requiredKeys.isEmpty() || !literals.isEmpty(); + + if (hasGuards) { + CodeBlock condition = buildShapeCondition(requiredKeys, literals); + builder.beginControlFlow("if ($L)", condition); + } + + // Declare event variable outside try-catch so handler invocation is not + // wrapped in the deserialization catch block (user handler exceptions must propagate). + builder.addStatement("$T $L = null", messageType, handlerFieldName + "Event"); + builder.beginControlFlow("try") + .addStatement( + "$L = $N.treeToValue(node, $T.class)", + handlerFieldName + "Event", + objectMapperField, + messageType) + .nextControlFlow("catch ($T e)", Exception.class) + .endControlFlow(); // end try-catch + builder.beginControlFlow("if ($L != null)", handlerFieldName + "Event") + .beginControlFlow("if ($L != null)", handlerFieldName) + .addStatement("$L.accept($L)", handlerFieldName, handlerFieldName + "Event") + .endControlFlow() + .addStatement("return") + .endControlFlow(); + + if (hasGuards) { + builder.endControlFlow(); // end if guard + } + } + + // Fallback: no message type matched + addUnrecognizedMessageErrorHandler(builder); + + builder.endControlFlow() // end outer try .beginControlFlow("catch ($T e)", Exception.class) .beginControlFlow("if ($N != null)", onErrorHandlerField) .addStatement("$N.accept(e)", onErrorHandlerField) .endControlFlow() - .endControlFlow(); // end catch + .endControlFlow(); // end outer catch return builder.build(); } - private void addUnknownTypeErrorHandler(MethodSpec.Builder builder) { + private CodeBlock buildShapeCondition(List requiredKeys, Map literalValues) { + CodeBlock.Builder condition = CodeBlock.builder(); + boolean first = true; + for (String key : requiredKeys) { + if (!first) { + condition.add("\n&& "); + } + condition.add("node.has($S)", key); + first = false; + } + for (Map.Entry entry : literalValues.entrySet()) { + if (!first) { + condition.add("\n&& "); + } + condition.add("$S.equals(node.path($S).asText())", entry.getValue(), entry.getKey()); + first = false; + } + return condition.build(); + } + + private void addUnrecognizedMessageErrorHandler(MethodSpec.Builder builder) { builder.beginControlFlow("if ($N != null)", onErrorHandlerField) .addStatement( - "$N.accept(new $T($S + type + $S))", + "$N.accept(new $T($S + json.substring(0, $T.min(200, json.length())) + $S))", onErrorHandlerField, RuntimeException.class, - "Unknown WebSocket message type: '", - "'. Update your SDK version to support new message types.") + "Unrecognized WebSocket message: ", + Math.class, + "... Update your SDK version to support new message types.") .endControlFlow(); } + /** + * Returns the non-literal required wire keys for a WebSocket message body. These are properties that must be + * present in the JSON for the message to match. + */ + private List getMessageRequiredWireKeys(WebSocketMessage message) { + return message.getBody().visit(new WebSocketMessageBody.Visitor>() { + @Override + public List visitInlinedBody(InlinedWebSocketMessageBody body) { + List keys = new ArrayList<>(); + for (InlinedWebSocketMessageBodyProperty prop : body.getProperties()) { + if (isTypeRequired(prop.getValueType()) && !isLiteralType(prop.getValueType())) { + keys.add(NameUtils.getWireValue(prop.getName())); + } + } + for (DeclaredTypeName extendedType : body.getExtends()) { + collectRequiredWireKeysFromExtended(extendedType, keys); + } + return keys; + } + + @Override + public List visitReference(WebSocketMessageBodyReference reference) { + return getRequiredWireKeysFromType(reference.getBodyType()); + } + + @Override + public List _visitUnknown(Object unknown) { + return Collections.emptyList(); + } + }); + } + + /** + * Returns literal property values for a WebSocket message body. Maps wire key to expected string value (e.g., + * "type" -> "transcript"). + */ + private Map getMessageLiteralValues(WebSocketMessage message) { + return message.getBody().visit(new WebSocketMessageBody.Visitor>() { + @Override + public Map visitInlinedBody(InlinedWebSocketMessageBody body) { + Map literals = new LinkedHashMap<>(); + for (InlinedWebSocketMessageBodyProperty prop : body.getProperties()) { + getLiteralStringValue(prop.getValueType()) + .ifPresent(value -> literals.put(NameUtils.getWireValue(prop.getName()), value)); + } + for (DeclaredTypeName extendedType : body.getExtends()) { + collectLiteralValuesFromExtended(extendedType, literals); + } + return literals; + } + + @Override + public Map visitReference(WebSocketMessageBodyReference reference) { + return getLiteralValuesFromType(reference.getBodyType()); + } + + @Override + public Map _visitUnknown(Object unknown) { + return Collections.emptyMap(); + } + }); + } + + private List getRequiredWireKeysFromType(TypeReference bodyType) { + if (!bodyType.isNamed()) { + return Collections.emptyList(); + } + try { + TypeDeclaration typeDeclaration = clientGeneratorContext.getTypeDeclaration( + bodyType.getNamed().get().getTypeId()); + if (!typeDeclaration.getShape().isObject()) { + return Collections.emptyList(); + } + ObjectTypeDeclaration objectType = + typeDeclaration.getShape().getObject().get(); + List keys = new ArrayList<>(); + collectRequiredWireKeys(objectType, keys); + return keys; + } catch (IllegalArgumentException e) { + return Collections.emptyList(); + } + } + + private void collectRequiredWireKeys(ObjectTypeDeclaration objectType, List keys) { + for (ObjectProperty property : objectType.getProperties()) { + if (isTypeRequired(property.getValueType()) && !isLiteralType(property.getValueType())) { + keys.add(NameUtils.getWireValue(property.getName())); + } + } + for (DeclaredTypeName extendedType : objectType.getExtends()) { + collectRequiredWireKeysFromExtended(extendedType, keys); + } + } + + private void collectRequiredWireKeysFromExtended(DeclaredTypeName extendedType, List keys) { + try { + TypeDeclaration extDeclaration = clientGeneratorContext.getTypeDeclaration(extendedType.getTypeId()); + if (extDeclaration != null && extDeclaration.getShape().isObject()) { + collectRequiredWireKeys(extDeclaration.getShape().getObject().get(), keys); + } + } catch (IllegalArgumentException e) { + // Type not found in IR declarations + } + } + + private Map getLiteralValuesFromType(TypeReference bodyType) { + if (!bodyType.isNamed()) { + return Collections.emptyMap(); + } + try { + TypeDeclaration typeDeclaration = clientGeneratorContext.getTypeDeclaration( + bodyType.getNamed().get().getTypeId()); + if (!typeDeclaration.getShape().isObject()) { + return Collections.emptyMap(); + } + ObjectTypeDeclaration objectType = + typeDeclaration.getShape().getObject().get(); + Map literals = new LinkedHashMap<>(); + collectLiteralValues(objectType, literals); + return literals; + } catch (IllegalArgumentException e) { + return Collections.emptyMap(); + } + } + + private void collectLiteralValues(ObjectTypeDeclaration objectType, Map literals) { + for (ObjectProperty property : objectType.getProperties()) { + getLiteralStringValue(property.getValueType()) + .ifPresent(value -> literals.put(NameUtils.getWireValue(property.getName()), value)); + } + for (DeclaredTypeName extendedType : objectType.getExtends()) { + collectLiteralValuesFromExtended(extendedType, literals); + } + } + + private void collectLiteralValuesFromExtended(DeclaredTypeName extendedType, Map literals) { + try { + TypeDeclaration extDeclaration = clientGeneratorContext.getTypeDeclaration(extendedType.getTypeId()); + if (extDeclaration != null && extDeclaration.getShape().isObject()) { + collectLiteralValues(extDeclaration.getShape().getObject().get(), literals); + } + } catch (IllegalArgumentException e) { + // Type not found in IR declarations + } + } + + private boolean isTypeRequired(TypeReference typeRef) { + if (typeRef.isContainer()) { + ContainerType container = typeRef.getContainer().get(); + return !(container.isOptional() || container.isNullable()); + } + return true; + } + + private boolean isLiteralType(TypeReference typeRef) { + return typeRef.isContainer() + && typeRef.getContainer().flatMap(ContainerType::getLiteral).isPresent(); + } + + private Optional getLiteralStringValue(TypeReference typeRef) { + if (!typeRef.isContainer()) { + return Optional.empty(); + } + return typeRef.getContainer().flatMap(ContainerType::getLiteral).flatMap(literal -> { + // Handle string literals directly + Optional str = literal.getString(); + if (str.isPresent()) { + return str; + } + // Handle boolean literals by converting to their string representation + // so they can be checked via node.path("key").asText() + return literal.getBoolean().map(b -> b.toString()); + }); + } + /** * Extracts the wire discriminant value for a WebSocket message by examining the body's literal "type" property. * Falls back to the message ID if no literal type is found. @@ -797,12 +1051,15 @@ protected String getHandlerFieldName(WebSocketMessage message) { // Use custom methodName if available, otherwise fall back to wire discriminant value String baseName; if (message.getMethodName().isPresent()) { - // methodName is already the desired name (e.g., "sendSettings", "onFunctionCallResponse") baseName = toCamelCase(message.getMethodName().get()); } else { - // Use the wire discriminant value (e.g., "Welcome" → "welcome", not "AgentV1Welcome") String wireValue = getWireDiscriminantValue(message); - baseName = decapitalize(toCamelCase(wireValue)); + if (collidingDiscriminantValues.contains(wireValue)) { + // Multiple messages share this wire value — use message type ID to disambiguate + baseName = decapitalize(toCamelCase(message.getType().get())); + } else { + baseName = decapitalize(toCamelCase(wireValue)); + } } return baseName + "Handler"; } @@ -894,8 +1151,13 @@ protected String getMessageMethodName(WebSocketMessage message) { if (message.getMethodName().isPresent()) { baseName = toCamelCase(message.getMethodName().get()); } else { - // Use the wire discriminant value (e.g., "Welcome" instead of "AgentV1Welcome") - baseName = "on" + toPascalCase(getWireDiscriminantValue(message)); + String wireValue = getWireDiscriminantValue(message); + if (collidingDiscriminantValues.contains(wireValue)) { + // Multiple messages share this wire value — use message type ID to disambiguate + baseName = "on" + toPascalCase(message.getType().get()); + } else { + baseName = "on" + toPascalCase(wireValue); + } } if (RESERVED_CONSUMER_METHOD_NAMES.contains(baseName)) { return baseName + "Message"; diff --git a/generators/java/sdk/versions.yml b/generators/java/sdk/versions.yml index d3e31d8496a2..5ee509840f47 100644 --- a/generators/java/sdk/versions.yml +++ b/generators/java/sdk/versions.yml @@ -1,4 +1,22 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 4.6.1 + changelogEntry: + - summary: | + Fix undiscriminated union deserializer misclassifying payloads. The generated + deserializer now checks that all required wire keys are present in the JSON + object before attempting to convert to each variant, preventing the first + variant from always winning when Jackson's builder silently accepts missing + required fields. + type: fix + - summary: | + Replace switch-on-type WebSocket message dispatch with shape-based trial + deserialization. Messages are now matched by checking required-field presence + and literal values before attempting Jackson conversion. This correctly handles + AsyncAPI channels where multiple message schemas share the same discriminator + value (e.g., two "History" variants with disjoint required fields). + type: fix + createdAt: "2026-04-27" + irVersion: 66 - version: 4.6.0 changelogEntry: - summary: | diff --git a/generators/python-v2/dynamic-snippets/src/EndpointSnippetGenerator.ts b/generators/python-v2/dynamic-snippets/src/EndpointSnippetGenerator.ts index c6a08dee8fbc..e9a94ae42e8f 100644 --- a/generators/python-v2/dynamic-snippets/src/EndpointSnippetGenerator.ts +++ b/generators/python-v2/dynamic-snippets/src/EndpointSnippetGenerator.ts @@ -293,16 +293,24 @@ export class EndpointSnippetGenerator { auth: FernIr.dynamic.BasicAuth; values: FernIr.dynamic.BasicAuthValues; }): python.NamedValue[] { - return [ - { + // usernameOmit/passwordOmit are not yet in the published @fern-api/dynamic-ir-sdk@66.1.0 type; + // use runtime property checks until the next dynamic IR SDK release includes them. + const usernameOmitted = "usernameOmit" in auth && (auth as Record).usernameOmit === true; + const passwordOmitted = "passwordOmit" in auth && (auth as Record).passwordOmit === true; + const args: python.NamedValue[] = []; + if (!usernameOmitted) { + args.push({ name: this.context.getPropertyName(auth.username), value: python.TypeInstantiation.str(values.username) - }, - { + }); + } + if (!passwordOmitted) { + args.push({ name: this.context.getPropertyName(auth.password), value: python.TypeInstantiation.str(values.password) - } - ]; + }); + } + return args; } private getConstructorBearerAuthArgs({ diff --git a/generators/python-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts b/generators/python-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts index b5d0e216b3a3..254f3fdf7c7d 100644 --- a/generators/python-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts +++ b/generators/python-v2/sdk/src/wire-tests/WireTestSetupGenerator.ts @@ -658,9 +658,14 @@ def pytest_unconfigure(config: pytest.Config) -> None: break; case "basic": - // Basic auth uses username and password parameters - params.push(` ${caseConverter.snakeSafe(scheme.username)}="test_username",`); - params.push(` ${caseConverter.snakeSafe(scheme.password)}="test_password",`); + // Basic auth uses username and password parameters (skip omitted fields). + // Values must use hyphens ("test-username") to match mock-utils WireMock stubs. + if (!scheme.usernameOmit) { + params.push(` ${caseConverter.snakeSafe(scheme.username)}="test-username",`); + } + if (!scheme.passwordOmit) { + params.push(` ${caseConverter.snakeSafe(scheme.password)}="test-password",`); + } break; case "header": diff --git a/generators/python/sdk/changes/5.8.0/basic-auth-pw-omitted.yml b/generators/python/sdk/changes/5.8.0/basic-auth-pw-omitted.yml new file mode 100644 index 000000000000..9c35224f7b92 --- /dev/null +++ b/generators/python/sdk/changes/5.8.0/basic-auth-pw-omitted.yml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=../../../../../fern-changes-yml.schema.json + +- summary: | + Support omitting username or password from basic auth when configured via + `usernameOmit` or `passwordOmit` in the IR. Omitted fields are removed from + the SDK's public API and treated as empty strings internally (e.g., omitting + password encodes `username:`, omitting username encodes `:password`). When + both are omitted, the Authorization header is skipped entirely. + type: feat diff --git a/generators/python/sdk/versions.yml b/generators/python/sdk/versions.yml index b338290976c1..090b23fabc23 100644 --- a/generators/python/sdk/versions.yml +++ b/generators/python/sdk/versions.yml @@ -1,4 +1,15 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 5.8.0 + changelogEntry: + - summary: | + Support omitting username or password from basic auth when configured via + `usernameOmit` or `passwordOmit` in the IR. Omitted fields are removed from + the SDK's public API and treated as empty strings internally (e.g., omitting + password encodes `username:`, omitting username encodes `:password`). When + both are omitted, the Authorization header is skipped entirely. + type: feat + createdAt: "2026-04-27" + irVersion: 66 - version: 5.7.0 changelogEntry: - summary: | diff --git a/generators/python/src/fern_python/generators/sdk/client_generator/root_client_generator.py b/generators/python/src/fern_python/generators/sdk/client_generator/root_client_generator.py index 8848aff76aaa..b43b100db4d8 100644 --- a/generators/python/src/fern_python/generators/sdk/client_generator/root_client_generator.py +++ b/generators/python/src/fern_python/generators/sdk/client_generator/root_client_generator.py @@ -1697,11 +1697,11 @@ def __init__( self._async_init_parameters: Optional[List[ConstructorParameter]] = ( list(async_init_parameters) if async_init_parameters is not None else None ) + self._sync_constructor_overloads = sync_constructor_overloads + self._async_constructor_overloads = async_constructor_overloads self._oauth_token_override = oauth_token_override self._use_kwargs_snippets = use_kwargs_snippets self._base_url_example_value = base_url_example_value - self._sync_constructor_overloads = sync_constructor_overloads - self._async_constructor_overloads = async_constructor_overloads def build(self) -> GeneratedRootClient: def create_class_reference(class_name: str) -> AST.ClassReference: diff --git a/generators/python/src/fern_python/generators/sdk/core_utilities/client_wrapper_generator.py b/generators/python/src/fern_python/generators/sdk/core_utilities/client_wrapper_generator.py index e73432941c91..0763a8975300 100644 --- a/generators/python/src/fern_python/generators/sdk/core_utilities/client_wrapper_generator.py +++ b/generators/python/src/fern_python/generators/sdk/core_utilities/client_wrapper_generator.py @@ -529,38 +529,68 @@ def _write_get_headers_body(writer: AST.NodeWriter) -> None: writer.write_newline_if_last_line_not() basic_auth_scheme = self._get_basic_auth_scheme() if basic_auth_scheme is not None: + username_omitted = basic_auth_scheme.username_omit is True + password_omitted = basic_auth_scheme.password_omit is True + if not self._context.ir.sdk_config.is_auth_mandatory: - username_var = names.get_username_constructor_parameter_name(basic_auth_scheme) - password_var = names.get_password_constructor_parameter_name(basic_auth_scheme) - writer.write_line(f"{username_var} = self.{names.get_username_getter_name(basic_auth_scheme)}()") - writer.write_line(f"{password_var} = self.{names.get_password_getter_name(basic_auth_scheme)}()") - writer.write_line(f"if {username_var} is not None and {password_var} is not None:") - with writer.indent(): + # Build condition and args based on which fields are omitted vs present + conditions = [] + if not username_omitted: + username_var = names.get_username_constructor_parameter_name(basic_auth_scheme) + writer.write_line( + f"{username_var} = self.{names.get_username_getter_name(basic_auth_scheme)}()" + ) + conditions.append(f"{username_var} is not None") + if not password_omitted: + password_var = names.get_password_constructor_parameter_name(basic_auth_scheme) + writer.write_line( + f"{password_var} = self.{names.get_password_getter_name(basic_auth_scheme)}()" + ) + conditions.append(f"{password_var} is not None") + + # Omitted fields use empty string directly + username_arg = AST.Expression('""') if username_omitted else AST.Expression(username_var) + password_arg = AST.Expression('""') if password_omitted else AST.Expression(password_var) + + if conditions: + writer.write_line(f"if {' and '.join(conditions)}:") + with writer.indent(): + writer.write(f'headers["{ClientWrapperGenerator.AUTHORIZATION_HEADER}"] = ') + writer.write_node( + AST.ClassInstantiation( + class_=httpx.HttpX.BASIC_AUTH, + args=[username_arg, password_arg], + ) + ) + writer.write("._auth_header") + writer.write_newline_if_last_line_not() + else: + # Both fields omitted and auth is non-mandatory - skip header entirely + pass + else: + # Auth is mandatory - omitted fields use empty string + if username_omitted and password_omitted: + # Both fields omitted - skip header entirely + pass + else: + username_getter = ( + '""' if username_omitted else f"self.{names.get_username_getter_name(basic_auth_scheme)}()" + ) + password_getter = ( + '""' if password_omitted else f"self.{names.get_password_getter_name(basic_auth_scheme)}()" + ) writer.write(f'headers["{ClientWrapperGenerator.AUTHORIZATION_HEADER}"] = ') writer.write_node( AST.ClassInstantiation( class_=httpx.HttpX.BASIC_AUTH, args=[ - AST.Expression(f"{username_var}"), - AST.Expression(f"{password_var}"), + AST.Expression(username_getter), + AST.Expression(password_getter), ], ) ) writer.write("._auth_header") writer.write_newline_if_last_line_not() - else: - writer.write(f'headers["{ClientWrapperGenerator.AUTHORIZATION_HEADER}"] = ') - writer.write_node( - AST.ClassInstantiation( - class_=httpx.HttpX.BASIC_AUTH, - args=[ - AST.Expression(f"self.{names.get_username_getter_name(basic_auth_scheme)}()"), - AST.Expression(f"self.{names.get_password_getter_name(basic_auth_scheme)}()"), - ], - ) - ) - writer.write("._auth_header") - writer.write_newline_if_last_line_not() for param in constructor_parameters: if param.is_basic: continue @@ -831,110 +861,114 @@ def _get_constructor_info(self, exclude_auth: bool = False) -> ConstructorInfo: basic_auth_scheme = self._get_basic_auth_scheme() if basic_auth_scheme is not None: - username_constructor_parameter_name = names.get_username_constructor_parameter_name(basic_auth_scheme) - username_constructor_parameter = ConstructorParameter( - constructor_parameter_name=username_constructor_parameter_name, - private_member_name=names.get_username_member_name(basic_auth_scheme), - type_hint=( - ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT - if self._context.ir.sdk_config.is_auth_mandatory - else AST.TypeHint.optional(ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT) - ), - initializer=AST.Expression( - f'{username_constructor_parameter_name}="YOUR_{resolve_name(basic_auth_scheme.username).screaming_snake_case.safe_name}"', - ), - getter_method=AST.FunctionDeclaration( - name=names.get_username_getter_name(basic_auth_scheme), - signature=AST.FunctionSignature( - parameters=[], - return_type=( - AST.TypeHint.str_() - if self._context.ir.sdk_config.is_auth_mandatory - else AST.TypeHint.optional(AST.TypeHint.str_()) - ), - ), - body=AST.CodeWriter( - self._get_required_getter_body_writer( - member_name=names.get_username_member_name(basic_auth_scheme) - ) + username_omitted = basic_auth_scheme.username_omit is True + password_omitted = basic_auth_scheme.password_omit is True + + # When omit is true, the field is completely removed from the end-user API. + # Only add non-omitted fields to constructor parameters. + if not username_omitted: + username_constructor_parameter_name = names.get_username_constructor_parameter_name(basic_auth_scheme) + username_constructor_parameter = ConstructorParameter( + constructor_parameter_name=username_constructor_parameter_name, + private_member_name=names.get_username_member_name(basic_auth_scheme), + type_hint=( + ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT if self._context.ir.sdk_config.is_auth_mandatory - else self._get_optional_getter_body_writer( - member_name=names.get_username_member_name(basic_auth_scheme) - ) + else AST.TypeHint.optional(ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT) ), - ), - environment_variable=( - basic_auth_scheme.username_env_var if basic_auth_scheme.username_env_var is not None else None - ), - is_basic=True, - template=TemplateGenerator.string_template( - is_optional=False, - template_string_prefix=username_constructor_parameter_name, - inputs=[ - TemplateInput.factory.payload( - PayloadInput( - location="AUTH", - path="username", - ) + initializer=AST.Expression( + f'{username_constructor_parameter_name}="YOUR_{resolve_name(basic_auth_scheme.username).screaming_snake_case.safe_name}"', + ), + getter_method=AST.FunctionDeclaration( + name=names.get_username_getter_name(basic_auth_scheme), + signature=AST.FunctionSignature( + parameters=[], + return_type=( + AST.TypeHint.str_() + if self._context.ir.sdk_config.is_auth_mandatory + else AST.TypeHint.optional(AST.TypeHint.str_()) + ), ), - ], - ), - ) - password_constructor_parameter_name = names.get_password_constructor_parameter_name(basic_auth_scheme) - password_constructor_parameter = ConstructorParameter( - constructor_parameter_name=password_constructor_parameter_name, - private_member_name=names.get_password_member_name(basic_auth_scheme), - type_hint=( - ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT - if self._context.ir.sdk_config.is_auth_mandatory - else AST.TypeHint.optional(ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT) - ), - initializer=AST.Expression( - f'{password_constructor_parameter_name}="YOUR_{resolve_name(basic_auth_scheme.password).screaming_snake_case.safe_name}"', - ), - getter_method=AST.FunctionDeclaration( - name=names.get_password_getter_name(basic_auth_scheme), - signature=AST.FunctionSignature( - parameters=[], - return_type=( - AST.TypeHint.str_() + body=AST.CodeWriter( + self._get_required_getter_body_writer( + member_name=names.get_username_member_name(basic_auth_scheme) + ) if self._context.ir.sdk_config.is_auth_mandatory - else AST.TypeHint.optional(AST.TypeHint.str_()) + else self._get_optional_getter_body_writer( + member_name=names.get_username_member_name(basic_auth_scheme) + ) ), ), - body=AST.CodeWriter( - self._get_required_getter_body_writer( - member_name=names.get_password_member_name(basic_auth_scheme) - ) + environment_variable=( + basic_auth_scheme.username_env_var if basic_auth_scheme.username_env_var is not None else None + ), + is_basic=True, + template=TemplateGenerator.string_template( + is_optional=False, + template_string_prefix=username_constructor_parameter_name, + inputs=[ + TemplateInput.factory.payload( + PayloadInput( + location="AUTH", + path="username", + ) + ), + ], + ), + ) + parameters.append(username_constructor_parameter) + + if not password_omitted: + password_constructor_parameter_name = names.get_password_constructor_parameter_name(basic_auth_scheme) + password_constructor_parameter = ConstructorParameter( + constructor_parameter_name=password_constructor_parameter_name, + private_member_name=names.get_password_member_name(basic_auth_scheme), + type_hint=( + ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT if self._context.ir.sdk_config.is_auth_mandatory - else self._get_optional_getter_body_writer( - member_name=names.get_password_member_name(basic_auth_scheme) - ) + else AST.TypeHint.optional(ClientWrapperGenerator.STRING_OR_SUPPLIER_TYPE_HINT) ), - ), - is_basic=True, - environment_variable=( - basic_auth_scheme.password_env_var if basic_auth_scheme.password_env_var is not None else None - ), - template=TemplateGenerator.string_template( - is_optional=False, - template_string_prefix=password_constructor_parameter_name, - inputs=[ - TemplateInput.factory.payload( - PayloadInput( - location="AUTH", - path="password", + initializer=AST.Expression( + f'{password_constructor_parameter_name}="YOUR_{resolve_name(basic_auth_scheme.password).screaming_snake_case.safe_name}"', + ), + getter_method=AST.FunctionDeclaration( + name=names.get_password_getter_name(basic_auth_scheme), + signature=AST.FunctionSignature( + parameters=[], + return_type=( + AST.TypeHint.str_() + if self._context.ir.sdk_config.is_auth_mandatory + else AST.TypeHint.optional(AST.TypeHint.str_()) + ), + ), + body=AST.CodeWriter( + self._get_required_getter_body_writer( + member_name=names.get_password_member_name(basic_auth_scheme) + ) + if self._context.ir.sdk_config.is_auth_mandatory + else self._get_optional_getter_body_writer( + member_name=names.get_password_member_name(basic_auth_scheme) ) ), - ], - ), - ) - parameters.extend( - [ - username_constructor_parameter, - password_constructor_parameter, - ] - ) + ), + is_basic=True, + environment_variable=( + basic_auth_scheme.password_env_var if basic_auth_scheme.password_env_var is not None else None + ), + template=TemplateGenerator.string_template( + is_optional=False, + template_string_prefix=password_constructor_parameter_name, + inputs=[ + TemplateInput.factory.payload( + PayloadInput( + location="AUTH", + path="password", + ) + ), + ], + ), + ) + parameters.append(password_constructor_parameter) # Add generic headers parameter parameters.append(headers_constructor_parameter) diff --git a/package.json b/package.json index b745087971ce..a28f2f0713b4 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "minimatch": ">=10.2.3", "qs": "6.15.0", "url-join": "^4.0.1", - "@fern-api/fdr-sdk": "1.1.13-c1ad12a2b8", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "form-data": "^4.0.4", "@fern-api/ui-core-utils": "0.145.12-b50d999d1", "vite": "^7.3.2", diff --git a/packages/cli/api-importers/graphql/package.json b/packages/cli/api-importers/graphql/package.json index 62cb25f1b8b7..35a89e44e303 100644 --- a/packages/cli/api-importers/graphql/package.json +++ b/packages/cli/api-importers/graphql/package.json @@ -31,7 +31,7 @@ "test:update": "vitest --run -u --passWithNoTests" }, "dependencies": { - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/task-context": "workspace:*", "graphql": "catalog:" diff --git a/packages/cli/cli/changes/4.97.0/feat-docs-translations.yml b/packages/cli/cli/changes/4.97.0/feat-docs-translations.yml new file mode 100644 index 000000000000..15d559df10b2 --- /dev/null +++ b/packages/cli/cli/changes/4.97.0/feat-docs-translations.yml @@ -0,0 +1,4 @@ +- summary: | + [Alpha] Add support for a `translations` block in `docs.yml` to configure multi-language documentation. + Each entry specifies a locale (`lang`) and optionally marks it as the default language. + type: feat diff --git a/packages/cli/cli/changes/4.97.0/fix-docs-translations-fdr-config.yml b/packages/cli/cli/changes/4.97.0/fix-docs-translations-fdr-config.yml new file mode 100644 index 000000000000..7cfe625d2850 --- /dev/null +++ b/packages/cli/cli/changes/4.97.0/fix-docs-translations-fdr-config.yml @@ -0,0 +1,4 @@ +- summary: | + Include docs translation metadata in the docs definition published to FDR so generated `fdr.json` + advertises configured locales alongside uploaded translation files. + type: fix diff --git a/packages/cli/cli/package.json b/packages/cli/cli/package.json index c6f9d27c234d..dcfbcf131f06 100644 --- a/packages/cli/cli/package.json +++ b/packages/cli/cli/package.json @@ -68,7 +68,7 @@ "@fern-api/docs-preview": "workspace:*", "@fern-api/docs-resolver": "workspace:*", "@fern-api/docs-validator": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fern-definition-formatter": "workspace:*", "@fern-api/fern-definition-schema": "workspace:*", "@fern-api/fern-definition-validator": "workspace:*", diff --git a/packages/cli/cli/versions.yml b/packages/cli/cli/versions.yml index 3c75b69cbe3b..f3426b5ab312 100644 --- a/packages/cli/cli/versions.yml +++ b/packages/cli/cli/versions.yml @@ -1,4 +1,16 @@ # yaml-language-server: $schema=../../../fern-versions-yml.schema.json +- version: 4.97.0 + changelogEntry: + - summary: | + [Alpha] Add support for a `translations` block in `docs.yml` to configure multi-language documentation. + Each entry specifies a locale (`lang`) and optionally marks it as the default language. + type: feat + - summary: | + Include docs translation metadata in the docs definition published to FDR so generated `fdr.json` + advertises configured locales alongside uploaded translation files. + type: fix + createdAt: "2026-04-27" + irVersion: 66 - version: 4.96.0 changelogEntry: - summary: | diff --git a/packages/cli/configuration-loader/package.json b/packages/cli/configuration-loader/package.json index fe27dd04aa14..f5083ba88c09 100644 --- a/packages/cli/configuration-loader/package.json +++ b/packages/cli/configuration-loader/package.json @@ -34,7 +34,7 @@ "dependencies": { "@fern-api/configuration": "workspace:*", "@fern-api/core-utils": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/github": "workspace:*", "@fern-api/logging-execa": "workspace:*", diff --git a/packages/cli/configuration-loader/src/docs-yml/__test__/translationsDocsConfiguration.test.ts b/packages/cli/configuration-loader/src/docs-yml/__test__/translationsDocsConfiguration.test.ts new file mode 100644 index 000000000000..fd9ff7546a8a --- /dev/null +++ b/packages/cli/configuration-loader/src/docs-yml/__test__/translationsDocsConfiguration.test.ts @@ -0,0 +1,189 @@ +import { docsYml } from "@fern-api/configuration"; +import { AbsoluteFilePath, RelativeFilePath } from "@fern-api/fs-utils"; +import { createMockTaskContext } from "@fern-api/task-context"; +import { mkdir, mkdtemp, rm, writeFile } from "fs/promises"; +import os from "os"; +import path from "path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; + +import { parseDocsConfiguration } from "../parseDocsConfiguration.js"; + +function makeMinimalRawConfig( + overrides: Partial = {} +): docsYml.RawSchemas.DocsConfiguration { + return { + instances: [], + // navigation is required by parseDocsConfiguration + navigation: [], + ...overrides + } as unknown as docsYml.RawSchemas.DocsConfiguration; +} + +describe("parseDocsConfiguration — translations config field", () => { + it("should produce undefined translations when not specified", async () => { + // No real FS access needed — no translation dirs to check + const FAKE_FERN_DIR = "/fern" as AbsoluteFilePath; + const FAKE_CONFIG_PATH = "/fern/docs.yml" as AbsoluteFilePath; + + const parsed = await parseDocsConfiguration({ + rawDocsConfiguration: makeMinimalRawConfig(), + absolutePathToFernFolder: FAKE_FERN_DIR, + absoluteFilepathToDocsConfig: FAKE_CONFIG_PATH, + context: createMockTaskContext() + }); + + expect(parsed.translations).toBeUndefined(); + expect(parsed.translationPages).toBeUndefined(); + }); +}); + +describe("parseDocsConfiguration — translation pages loading", () => { + let tmpDir: string; + + beforeEach(async () => { + tmpDir = await mkdtemp(path.join(os.tmpdir(), "fern-translations-test-")); + }); + + afterEach(async () => { + await rm(tmpDir, { recursive: true, force: true }); + }); + + it("should return undefined translationPages when no translations configured", async () => { + const fernDir = tmpDir as AbsoluteFilePath; + const configPath = path.join(tmpDir, "docs.yml") as AbsoluteFilePath; + await writeFile(configPath, ""); + + const parsed = await parseDocsConfiguration({ + rawDocsConfiguration: makeMinimalRawConfig(), + absolutePathToFernFolder: fernDir, + absoluteFilepathToDocsConfig: configPath, + context: createMockTaskContext() + }); + + expect(parsed.translationPages).toBeUndefined(); + }); + + it("should load translated pages from translations// directories", async () => { + const fernDir = tmpDir as AbsoluteFilePath; + const configPath = path.join(tmpDir, "docs.yml") as AbsoluteFilePath; + + // Create a page in the fern folder + const pagesDir = path.join(tmpDir, "pages"); + await mkdir(pagesDir, { recursive: true }); + await writeFile(path.join(pagesDir, "getting-started.mdx"), "# Getting Started"); + await writeFile(configPath, ""); + + // Create French translation directory and the same page + const frDir = path.join(tmpDir, "translations", "fr", "pages"); + await mkdir(frDir, { recursive: true }); + await writeFile(path.join(frDir, "getting-started.mdx"), "# Démarrage rapide"); + + // Build a raw config that references the page + // Note: Must include a default locale (en) so that "fr" is treated as a translation + const config = makeMinimalRawConfig({ + translations: [{ lang: "en", default: true }, { lang: "fr" }], + navigation: [ + { + page: "Getting Started", + path: "pages/getting-started.mdx" + } + ] as docsYml.RawSchemas.NavigationConfig + }); + + const parsed = await parseDocsConfiguration({ + rawDocsConfiguration: config, + absolutePathToFernFolder: fernDir, + absoluteFilepathToDocsConfig: configPath, + context: createMockTaskContext() + }); + + expect(parsed.translationPages).toBeDefined(); + const frPages = parsed.translationPages?.["fr"]; + expect(frPages).toBeDefined(); + expect(frPages?.[RelativeFilePath.of("pages/getting-started.mdx")]).toBe("# Démarrage rapide"); + }); + + it("should warn about missing translation files but still succeed", async () => { + const fernDir = tmpDir as AbsoluteFilePath; + const configPath = path.join(tmpDir, "docs.yml") as AbsoluteFilePath; + + // Create a page in the fern folder + const pagesDir = path.join(tmpDir, "pages"); + await mkdir(pagesDir, { recursive: true }); + await writeFile(path.join(pagesDir, "getting-started.mdx"), "# Getting Started"); + await writeFile(configPath, ""); + + // Create Japanese translation directory but WITHOUT the page + const jaDir = path.join(tmpDir, "translations", "ja"); + await mkdir(jaDir, { recursive: true }); + + // Note: Must include a default locale (en) so that "ja" is treated as a translation + const config = makeMinimalRawConfig({ + translations: [{ lang: "en", default: true }, { lang: "ja" }], + navigation: [ + { + page: "Getting Started", + path: "pages/getting-started.mdx" + } + ] as docsYml.RawSchemas.NavigationConfig + }); + + const warnings: string[] = []; + const mockContext = createMockTaskContext({ + logger: { + warn: (msg: string) => warnings.push(msg), + info: () => undefined, + debug: () => undefined, + error: () => undefined + } as never + }); + + const parsed = await parseDocsConfiguration({ + rawDocsConfiguration: config, + absolutePathToFernFolder: fernDir, + absoluteFilepathToDocsConfig: configPath, + context: mockContext + }); + + // Should still have an entry for "ja" but empty (no files found) + expect(parsed.translationPages?.["ja"]).toBeDefined(); + expect(Object.keys(parsed.translationPages?.["ja"] ?? {})).toHaveLength(0); + // Should have warned about missing files + expect(warnings.some((w) => w.includes("ja") && w.includes("missing"))).toBe(true); + }); + + it("should load translations for multiple locales", async () => { + const fernDir = tmpDir as AbsoluteFilePath; + const configPath = path.join(tmpDir, "docs.yml") as AbsoluteFilePath; + + const pagesDir = path.join(tmpDir, "pages"); + await mkdir(pagesDir, { recursive: true }); + await writeFile(path.join(pagesDir, "index.mdx"), "# Home"); + await writeFile(configPath, ""); + + for (const [locale, content] of [ + ["fr", "# Accueil"], + ["ja", "# ホーム"] + ] as const) { + const dir = path.join(tmpDir, "translations", locale, "pages"); + await mkdir(dir, { recursive: true }); + await writeFile(path.join(dir, "index.mdx"), content); + } + + // Note: Must include a default locale (en) so that "fr" and "ja" are treated as translations + const config = makeMinimalRawConfig({ + translations: [{ lang: "en", default: true }, { lang: "fr" }, { lang: "ja" }], + navigation: [{ page: "Home", path: "pages/index.mdx" }] as docsYml.RawSchemas.NavigationConfig + }); + + const parsed = await parseDocsConfiguration({ + rawDocsConfiguration: config, + absolutePathToFernFolder: fernDir, + absoluteFilepathToDocsConfig: configPath, + context: createMockTaskContext() + }); + + expect(parsed.translationPages?.["fr"]?.[RelativeFilePath.of("pages/index.mdx")]).toBe("# Accueil"); + expect(parsed.translationPages?.["ja"]?.[RelativeFilePath.of("pages/index.mdx")]).toBe("# ホーム"); + }); +}); diff --git a/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts b/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts index f9d0152c4518..9229ed2aeed4 100644 --- a/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts +++ b/packages/cli/configuration-loader/src/docs-yml/parseDocsConfiguration.ts @@ -1,9 +1,8 @@ import { docsYml } from "@fern-api/configuration"; import { assertNever, isPlainObject, sanitizeNullValues } from "@fern-api/core-utils"; import { FdrAPI as CjsFdrSdk } from "@fern-api/fdr-sdk"; -import { AbsoluteFilePath, dirname, doesPathExist, listFiles, resolve } from "@fern-api/fs-utils"; +import { AbsoluteFilePath, dirname, doesPathExist, listFiles, RelativeFilePath, resolve } from "@fern-api/fs-utils"; import { CliError, TaskContext } from "@fern-api/task-context"; - import { readFile } from "fs/promises"; import yaml from "js-yaml"; import path from "path"; @@ -148,18 +147,42 @@ export async function parseDocsConfiguration({ absoluteFilepathToDocsConfig }); - const [navigation, pages, typography, css, js, metadata, context7File, llmsTxtFile, llmsFullTxtFile] = - await Promise.all([ - convertedNavigationPromise, - pagesPromise, - typographyPromise, - cssPromise, - jsPromise, - metadataPromise, - context7FilePromise, - llmsTxtFilePromise, - llmsFullTxtFilePromise - ]); + const defaultLocale = + rawDocsConfiguration.translations?.find((t) => t.default === true)?.lang ?? + rawDocsConfiguration.translations?.[0]?.lang; + const translationPagesPromise = pagesPromise.then((resolvedPages) => + loadTranslationPages({ + translations: rawDocsConfiguration.translations, + defaultLocale, + pages: resolvedPages, + absolutePathToFernFolder, + context + }) + ); + + const [ + navigation, + pages, + typography, + css, + js, + metadata, + context7File, + llmsTxtFile, + llmsFullTxtFile, + translationPages + ] = await Promise.all([ + convertedNavigationPromise, + pagesPromise, + typographyPromise, + cssPromise, + jsPromise, + metadataPromise, + context7FilePromise, + llmsTxtFilePromise, + llmsFullTxtFilePromise, + translationPagesPromise + ]); // Validate incompatible tabs configuration: sidebar placement + center alignment const resolvedTheme = convertThemeConfig(rawDocsConfiguration.theme); @@ -185,6 +208,9 @@ export async function parseDocsConfiguration({ /* filepath of page to contents */ pages, + /* per-locale translated page content */ + translationPages, + /* navigation */ landingPage, navigation, @@ -192,6 +218,7 @@ export async function parseDocsConfiguration({ footerLinks: convertFooterLinks(footerLinks), defaultLanguage, languages: rawDocsConfiguration.languages, + translations: rawDocsConfiguration.translations, announcement: rawDocsConfiguration.announcement, /* seo */ @@ -249,6 +276,8 @@ export async function parseDocsConfiguration({ /* integrations */ integrations: { ...integrations, + // context7 is handled separately via context7File (resolved to AbsoluteFilePath) + context7: undefined, intercom: integrations?.intercom ? integrations.intercom : undefined }, @@ -1916,3 +1945,85 @@ function validateCollapsibleConfig({ ); } } + +/** + * Loads translated page content from `translations//` directories. + * + * For each locale declared in `translations`, this function: + * 1. Checks that `translations//` exists (errors if missing). + * 2. For each page referenced in the primary navigation, looks for the same + * relative path under `translations//`. Missing individual files are + * reported as warnings (partial translations are allowed). + * 3. Returns a map of locale → { relativeFilePath → markdown content }. + */ +async function loadTranslationPages({ + translations, + defaultLocale, + pages, + absolutePathToFernFolder, + context +}: { + translations: docsYml.RawSchemas.TranslationConfig[] | undefined; + defaultLocale: string | undefined; + pages: Record; + absolutePathToFernFolder: AbsoluteFilePath; + context: TaskContext; +}): Promise> | undefined> { + if (translations == null || translations.length === 0) { + return undefined; + } + + const translationsRootDir = path.join(absolutePathToFernFolder, "translations") as AbsoluteFilePath; + + const result: Record> = {}; + + await Promise.all( + translations.map(async ({ lang }) => { + // The default locale's pages live in the top-level `pages/` directory, + // not in `translations//`. Always skip it, even if the directory exists. + if (lang === defaultLocale) { + return; + } + + const langDir = path.join(translationsRootDir, lang) as AbsoluteFilePath; + + if (!(await doesPathExist(langDir))) { + context.failAndThrow( + `Translation directory for locale "${lang}" not found.`, + `Expected a directory at: ${langDir}\n` + + `Create the directory and add translated versions of your documentation pages.\n` + + `The directory should mirror the same relative paths referenced in your docs.yml navigation.\n` + + `Example: if your docs.yml references "pages/getting-started.mdx", add a translated\n` + + `version at "translations/${lang}/pages/getting-started.mdx".` + ); + return; + } + + const localePages: Record = {} as Record; + const missingFiles: RelativeFilePath[] = []; + + await Promise.all( + (Object.keys(pages) as RelativeFilePath[]).map(async (relativeFilePath) => { + const translatedFilePath = path.join(langDir, relativeFilePath) as AbsoluteFilePath; + if (await doesPathExist(translatedFilePath)) { + localePages[relativeFilePath] = await readFile(translatedFilePath, "utf-8"); + } else { + missingFiles.push(relativeFilePath); + } + }) + ); + + if (missingFiles.length > 0) { + context.logger.warn( + `Translation for locale "${lang}" is missing ${missingFiles.length} page(s):\n` + + missingFiles.map((f) => ` - translations/${lang}/${f}`).join("\n") + + `\nThese pages will fall back to the default language content.` + ); + } + + result[lang] = localePages; + }) + ); + + return result; +} diff --git a/packages/cli/configuration/package.json b/packages/cli/configuration/package.json index b1cdc7750bb3..58a2418c0680 100644 --- a/packages/cli/configuration/package.json +++ b/packages/cli/configuration/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "@fern-api/core-utils": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fern-definition-schema": "workspace:*", "@fern-api/path-utils": "workspace:*", "@fern-fern/fiddle-sdk": "catalog:", diff --git a/packages/cli/configuration/src/docs-yml/DocsYmlSchemas.ts b/packages/cli/configuration/src/docs-yml/DocsYmlSchemas.ts index 939d0a56b3d4..bf3c21495e24 100644 --- a/packages/cli/configuration/src/docs-yml/DocsYmlSchemas.ts +++ b/packages/cli/configuration/src/docs-yml/DocsYmlSchemas.ts @@ -944,6 +944,13 @@ export const ProductFileConfig = z.object({ navigation: NavigationConfig }); +// ===== Translations ===== + +export const TranslationConfig = z.object({ + lang: Language, + default: z.boolean().optional() +}); + // ===== Main DocsConfiguration ===== export const DocsConfiguration = z.object({ @@ -964,6 +971,21 @@ export const DocsConfiguration = z.object({ experimental: ExperimentalConfig.optional(), "default-language": ProgrammingLanguage.optional(), languages: z.array(Language).optional(), + translations: z + .array(TranslationConfig) + .optional() + .superRefine((translations, ctx) => { + if (translations == null) { + return; + } + const defaultCount = translations.filter((t) => t.default === true).length; + if (defaultCount > 1) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Only one translation entry can be marked as default, but ${defaultCount} were found` + }); + } + }), "ai-chat": AIChatConfig.optional(), "ai-search": AIChatConfig.optional(), "ai-examples": AiExamplesConfig.optional(), diff --git a/packages/cli/configuration/src/docs-yml/ParsedDocsConfiguration.ts b/packages/cli/configuration/src/docs-yml/ParsedDocsConfiguration.ts index 28284ee80b7a..068bba9cedc3 100644 --- a/packages/cli/configuration/src/docs-yml/ParsedDocsConfiguration.ts +++ b/packages/cli/configuration/src/docs-yml/ParsedDocsConfiguration.ts @@ -14,6 +14,7 @@ import { PlaygroundSettings, Target, ThemeConfig, + TranslationConfig, VersionAvailability } from "./schemas/index.js"; @@ -52,6 +53,9 @@ export interface ParsedDocsConfiguration { /* filepath of page to contents */ pages: Record; + /* per-locale translated page content: locale → { relativeFilePath → markdown } */ + translationPages: Record> | undefined; + /* RBAC declaration */ roles: string[] | undefined; @@ -80,6 +84,7 @@ export interface ParsedDocsConfiguration { llmsTxtFile: AbsoluteFilePath | undefined; llmsFullTxtFile: AbsoluteFilePath | undefined; languages: Language[] | undefined; + translations: TranslationConfig[] | undefined; defaultLanguage: CjsFdrSdk.docs.v1.commons.ProgrammingLanguage | undefined; analyticsConfig: CjsFdrSdk.docs.v1.commons.AnalyticsConfig | undefined; announcement: AnnouncementConfig | undefined; diff --git a/packages/cli/configuration/src/docs-yml/__test__/translations.test.ts b/packages/cli/configuration/src/docs-yml/__test__/translations.test.ts new file mode 100644 index 000000000000..1de382dac639 --- /dev/null +++ b/packages/cli/configuration/src/docs-yml/__test__/translations.test.ts @@ -0,0 +1,90 @@ +import { describe, expect, it } from "vitest"; + +import { DocsConfiguration, TranslationConfig } from "../DocsYmlSchemas.js"; + +describe("TranslationConfig schema", () => { + it("should parse a translation entry with lang only", () => { + const result = TranslationConfig.parse({ lang: "en" }); + expect(result.lang).toBe("en"); + expect(result.default).toBeUndefined(); + }); + + it("should parse a translation entry with lang and default: true", () => { + const result = TranslationConfig.parse({ lang: "fr", default: true }); + expect(result.lang).toBe("fr"); + expect(result.default).toBe(true); + }); + + it("should parse a translation entry with default: false", () => { + const result = TranslationConfig.parse({ lang: "ja", default: false }); + expect(result.lang).toBe("ja"); + expect(result.default).toBe(false); + }); + + it("should reject an unsupported language code", () => { + expect(() => TranslationConfig.parse({ lang: "xx" })).toThrow(); + }); + + it("should reject a missing lang field", () => { + expect(() => TranslationConfig.parse({ default: true })).toThrow(); + }); + + it("should reject a non-boolean default field", () => { + expect(() => TranslationConfig.parse({ lang: "en", default: "yes" })).toThrow(); + }); + + it("should accept all supported language codes", () => { + const langs = ["en", "es", "fr", "de", "it", "pt", "ja", "zh", "ko", "el", "no", "pl", "ru", "sv", "tr"]; + for (const lang of langs) { + expect(() => TranslationConfig.parse({ lang })).not.toThrow(); + } + }); +}); + +describe("DocsConfiguration translations field", () => { + it("should parse a docs config with no translations field", () => { + const result = DocsConfiguration.parse({ instances: [] }); + expect(result.translations).toBeUndefined(); + }); + + it("should parse a docs config with a single default translation", () => { + const result = DocsConfiguration.parse({ + instances: [], + translations: [{ lang: "en", default: true }] + }); + expect(result.translations).toHaveLength(1); + expect(result.translations?.[0]?.lang).toBe("en"); + expect(result.translations?.[0]?.default).toBe(true); + }); + + it("should parse a docs config with multiple translations", () => { + const result = DocsConfiguration.parse({ + instances: [], + translations: [{ lang: "en", default: true }, { lang: "ja" }, { lang: "fr" }] + }); + expect(result.translations).toHaveLength(3); + expect(result.translations?.[0]?.lang).toBe("en"); + expect(result.translations?.[1]?.lang).toBe("ja"); + expect(result.translations?.[1]?.default).toBeUndefined(); + expect(result.translations?.[2]?.lang).toBe("fr"); + }); + + it("should reject translations with an invalid language code", () => { + expect(() => + DocsConfiguration.parse({ + instances: [], + translations: [{ lang: "xx" }] + }) + ).toThrow(); + }); + + it("should allow translations alongside languages field", () => { + const result = DocsConfiguration.parse({ + instances: [], + languages: ["en", "fr"], + translations: [{ lang: "en", default: true }, { lang: "fr" }] + }); + expect(result.languages).toEqual(["en", "fr"]); + expect(result.translations).toHaveLength(2); + }); +}); diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/DocsConfiguration.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/DocsConfiguration.ts index bc9433ae7745..d43bdc53909c 100644 --- a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/DocsConfiguration.ts +++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/DocsConfiguration.ts @@ -54,6 +54,21 @@ export interface DocsConfiguration { */ defaultLanguage?: FernDocsConfig.ProgrammingLanguage; languages?: FernDocsConfig.Language[]; + /** + * Configuration for multi-language documentation. Each entry defines a locale + * that the documentation supports. Use the `translations/` directory alongside + * `docs.yml` to provide per-language content. + * + * Example: + * ```yaml + * translations: + * - lang: en + * default: true + * - lang: ja + * - lang: fr + * ``` + */ + translations?: FernDocsConfig.TranslationConfig[]; aiChat?: FernDocsConfig.AiChatConfig; aiSearch?: FernDocsConfig.AiChatConfig; /** Configure AI-powered example enhancement for API documentation. When enabled, API examples will be enhanced with AI-generated content to provide more comprehensive and realistic examples. */ diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/TranslationConfig.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/TranslationConfig.ts new file mode 100644 index 000000000000..4d75ead9da6f --- /dev/null +++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/TranslationConfig.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as FernDocsConfig from "../../../index.js"; + +export interface TranslationConfig { + lang: FernDocsConfig.Language; + /** Whether this language is the default. At most one entry should be marked as default. */ + default?: boolean; +} diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/index.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/index.ts index cb9371654ddc..92fe869f781a 100644 --- a/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/index.ts +++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/api/resources/docs/types/index.ts @@ -134,6 +134,7 @@ export * from "./TabVariant.js"; export * from "./Target.js"; export * from "./ThemeConfig.js"; export * from "./TitleSource.js"; +export * from "./TranslationConfig.js"; export * from "./TwitterCardSetting.js"; export * from "./UntabbedNavigationConfig.js"; export * from "./VersionAvailability.js"; diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/DocsConfiguration.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/DocsConfiguration.ts index b416ac887258..28bfc60ad914 100644 --- a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/DocsConfiguration.ts +++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/DocsConfiguration.ts @@ -36,6 +36,7 @@ import { RoleId } from "./RoleId.js"; import { TabConfig } from "./TabConfig.js"; import { TabId } from "./TabId.js"; import { ThemeConfig } from "./ThemeConfig.js"; +import { TranslationConfig } from "./TranslationConfig.js"; import { VersionConfig } from "./VersionConfig.js"; export const DocsConfiguration: core.serialization.ObjectSchema< @@ -60,6 +61,7 @@ export const DocsConfiguration: core.serialization.ObjectSchema< experimental: ExperimentalConfig.optional(), defaultLanguage: core.serialization.property("default-language", ProgrammingLanguage.optional()), languages: core.serialization.list(Language).optional(), + translations: core.serialization.list(TranslationConfig).optional(), aiChat: core.serialization.property("ai-chat", AiChatConfig.optional()), aiSearch: core.serialization.property("ai-search", AiChatConfig.optional()), aiExamples: core.serialization.property("ai-examples", AiExamplesConfig.optional()), @@ -102,6 +104,7 @@ export declare namespace DocsConfiguration { experimental?: ExperimentalConfig.Raw | null; "default-language"?: ProgrammingLanguage.Raw | null; languages?: Language.Raw[] | null; + translations?: TranslationConfig.Raw[] | null; "ai-chat"?: AiChatConfig.Raw | null; "ai-search"?: AiChatConfig.Raw | null; "ai-examples"?: AiExamplesConfig.Raw | null; diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/TranslationConfig.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/TranslationConfig.ts new file mode 100644 index 000000000000..4583e7c56b19 --- /dev/null +++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/TranslationConfig.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as FernDocsConfig from "../../../../api/index.js"; +import * as core from "../../../../core/index.js"; +import type * as serializers from "../../../index.js"; +import { Language } from "./Language.js"; + +export const TranslationConfig: core.serialization.ObjectSchema< + serializers.TranslationConfig.Raw, + FernDocsConfig.TranslationConfig +> = core.serialization.object({ + lang: Language, + default: core.serialization.boolean().optional(), +}); + +export declare namespace TranslationConfig { + export interface Raw { + lang: Language.Raw; + default?: boolean | null; + } +} diff --git a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/index.ts b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/index.ts index cb9371654ddc..92fe869f781a 100644 --- a/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/index.ts +++ b/packages/cli/configuration/src/docs-yml/schemas/sdk/serialization/resources/docs/types/index.ts @@ -134,6 +134,7 @@ export * from "./TabVariant.js"; export * from "./Target.js"; export * from "./ThemeConfig.js"; export * from "./TitleSource.js"; +export * from "./TranslationConfig.js"; export * from "./TwitterCardSetting.js"; export * from "./UntabbedNavigationConfig.js"; export * from "./VersionAvailability.js"; diff --git a/packages/cli/docs-importers/commons/package.json b/packages/cli/docs-importers/commons/package.json index dd1bf087cd6c..0144fb870cd5 100644 --- a/packages/cli/docs-importers/commons/package.json +++ b/packages/cli/docs-importers/commons/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "@fern-api/configuration": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/task-context": "workspace:*", "js-yaml": "catalog:" diff --git a/packages/cli/docs-importers/mintlify/package.json b/packages/cli/docs-importers/mintlify/package.json index 2abc430a2e54..22d0d5d62040 100644 --- a/packages/cli/docs-importers/mintlify/package.json +++ b/packages/cli/docs-importers/mintlify/package.json @@ -35,7 +35,7 @@ "@fern-api/configuration": "workspace:*", "@fern-api/core-utils": "workspace:*", "@fern-api/docs-importer-commons": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/logger": "workspace:*", "@fern-api/task-context": "workspace:*", diff --git a/packages/cli/docs-importers/readme/package.json b/packages/cli/docs-importers/readme/package.json index 885b339ed2de..b332630db465 100644 --- a/packages/cli/docs-importers/readme/package.json +++ b/packages/cli/docs-importers/readme/package.json @@ -35,7 +35,7 @@ "@fern-api/configuration": "workspace:*", "@fern-api/core-utils": "workspace:*", "@fern-api/docs-importer-commons": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/logger": "workspace:*", "@fern-api/task-context": "workspace:*", diff --git a/packages/cli/docs-markdown-utils/package.json b/packages/cli/docs-markdown-utils/package.json index 50637c630040..cfca176e325d 100644 --- a/packages/cli/docs-markdown-utils/package.json +++ b/packages/cli/docs-markdown-utils/package.json @@ -32,7 +32,7 @@ "test:update": "vitest --run -u" }, "dependencies": { - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/task-context": "workspace:*", "estree-walker": "catalog:", diff --git a/packages/cli/docs-preview/package.json b/packages/cli/docs-preview/package.json index e3153b4e42d7..874dbc8c2651 100644 --- a/packages/cli/docs-preview/package.json +++ b/packages/cli/docs-preview/package.json @@ -35,7 +35,7 @@ "@fern-api/core-utils": "workspace:*", "@fern-api/docs-markdown-utils": "workspace:*", "@fern-api/docs-resolver": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/ir-sdk": "workspace:*", "@fern-api/ir-utils": "workspace:*", diff --git a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts index e40a8d5cc996..de9a84a79e19 100644 --- a/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts +++ b/packages/cli/docs-resolver/src/DocsDefinitionResolver.ts @@ -54,6 +54,17 @@ interface LibraryNavNode { children?: LibraryNavNode[]; } +interface DocsTranslationsConfig { + defaultLocale: string; + translations: string[] | undefined; +} + +// TODO: Remove this shim once the published @fern-api/fdr-sdk type for +// DocsV1Write.DocsConfig includes the translations field. +interface DocsConfigWithTranslations extends DocsV1Write.DocsConfig { + translations: DocsTranslationsConfig | undefined; +} + import { ApiReferenceNodeConverter } from "./ApiReferenceNodeConverter.js"; import { ChangelogNodeConverter } from "./ChangelogNodeConverter.js"; import { NodeIdGenerator } from "./NodeIdGenerator.js"; @@ -251,6 +262,47 @@ export class DocsDefinitionResolver { } return this._parsedDocsConfig; } + + /** + * Returns per-locale translated page content loaded from `translations//` directories. + * Must be called after `resolve()`. + */ + public getTranslationPages(): Record> | undefined { + return this._parsedDocsConfig?.translationPages; + } + + /** + * Returns the map of absolute file paths to uploaded file IDs. + * Used by translation processing to rewrite image paths in translated pages. + * Must be called after `resolve()`. + */ + public getCollectedFileIds(): ReadonlyMap { + return this.collectedFileIds; + } + + /** + * Returns the absolute path to the docs workspace (fern folder). + */ + public getDocsWorkspacePath(): AbsoluteFilePath { + return this.docsWorkspace.absoluteFilePath; + } + + private getDocsTranslationsConfig(): DocsConfigWithTranslations["translations"] { + const translations = this.parsedDocsConfig.translations; + if (translations == null || translations.length === 0) { + return undefined; + } + + const defaultTranslation = translations.find((translation) => translation.default === true) ?? translations[0]; + if (defaultTranslation == null) { + return undefined; + } + + return { + defaultLocale: defaultTranslation.lang, + translations: translations.map((translation) => translation.lang) + }; + } private collectedFileIds = new Map(); private markdownFilesToFullSlugs: Map = new Map(); private markdownFilesToSidebarTitle: Map = new Map(); @@ -752,13 +804,16 @@ export class DocsDefinitionResolver { context7: this.getFileId(this.parsedDocsConfig.context7File) } as DocsV1Write.DocsConfig["integrations"]) : undefined; - const config: DocsV1Write.DocsConfig = { + const config: DocsConfigWithTranslations = { aiChatConfig: this.parsedDocsConfig.aiChatConfig != null ? { model: this.parsedDocsConfig.aiChatConfig.model, systemPrompt: this.parsedDocsConfig.aiChatConfig.systemPrompt, - location: this.parsedDocsConfig.aiChatConfig.location, + // Filter out 'discord' which is no longer supported by fdr-sdk + location: this.parsedDocsConfig.aiChatConfig.location?.filter( + (loc): loc is "slack" | "docs" => loc === "slack" || loc === "docs" + ), datasources: this.parsedDocsConfig.aiChatConfig.datasources?.map((ds) => ({ url: ds.url, title: ds.title @@ -808,7 +863,6 @@ export class DocsDefinitionResolver { settings: this.parsedDocsConfig.settings, css: this.parsedDocsConfig.css, js: this.convertJavascriptConfiguration(), - // @ts-expect-error - Remove this when the fdr-sdk upgraded to the latest version agents: this.parsedDocsConfig.agents != null || this.parsedDocsConfig.llmsTxtFile != null || @@ -828,6 +882,8 @@ export class DocsDefinitionResolver { })), defaultLanguage: this.parsedDocsConfig.defaultLanguage, languages: this.parsedDocsConfig.languages, + + translations: this.getDocsTranslationsConfig(), analyticsConfig: { ...this.parsedDocsConfig.analyticsConfig, segment: this.parsedDocsConfig.analyticsConfig?.segment, diff --git a/packages/cli/docs-resolver/src/__test__/applyTranslatedFrontmatterToNavTree.test.ts b/packages/cli/docs-resolver/src/__test__/applyTranslatedFrontmatterToNavTree.test.ts new file mode 100644 index 000000000000..b73e9ebc0c71 --- /dev/null +++ b/packages/cli/docs-resolver/src/__test__/applyTranslatedFrontmatterToNavTree.test.ts @@ -0,0 +1,263 @@ +import { FernNavigation } from "@fern-api/fdr-sdk"; +import { describe, expect, it } from "vitest"; + +import { applyTranslatedFrontmatterToNavTree } from "../applyTranslatedFrontmatterToNavTree.js"; + +// Helper to cast test objects to RootNode +function asRoot(obj: unknown): FernNavigation.V1.RootNode { + return obj as FernNavigation.V1.RootNode; +} + +// Helper to access nested properties on result +function getChild(result: FernNavigation.V1.RootNode | undefined): Record { + return (result as unknown as { child: Record }).child; +} + +describe("applyTranslatedFrontmatterToNavTree", () => { + it("returns undefined when root is undefined", () => { + const result = applyTranslatedFrontmatterToNavTree(undefined, {}); + expect(result).toBeUndefined(); + }); + + it("returns original root when no translated pages", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/getting-started.mdx", + title: "Getting Started", + slug: "getting-started" + } + }; + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), {}); + expect(result).toEqual(root); + }); + + it("applies sidebar-title override to matching page", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/getting-started.mdx", + title: "Getting Started", + slug: "getting-started" + } + }; + const translatedPages = { + "pages/getting-started.mdx": `--- +sidebar-title: Premiers pas +--- +# Premiers pas` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + + expect(result).toEqual({ + type: "root", + child: { + type: "page", + pageId: "pages/getting-started.mdx", + title: "Premiers pas", + slug: "getting-started" + } + }); + }); + + it("does not override title when no sidebar-title in frontmatter", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/intro.mdx", + title: "Introduction", + slug: "intro" + } + }; + const translatedPages = { + "pages/intro.mdx": `# Translated content without frontmatter` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + + expect(result).toEqual(root); + }); + + it("handles nested navigation structure", () => { + const root = { + type: "root" as const, + child: { + type: "section" as const, + title: "SDK", + children: [ + { + type: "page" as const, + pageId: "pages/sdk/overview.mdx", + title: "Overview", + slug: "sdk/overview" + }, + { + type: "page" as const, + pageId: "pages/sdk/install.mdx", + title: "Installation", + slug: "sdk/install" + } + ] + } + }; + const translatedPages = { + "pages/sdk/overview.mdx": `--- +sidebar-title: Vue d'ensemble +---`, + "pages/sdk/install.mdx": `--- +sidebar-title: Installation +---` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + const child = getChild(result); + const children = child.children as Array<{ title: string }>; + + expect(children[0]?.title).toBe("Vue d'ensemble"); + expect(children[1]?.title).toBe("Installation"); + }); + + it("ignores pages that don't match any node in the tree", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/intro.mdx", + title: "Introduction", + slug: "intro" + } + }; + const translatedPages = { + "pages/nonexistent.mdx": `--- +sidebar-title: Should be ignored +---` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + + expect(result).toEqual(root); + }); + + it("handles empty sidebar-title gracefully", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/test.mdx", + title: "Test", + slug: "test" + } + }; + const translatedPages = { + "pages/test.mdx": `--- +sidebar-title: "" +---` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + + // Empty sidebar-title should not override + expect(getChild(result).title).toBe("Test"); + }); + + it("trims whitespace from sidebar-title", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/test.mdx", + title: "Test", + slug: "test" + } + }; + const translatedPages = { + "pages/test.mdx": `--- +sidebar-title: " Prueba " +---` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + + expect(getChild(result).title).toBe("Prueba"); + }); + + it("handles invalid frontmatter gracefully", () => { + const root = { + type: "root" as const, + child: { + type: "page" as const, + pageId: "pages/test.mdx", + title: "Test", + slug: "test" + } + }; + const translatedPages = { + "pages/test.mdx": `--- +invalid yaml: [ +--- +# Content` + }; + + // Should not throw, just return original structure + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + expect(getChild(result).title).toBe("Test"); + }); + + it("applies sidebar-title override to section nodes with overviewPageId", () => { + const root = { + type: "root" as const, + child: { + type: "section" as const, + title: "SDK Guide", + overviewPageId: "pages/sdk/overview.mdx", + slug: "sdk", + children: [ + { + type: "page" as const, + pageId: "pages/sdk/install.mdx", + title: "Installation", + slug: "sdk/install" + } + ] + } + }; + const translatedPages = { + "pages/sdk/overview.mdx": `--- +sidebar-title: Guide du SDK +--- +# Guide du SDK` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + const child = getChild(result); + const children = child.children as Array<{ title: string }>; + + expect(child.title).toBe("Guide du SDK"); + // Child page title should remain unchanged + expect(children[0]?.title).toBe("Installation"); + }); + + it("does not override section title when overview page has no sidebar-title", () => { + const root = { + type: "root" as const, + child: { + type: "section" as const, + title: "API Reference", + overviewPageId: "pages/api/index.mdx", + slug: "api", + children: [] + } + }; + const translatedPages = { + "pages/api/index.mdx": `# API Reference content without frontmatter` + }; + + const result = applyTranslatedFrontmatterToNavTree(asRoot(root), translatedPages); + + expect(getChild(result).title).toBe("API Reference"); + }); +}); diff --git a/packages/cli/docs-resolver/src/__test__/translations-config.test.ts b/packages/cli/docs-resolver/src/__test__/translations-config.test.ts new file mode 100644 index 000000000000..39c98bbc77f9 --- /dev/null +++ b/packages/cli/docs-resolver/src/__test__/translations-config.test.ts @@ -0,0 +1,107 @@ +import { describe, expect, it } from "vitest"; + +import { DocsDefinitionResolver } from "../DocsDefinitionResolver.js"; + +interface DocsTranslationsConfig { + defaultLocale: string; + translations: string[] | undefined; +} + +interface DocsConfigWithTranslations { + translations: DocsTranslationsConfig | undefined; +} + +function createResolverWithTranslations( + translations: Array<{ + lang: string; + default?: boolean; + }> +): DocsDefinitionResolver { + const resolver = Object.create(DocsDefinitionResolver.prototype) as DocsDefinitionResolver; + + Reflect.set(resolver, "_parsedDocsConfig", { + aiChatConfig: undefined, + agents: undefined, + analyticsConfig: undefined, + announcement: undefined, + backgroundImage: undefined, + colors: undefined, + context7File: undefined, + css: undefined, + defaultLanguage: undefined, + experimental: undefined, + favicon: undefined, + footer: undefined, + footerLinks: undefined, + header: undefined, + integrations: undefined, + js: undefined, + languages: undefined, + landingPage: undefined, + layout: undefined, + libraries: undefined, + llmsFullTxtFile: undefined, + llmsTxtFile: undefined, + logo: undefined, + metadata: undefined, + navbarLinks: undefined, + navigation: undefined, + pageActions: undefined, + pages: {}, + redirects: undefined, + roles: undefined, + settings: undefined, + theme: undefined, + title: undefined, + translationPages: undefined, + translations: translations.map((translation) => ({ + // The resolver only reads `lang` and `default`. + lang: translation.lang, + default: translation.default + })), + typography: undefined + }); + Reflect.set(resolver, "collectedFileIds", new Map()); + Reflect.set(resolver, "editThisPage", undefined); + + return resolver; +} + +function getTranslationsConfig(config: object): DocsTranslationsConfig | undefined { + if ("translations" in config) { + return (config as DocsConfigWithTranslations).translations; + } + return undefined; +} + +describe("DocsDefinitionResolver translations config", () => { + it("includes translation metadata in the resolved docs config", async () => { + const resolver = createResolverWithTranslations([{ lang: "en", default: true }, { lang: "ja" }]); + + const convertDocsConfiguration = Reflect.get(resolver, "convertDocsConfiguration") as ( + root: object + ) => Promise; + + const config = await convertDocsConfiguration.call(resolver, { type: "root" }); + + expect(getTranslationsConfig(config)).toEqual({ + defaultLocale: "en", + translations: ["en", "ja"] + }); + }); + + it("falls back to the first locale when no default is explicitly configured", async () => { + const resolver = createResolverWithTranslations([{ lang: "fr" }, { lang: "de" }]); + + const convertDocsConfiguration = Reflect.get(resolver, "convertDocsConfiguration") as ( + root: object + ) => Promise; + + const config = await convertDocsConfiguration.call(resolver, { type: "root" }); + + expect(getTranslationsConfig(config)).toEqual({ + defaultLocale: "fr", + translations: ["fr", "de"] + }); + }); +}); diff --git a/packages/cli/docs-resolver/src/applyTranslatedFrontmatterToNavTree.ts b/packages/cli/docs-resolver/src/applyTranslatedFrontmatterToNavTree.ts new file mode 100644 index 000000000000..ccb8490fae7c --- /dev/null +++ b/packages/cli/docs-resolver/src/applyTranslatedFrontmatterToNavTree.ts @@ -0,0 +1,111 @@ +import { FernNavigation } from "@fern-api/fdr-sdk"; +import { TaskContext } from "@fern-api/task-context"; +import matter from "gray-matter"; + +interface FrontmatterOverride { + sidebarTitle?: string; + // TODO(translations-alpha): slug overrides are not yet supported because PageNode.slug + // is a fully-qualified path that requires proper composition with parent slugs. +} + +interface ParseResult { + override: FrontmatterOverride; + error?: string; +} + +function parseFrontmatterOverrides(markdown: string): ParseResult { + try { + const { data } = matter(markdown); + const result: FrontmatterOverride = {}; + const sidebarTitle = data["sidebar-title"]; + if (typeof sidebarTitle === "string" && sidebarTitle.trim().length > 0) { + result.sidebarTitle = sidebarTitle.trim(); + } + // TODO(translations-alpha): slug parsing removed until proper composition is implemented + return { override: result }; + } catch (e) { + return { override: {}, error: e instanceof Error ? e.message : String(e) }; + } +} + +/** + * Walks the navigation tree and applies sidebar-title overrides from + * translated page frontmatter. The CLI calls this before sending a translated + * DocsDefinition to FDR so that the server receives a fully-computed nav tree. + * + * Note: slug overrides are not yet supported because PageNode.slug is a fully-qualified + * path that requires proper composition with parent slugs. + * + * @param root - the base navigation tree (from the original docsDefinition) + * @param translatedPages - map of pageId (relative file path) to translated markdown + * @param context - optional task context for logging parse errors + */ +export function applyTranslatedFrontmatterToNavTree( + root: FernNavigation.V1.RootNode | undefined, + translatedPages: Record, + context?: TaskContext +): FernNavigation.V1.RootNode | undefined { + if (root == null) { + return undefined; + } + + // Build a map of pageId -> frontmatter overrides (only for pages that have overrides) + const overrides = new Map(); + for (const [pageId, markdown] of Object.entries(translatedPages)) { + const { override, error } = parseFrontmatterOverrides(markdown); + if (error != null) { + context?.logger.warn( + `Failed to parse frontmatter in translated page "${pageId}": ${error}. ` + + `Sidebar title override will be skipped.` + ); + } + if (override.sidebarTitle != null) { + overrides.set(pageId, override); + } + } + + if (overrides.size === 0) { + return root; + } + + return walkNode(root, overrides) as FernNavigation.V1.RootNode; +} + +function walkNode(node: unknown, overrides: Map): unknown { + if (node == null || typeof node !== "object") { + return node; + } + if (Array.isArray(node)) { + return node.map((item) => walkNode(item, overrides)); + } + + const obj = node as Record; + const updated: Record = {}; + for (const [k, v] of Object.entries(obj)) { + updated[k] = walkNode(v, overrides); + } + + // Apply overrides to page nodes that match a translated page + if (updated["type"] === "page" && typeof updated["pageId"] === "string") { + const override = overrides.get(updated["pageId"]); + if (override != null) { + if (override.sidebarTitle != null) { + updated["title"] = override.sidebarTitle; + } + // TODO(translations-alpha): Slug overrides are intentionally skipped for now. + // PageNode.slug is a fully-qualified path (e.g. "fr/sdks/getting-started"), + // but frontmatter slug is just a leaf segment. Composing them properly requires + // extracting the SlugGenerator logic from DocsDefinitionResolver. + } + } + + // Apply overrides to section nodes with an overview page that matches a translated page + if (updated["type"] === "section" && typeof updated["overviewPageId"] === "string") { + const override = overrides.get(updated["overviewPageId"]); + if (override != null && override.sidebarTitle != null) { + updated["title"] = override.sidebarTitle; + } + } + + return updated; +} diff --git a/packages/cli/docs-resolver/src/index.ts b/packages/cli/docs-resolver/src/index.ts index 01b21fedfc26..cd0e0d1762c2 100644 --- a/packages/cli/docs-resolver/src/index.ts +++ b/packages/cli/docs-resolver/src/index.ts @@ -1,3 +1,6 @@ +// Re-export markdown utilities needed for translation processing +export { replaceImagePathsAndUrls, stripMdxComments } from "@fern-api/docs-markdown-utils"; +export { applyTranslatedFrontmatterToNavTree } from "./applyTranslatedFrontmatterToNavTree.js"; export { DocsDefinitionResolver, type UploadedFile } from "./DocsDefinitionResolver.js"; export { stitchGlobalTheme } from "./stitchGlobalTheme.js"; export { convertIrToApiDefinition } from "./utils/convertIrToApiDefinition.js"; diff --git a/packages/cli/ete-tests/package.json b/packages/cli/ete-tests/package.json index 65f9a86fd166..dbe1f03bbdb0 100644 --- a/packages/cli/ete-tests/package.json +++ b/packages/cli/ete-tests/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@fern-api/configuration": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/lazy-fern-workspace": "workspace:*", "@fern-api/logger": "workspace:*", diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_ConversationHistoryMessage.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_ConversationHistoryMessage.json new file mode 100644 index 000000000000..6c445677404f --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_ConversationHistoryMessage.json @@ -0,0 +1,21 @@ +{ + "type": "object", + "properties": { + "type": { + "const": "History" + }, + "role": { + "type": "string" + }, + "content": { + "type": "string" + } + }, + "required": [ + "type", + "role", + "content" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_ConversationTextMessage.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_ConversationTextMessage.json new file mode 100644 index 000000000000..7bb5f4eb1967 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_ConversationTextMessage.json @@ -0,0 +1,21 @@ +{ + "type": "object", + "properties": { + "type": { + "const": "ConversationText" + }, + "text": { + "type": "string" + }, + "confidence": { + "type": "number" + } + }, + "required": [ + "type", + "text", + "confidence" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_FunctionCall.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_FunctionCall.json new file mode 100644 index 000000000000..19bdc7762ae2 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_FunctionCall.json @@ -0,0 +1,21 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "arguments": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_FunctionCallHistoryMessage.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_FunctionCallHistoryMessage.json new file mode 100644 index 000000000000..f2f8218871d6 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_FunctionCallHistoryMessage.json @@ -0,0 +1,41 @@ +{ + "type": "object", + "properties": { + "type": { + "const": "History" + }, + "function_calls": { + "type": "array", + "items": { + "$ref": "#/definitions/realtime.FunctionCall" + } + } + }, + "required": [ + "type", + "function_calls" + ], + "additionalProperties": false, + "definitions": { + "realtime.FunctionCall": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "arguments": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "arguments" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_SendEvent.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_SendEvent.json new file mode 100644 index 000000000000..b72d70df98dc --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/java-websocket-shared-discriminator/type_realtime_SendEvent.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": [ + "text" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasToLeafB.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasToLeafB.json new file mode 100644 index 000000000000..a6f450447787 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasToLeafB.json @@ -0,0 +1,17 @@ +{ + "$ref": "#/definitions/union.LeafObjectB", + "definitions": { + "union.LeafObjectB": { + "type": "object", + "properties": { + "onlyInB": { + "type": "string" + } + }, + "required": [ + "onlyInB" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedLeafA.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedLeafA.json new file mode 100644 index 000000000000..58b62fd1411d --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedLeafA.json @@ -0,0 +1,21 @@ +{ + "$ref": "#/definitions/union.LeafObjectA", + "definitions": { + "union.LeafObjectA": { + "type": "object", + "properties": { + "onlyInA": { + "type": "string" + }, + "sharedNumber": { + "type": "integer" + } + }, + "required": [ + "onlyInA", + "sharedNumber" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedLeafB.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedLeafB.json new file mode 100644 index 000000000000..53334755b486 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedLeafB.json @@ -0,0 +1,20 @@ +{ + "$ref": "#/definitions/union.AliasToLeafB", + "definitions": { + "union.LeafObjectB": { + "type": "object", + "properties": { + "onlyInB": { + "type": "string" + } + }, + "required": [ + "onlyInB" + ], + "additionalProperties": false + }, + "union.AliasToLeafB": { + "$ref": "#/definitions/union.LeafObjectB" + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedObjectUnion.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedObjectUnion.json new file mode 100644 index 000000000000..6e2b145ae741 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_AliasedObjectUnion.json @@ -0,0 +1,49 @@ +{ + "anyOf": [ + { + "$ref": "#/definitions/union.AliasedLeafA" + }, + { + "$ref": "#/definitions/union.AliasedLeafB" + } + ], + "definitions": { + "union.LeafObjectA": { + "type": "object", + "properties": { + "onlyInA": { + "type": "string" + }, + "sharedNumber": { + "type": "integer" + } + }, + "required": [ + "onlyInA", + "sharedNumber" + ], + "additionalProperties": false + }, + "union.AliasedLeafA": { + "$ref": "#/definitions/union.LeafObjectA" + }, + "union.LeafObjectB": { + "type": "object", + "properties": { + "onlyInB": { + "type": "string" + } + }, + "required": [ + "onlyInB" + ], + "additionalProperties": false + }, + "union.AliasToLeafB": { + "$ref": "#/definitions/union.LeafObjectB" + }, + "union.AliasedLeafB": { + "$ref": "#/definitions/union.AliasToLeafB" + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafObjectA.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafObjectA.json new file mode 100644 index 000000000000..ec0ea7973b8c --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafObjectA.json @@ -0,0 +1,17 @@ +{ + "type": "object", + "properties": { + "onlyInA": { + "type": "string" + }, + "sharedNumber": { + "type": "integer" + } + }, + "required": [ + "onlyInA", + "sharedNumber" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafObjectB.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafObjectB.json new file mode 100644 index 000000000000..51795e231ba0 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafObjectB.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "onlyInB": { + "type": "string" + } + }, + "required": [ + "onlyInB" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafTypeA.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafTypeA.json new file mode 100644 index 000000000000..efcd7db5cea7 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafTypeA.json @@ -0,0 +1,17 @@ +{ + "type": "object", + "properties": { + "alpha": { + "type": "string" + }, + "beta": { + "type": "integer" + } + }, + "required": [ + "alpha", + "beta" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafTypeB.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafTypeB.json new file mode 100644 index 000000000000..caff0cfd38ca --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_LeafTypeB.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "gamma": { + "type": "string" + } + }, + "required": [ + "gamma" + ], + "additionalProperties": false, + "definitions": {} +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_NestedObjectUnion.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_NestedObjectUnion.json new file mode 100644 index 000000000000..794b1b87d2d4 --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_NestedObjectUnion.json @@ -0,0 +1,40 @@ +{ + "anyOf": [ + { + "$ref": "#/definitions/union.LeafTypeA" + }, + { + "$ref": "#/definitions/union.LeafTypeB" + } + ], + "definitions": { + "union.LeafTypeA": { + "type": "object", + "properties": { + "alpha": { + "type": "string" + }, + "beta": { + "type": "integer" + } + }, + "required": [ + "alpha", + "beta" + ], + "additionalProperties": false + }, + "union.LeafTypeB": { + "type": "object", + "properties": { + "gamma": { + "type": "string" + } + }, + "required": [ + "gamma" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_OuterNestedUnion.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_OuterNestedUnion.json new file mode 100644 index 000000000000..16aebd0ad86b --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_OuterNestedUnion.json @@ -0,0 +1,66 @@ +{ + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/union.WrapperObject" + } + ], + "definitions": { + "union.LeafTypeA": { + "type": "object", + "properties": { + "alpha": { + "type": "string" + }, + "beta": { + "type": "integer" + } + }, + "required": [ + "alpha", + "beta" + ], + "additionalProperties": false + }, + "union.LeafTypeB": { + "type": "object", + "properties": { + "gamma": { + "type": "string" + } + }, + "required": [ + "gamma" + ], + "additionalProperties": false + }, + "union.NestedObjectUnion": { + "anyOf": [ + { + "$ref": "#/definitions/union.LeafTypeA" + }, + { + "$ref": "#/definitions/union.LeafTypeB" + } + ] + }, + "union.WrapperObject": { + "type": "object", + "properties": { + "inner": { + "$ref": "#/definitions/union.NestedObjectUnion" + }, + "label": { + "type": "string" + } + }, + "required": [ + "inner", + "label" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_WrapperObject.json b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_WrapperObject.json new file mode 100644 index 000000000000..ab0a4232d75f --- /dev/null +++ b/packages/cli/fern-definition/ir-to-jsonschema/src/__test__/__snapshots__/undiscriminated-unions/type_union_WrapperObject.json @@ -0,0 +1,56 @@ +{ + "type": "object", + "properties": { + "inner": { + "$ref": "#/definitions/union.NestedObjectUnion" + }, + "label": { + "type": "string" + } + }, + "required": [ + "inner", + "label" + ], + "additionalProperties": false, + "definitions": { + "union.LeafTypeA": { + "type": "object", + "properties": { + "alpha": { + "type": "string" + }, + "beta": { + "type": "integer" + } + }, + "required": [ + "alpha", + "beta" + ], + "additionalProperties": false + }, + "union.LeafTypeB": { + "type": "object", + "properties": { + "gamma": { + "type": "string" + } + }, + "required": [ + "gamma" + ], + "additionalProperties": false + }, + "union.NestedObjectUnion": { + "anyOf": [ + { + "$ref": "#/definitions/union.LeafTypeA" + }, + { + "$ref": "#/definitions/union.LeafTypeB" + } + ] + } + } +} \ No newline at end of file diff --git a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/java-websocket-shared-discriminator.json b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/java-websocket-shared-discriminator.json new file mode 100644 index 000000000000..15c77c67972b --- /dev/null +++ b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/java-websocket-shared-discriminator.json @@ -0,0 +1,738 @@ +{ + "version": "1.0.0", + "types": { + "type_realtime:SendEvent": { + "type": "object", + "declaration": { + "name": { + "originalName": "SendEvent", + "camelCase": { + "unsafeName": "sendEvent", + "safeName": "sendEvent" + }, + "snakeCase": { + "unsafeName": "send_event", + "safeName": "send_event" + }, + "screamingSnakeCase": { + "unsafeName": "SEND_EVENT", + "safeName": "SEND_EVENT" + }, + "pascalCase": { + "unsafeName": "SendEvent", + "safeName": "SendEvent" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "text", + "name": { + "originalName": "text", + "camelCase": { + "unsafeName": "text", + "safeName": "text" + }, + "snakeCase": { + "unsafeName": "text", + "safeName": "text" + }, + "screamingSnakeCase": { + "unsafeName": "TEXT", + "safeName": "TEXT" + }, + "pascalCase": { + "unsafeName": "Text", + "safeName": "Text" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:ConversationHistoryMessage": { + "type": "object", + "declaration": { + "name": { + "originalName": "ConversationHistoryMessage", + "camelCase": { + "unsafeName": "conversationHistoryMessage", + "safeName": "conversationHistoryMessage" + }, + "snakeCase": { + "unsafeName": "conversation_history_message", + "safeName": "conversation_history_message" + }, + "screamingSnakeCase": { + "unsafeName": "CONVERSATION_HISTORY_MESSAGE", + "safeName": "CONVERSATION_HISTORY_MESSAGE" + }, + "pascalCase": { + "unsafeName": "ConversationHistoryMessage", + "safeName": "ConversationHistoryMessage" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "type", + "name": { + "originalName": "type", + "camelCase": { + "unsafeName": "type", + "safeName": "type" + }, + "snakeCase": { + "unsafeName": "type", + "safeName": "type" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE", + "safeName": "TYPE" + }, + "pascalCase": { + "unsafeName": "Type", + "safeName": "Type" + } + } + }, + "typeReference": { + "type": "literal", + "value": { + "type": "string", + "value": "History" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "role", + "name": { + "originalName": "role", + "camelCase": { + "unsafeName": "role", + "safeName": "role" + }, + "snakeCase": { + "unsafeName": "role", + "safeName": "role" + }, + "screamingSnakeCase": { + "unsafeName": "ROLE", + "safeName": "ROLE" + }, + "pascalCase": { + "unsafeName": "Role", + "safeName": "Role" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "content", + "name": { + "originalName": "content", + "camelCase": { + "unsafeName": "content", + "safeName": "content" + }, + "snakeCase": { + "unsafeName": "content", + "safeName": "content" + }, + "screamingSnakeCase": { + "unsafeName": "CONTENT", + "safeName": "CONTENT" + }, + "pascalCase": { + "unsafeName": "Content", + "safeName": "Content" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:FunctionCallHistoryMessage": { + "type": "object", + "declaration": { + "name": { + "originalName": "FunctionCallHistoryMessage", + "camelCase": { + "unsafeName": "functionCallHistoryMessage", + "safeName": "functionCallHistoryMessage" + }, + "snakeCase": { + "unsafeName": "function_call_history_message", + "safeName": "function_call_history_message" + }, + "screamingSnakeCase": { + "unsafeName": "FUNCTION_CALL_HISTORY_MESSAGE", + "safeName": "FUNCTION_CALL_HISTORY_MESSAGE" + }, + "pascalCase": { + "unsafeName": "FunctionCallHistoryMessage", + "safeName": "FunctionCallHistoryMessage" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "type", + "name": { + "originalName": "type", + "camelCase": { + "unsafeName": "type", + "safeName": "type" + }, + "snakeCase": { + "unsafeName": "type", + "safeName": "type" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE", + "safeName": "TYPE" + }, + "pascalCase": { + "unsafeName": "Type", + "safeName": "Type" + } + } + }, + "typeReference": { + "type": "literal", + "value": { + "type": "string", + "value": "History" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "function_calls", + "name": { + "originalName": "function_calls", + "camelCase": { + "unsafeName": "functionCalls", + "safeName": "functionCalls" + }, + "snakeCase": { + "unsafeName": "function_calls", + "safeName": "function_calls" + }, + "screamingSnakeCase": { + "unsafeName": "FUNCTION_CALLS", + "safeName": "FUNCTION_CALLS" + }, + "pascalCase": { + "unsafeName": "FunctionCalls", + "safeName": "FunctionCalls" + } + } + }, + "typeReference": { + "type": "list", + "value": { + "type": "named", + "value": "type_realtime:FunctionCall" + } + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:ConversationTextMessage": { + "type": "object", + "declaration": { + "name": { + "originalName": "ConversationTextMessage", + "camelCase": { + "unsafeName": "conversationTextMessage", + "safeName": "conversationTextMessage" + }, + "snakeCase": { + "unsafeName": "conversation_text_message", + "safeName": "conversation_text_message" + }, + "screamingSnakeCase": { + "unsafeName": "CONVERSATION_TEXT_MESSAGE", + "safeName": "CONVERSATION_TEXT_MESSAGE" + }, + "pascalCase": { + "unsafeName": "ConversationTextMessage", + "safeName": "ConversationTextMessage" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "type", + "name": { + "originalName": "type", + "camelCase": { + "unsafeName": "type", + "safeName": "type" + }, + "snakeCase": { + "unsafeName": "type", + "safeName": "type" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE", + "safeName": "TYPE" + }, + "pascalCase": { + "unsafeName": "Type", + "safeName": "Type" + } + } + }, + "typeReference": { + "type": "literal", + "value": { + "type": "string", + "value": "ConversationText" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "text", + "name": { + "originalName": "text", + "camelCase": { + "unsafeName": "text", + "safeName": "text" + }, + "snakeCase": { + "unsafeName": "text", + "safeName": "text" + }, + "screamingSnakeCase": { + "unsafeName": "TEXT", + "safeName": "TEXT" + }, + "pascalCase": { + "unsafeName": "Text", + "safeName": "Text" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "confidence", + "name": { + "originalName": "confidence", + "camelCase": { + "unsafeName": "confidence", + "safeName": "confidence" + }, + "snakeCase": { + "unsafeName": "confidence", + "safeName": "confidence" + }, + "screamingSnakeCase": { + "unsafeName": "CONFIDENCE", + "safeName": "CONFIDENCE" + }, + "pascalCase": { + "unsafeName": "Confidence", + "safeName": "Confidence" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "DOUBLE" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:FunctionCall": { + "type": "object", + "declaration": { + "name": { + "originalName": "FunctionCall", + "camelCase": { + "unsafeName": "functionCall", + "safeName": "functionCall" + }, + "snakeCase": { + "unsafeName": "function_call", + "safeName": "function_call" + }, + "screamingSnakeCase": { + "unsafeName": "FUNCTION_CALL", + "safeName": "FUNCTION_CALL" + }, + "pascalCase": { + "unsafeName": "FunctionCall", + "safeName": "FunctionCall" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "id", + "name": { + "originalName": "id", + "camelCase": { + "unsafeName": "id", + "safeName": "id" + }, + "snakeCase": { + "unsafeName": "id", + "safeName": "id" + }, + "screamingSnakeCase": { + "unsafeName": "ID", + "safeName": "ID" + }, + "pascalCase": { + "unsafeName": "ID", + "safeName": "ID" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "name", + "name": { + "originalName": "name", + "camelCase": { + "unsafeName": "name", + "safeName": "name" + }, + "snakeCase": { + "unsafeName": "name", + "safeName": "name" + }, + "screamingSnakeCase": { + "unsafeName": "NAME", + "safeName": "NAME" + }, + "pascalCase": { + "unsafeName": "Name", + "safeName": "Name" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "arguments", + "name": { + "originalName": "arguments", + "camelCase": { + "unsafeName": "arguments", + "safeName": "arguments" + }, + "snakeCase": { + "unsafeName": "arguments", + "safeName": "arguments" + }, + "screamingSnakeCase": { + "unsafeName": "ARGUMENTS", + "safeName": "ARGUMENTS" + }, + "pascalCase": { + "unsafeName": "Arguments", + "safeName": "Arguments" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + } + }, + "headers": [], + "endpoints": {}, + "pathParameters": [], + "environments": null, + "variables": null, + "generatorConfig": null +} \ No newline at end of file diff --git a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/undiscriminated-unions.json b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/undiscriminated-unions.json index 270b08baa590..c266f31ac55d 100644 --- a/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/undiscriminated-unions.json +++ b/packages/cli/generation/ir-generator-tests/src/dynamic-snippets/__test__/test-definitions/undiscriminated-unions.json @@ -2114,6 +2114,1045 @@ "value": "type_union:Name" } ] + }, + "type_union:LeafTypeA": { + "type": "object", + "declaration": { + "name": { + "originalName": "LeafTypeA", + "camelCase": { + "unsafeName": "leafTypeA", + "safeName": "leafTypeA" + }, + "snakeCase": { + "unsafeName": "leaf_type_a", + "safeName": "leaf_type_a" + }, + "screamingSnakeCase": { + "unsafeName": "LEAF_TYPE_A", + "safeName": "LEAF_TYPE_A" + }, + "pascalCase": { + "unsafeName": "LeafTypeA", + "safeName": "LeafTypeA" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "alpha", + "name": { + "originalName": "alpha", + "camelCase": { + "unsafeName": "alpha", + "safeName": "alpha" + }, + "snakeCase": { + "unsafeName": "alpha", + "safeName": "alpha" + }, + "screamingSnakeCase": { + "unsafeName": "ALPHA", + "safeName": "ALPHA" + }, + "pascalCase": { + "unsafeName": "Alpha", + "safeName": "Alpha" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "beta", + "name": { + "originalName": "beta", + "camelCase": { + "unsafeName": "beta", + "safeName": "beta" + }, + "snakeCase": { + "unsafeName": "beta", + "safeName": "beta" + }, + "screamingSnakeCase": { + "unsafeName": "BETA", + "safeName": "BETA" + }, + "pascalCase": { + "unsafeName": "Beta", + "safeName": "Beta" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "INTEGER" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:LeafTypeB": { + "type": "object", + "declaration": { + "name": { + "originalName": "LeafTypeB", + "camelCase": { + "unsafeName": "leafTypeB", + "safeName": "leafTypeB" + }, + "snakeCase": { + "unsafeName": "leaf_type_b", + "safeName": "leaf_type_b" + }, + "screamingSnakeCase": { + "unsafeName": "LEAF_TYPE_B", + "safeName": "LEAF_TYPE_B" + }, + "pascalCase": { + "unsafeName": "LeafTypeB", + "safeName": "LeafTypeB" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "gamma", + "name": { + "originalName": "gamma", + "camelCase": { + "unsafeName": "gamma", + "safeName": "gamma" + }, + "snakeCase": { + "unsafeName": "gamma", + "safeName": "gamma" + }, + "screamingSnakeCase": { + "unsafeName": "GAMMA", + "safeName": "GAMMA" + }, + "pascalCase": { + "unsafeName": "Gamma", + "safeName": "Gamma" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:NestedObjectUnion": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "NestedObjectUnion", + "camelCase": { + "unsafeName": "nestedObjectUnion", + "safeName": "nestedObjectUnion" + }, + "snakeCase": { + "unsafeName": "nested_object_union", + "safeName": "nested_object_union" + }, + "screamingSnakeCase": { + "unsafeName": "NESTED_OBJECT_UNION", + "safeName": "NESTED_OBJECT_UNION" + }, + "pascalCase": { + "unsafeName": "NestedObjectUnion", + "safeName": "NestedObjectUnion" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "types": [ + { + "type": "named", + "value": "type_union:LeafTypeA" + }, + { + "type": "named", + "value": "type_union:LeafTypeB" + } + ] + }, + "type_union:WrapperObject": { + "type": "object", + "declaration": { + "name": { + "originalName": "WrapperObject", + "camelCase": { + "unsafeName": "wrapperObject", + "safeName": "wrapperObject" + }, + "snakeCase": { + "unsafeName": "wrapper_object", + "safeName": "wrapper_object" + }, + "screamingSnakeCase": { + "unsafeName": "WRAPPER_OBJECT", + "safeName": "WRAPPER_OBJECT" + }, + "pascalCase": { + "unsafeName": "WrapperObject", + "safeName": "WrapperObject" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "inner", + "name": { + "originalName": "inner", + "camelCase": { + "unsafeName": "inner", + "safeName": "inner" + }, + "snakeCase": { + "unsafeName": "inner", + "safeName": "inner" + }, + "screamingSnakeCase": { + "unsafeName": "INNER", + "safeName": "INNER" + }, + "pascalCase": { + "unsafeName": "Inner", + "safeName": "Inner" + } + } + }, + "typeReference": { + "type": "named", + "value": "type_union:NestedObjectUnion" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "label", + "name": { + "originalName": "label", + "camelCase": { + "unsafeName": "label", + "safeName": "label" + }, + "snakeCase": { + "unsafeName": "label", + "safeName": "label" + }, + "screamingSnakeCase": { + "unsafeName": "LABEL", + "safeName": "LABEL" + }, + "pascalCase": { + "unsafeName": "Label", + "safeName": "Label" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:OuterNestedUnion": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "OuterNestedUnion", + "camelCase": { + "unsafeName": "outerNestedUnion", + "safeName": "outerNestedUnion" + }, + "snakeCase": { + "unsafeName": "outer_nested_union", + "safeName": "outer_nested_union" + }, + "screamingSnakeCase": { + "unsafeName": "OUTER_NESTED_UNION", + "safeName": "OUTER_NESTED_UNION" + }, + "pascalCase": { + "unsafeName": "OuterNestedUnion", + "safeName": "OuterNestedUnion" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "types": [ + { + "type": "primitive", + "value": "STRING" + }, + { + "type": "named", + "value": "type_union:WrapperObject" + } + ] + }, + "type_union:AliasedLeafA": { + "type": "alias", + "declaration": { + "name": { + "originalName": "AliasedLeafA", + "camelCase": { + "unsafeName": "aliasedLeafA", + "safeName": "aliasedLeafA" + }, + "snakeCase": { + "unsafeName": "aliased_leaf_a", + "safeName": "aliased_leaf_a" + }, + "screamingSnakeCase": { + "unsafeName": "ALIASED_LEAF_A", + "safeName": "ALIASED_LEAF_A" + }, + "pascalCase": { + "unsafeName": "AliasedLeafA", + "safeName": "AliasedLeafA" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "typeReference": { + "type": "named", + "value": "type_union:LeafObjectA" + } + }, + "type_union:AliasedLeafB": { + "type": "alias", + "declaration": { + "name": { + "originalName": "AliasedLeafB", + "camelCase": { + "unsafeName": "aliasedLeafB", + "safeName": "aliasedLeafB" + }, + "snakeCase": { + "unsafeName": "aliased_leaf_b", + "safeName": "aliased_leaf_b" + }, + "screamingSnakeCase": { + "unsafeName": "ALIASED_LEAF_B", + "safeName": "ALIASED_LEAF_B" + }, + "pascalCase": { + "unsafeName": "AliasedLeafB", + "safeName": "AliasedLeafB" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "typeReference": { + "type": "named", + "value": "type_union:AliasToLeafB" + } + }, + "type_union:AliasToLeafB": { + "type": "alias", + "declaration": { + "name": { + "originalName": "AliasToLeafB", + "camelCase": { + "unsafeName": "aliasToLeafB", + "safeName": "aliasToLeafB" + }, + "snakeCase": { + "unsafeName": "alias_to_leaf_b", + "safeName": "alias_to_leaf_b" + }, + "screamingSnakeCase": { + "unsafeName": "ALIAS_TO_LEAF_B", + "safeName": "ALIAS_TO_LEAF_B" + }, + "pascalCase": { + "unsafeName": "AliasToLeafB", + "safeName": "AliasToLeafB" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "typeReference": { + "type": "named", + "value": "type_union:LeafObjectB" + } + }, + "type_union:LeafObjectA": { + "type": "object", + "declaration": { + "name": { + "originalName": "LeafObjectA", + "camelCase": { + "unsafeName": "leafObjectA", + "safeName": "leafObjectA" + }, + "snakeCase": { + "unsafeName": "leaf_object_a", + "safeName": "leaf_object_a" + }, + "screamingSnakeCase": { + "unsafeName": "LEAF_OBJECT_A", + "safeName": "LEAF_OBJECT_A" + }, + "pascalCase": { + "unsafeName": "LeafObjectA", + "safeName": "LeafObjectA" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "onlyInA", + "name": { + "originalName": "onlyInA", + "camelCase": { + "unsafeName": "onlyInA", + "safeName": "onlyInA" + }, + "snakeCase": { + "unsafeName": "only_in_a", + "safeName": "only_in_a" + }, + "screamingSnakeCase": { + "unsafeName": "ONLY_IN_A", + "safeName": "ONLY_IN_A" + }, + "pascalCase": { + "unsafeName": "OnlyInA", + "safeName": "OnlyInA" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "sharedNumber", + "name": { + "originalName": "sharedNumber", + "camelCase": { + "unsafeName": "sharedNumber", + "safeName": "sharedNumber" + }, + "snakeCase": { + "unsafeName": "shared_number", + "safeName": "shared_number" + }, + "screamingSnakeCase": { + "unsafeName": "SHARED_NUMBER", + "safeName": "SHARED_NUMBER" + }, + "pascalCase": { + "unsafeName": "SharedNumber", + "safeName": "SharedNumber" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "INTEGER" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:LeafObjectB": { + "type": "object", + "declaration": { + "name": { + "originalName": "LeafObjectB", + "camelCase": { + "unsafeName": "leafObjectB", + "safeName": "leafObjectB" + }, + "snakeCase": { + "unsafeName": "leaf_object_b", + "safeName": "leaf_object_b" + }, + "screamingSnakeCase": { + "unsafeName": "LEAF_OBJECT_B", + "safeName": "LEAF_OBJECT_B" + }, + "pascalCase": { + "unsafeName": "LeafObjectB", + "safeName": "LeafObjectB" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "onlyInB", + "name": { + "originalName": "onlyInB", + "camelCase": { + "unsafeName": "onlyInB", + "safeName": "onlyInB" + }, + "snakeCase": { + "unsafeName": "only_in_b", + "safeName": "only_in_b" + }, + "screamingSnakeCase": { + "unsafeName": "ONLY_IN_B", + "safeName": "ONLY_IN_B" + }, + "pascalCase": { + "unsafeName": "OnlyInB", + "safeName": "OnlyInB" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:AliasedObjectUnion": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "AliasedObjectUnion", + "camelCase": { + "unsafeName": "aliasedObjectUnion", + "safeName": "aliasedObjectUnion" + }, + "snakeCase": { + "unsafeName": "aliased_object_union", + "safeName": "aliased_object_union" + }, + "screamingSnakeCase": { + "unsafeName": "ALIASED_OBJECT_UNION", + "safeName": "ALIASED_OBJECT_UNION" + }, + "pascalCase": { + "unsafeName": "AliasedObjectUnion", + "safeName": "AliasedObjectUnion" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "types": [ + { + "type": "named", + "value": "type_union:AliasedLeafA" + }, + { + "type": "named", + "value": "type_union:AliasedLeafB" + } + ] } }, "headers": [], @@ -2628,6 +3667,178 @@ }, "examples": null }, + "endpoint_union.nestedObjectUnions": { + "auth": null, + "declaration": { + "name": { + "originalName": "nestedObjectUnions", + "camelCase": { + "unsafeName": "nestedObjectUnions", + "safeName": "nestedObjectUnions" + }, + "snakeCase": { + "unsafeName": "nested_object_unions", + "safeName": "nested_object_unions" + }, + "screamingSnakeCase": { + "unsafeName": "NESTED_OBJECT_UNIONS", + "safeName": "NESTED_OBJECT_UNIONS" + }, + "pascalCase": { + "unsafeName": "NestedObjectUnions", + "safeName": "NestedObjectUnions" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "location": { + "method": "POST", + "path": "/nested-objects" + }, + "request": { + "type": "body", + "pathParameters": [], + "body": { + "type": "typeReference", + "value": { + "type": "named", + "value": "type_union:OuterNestedUnion" + } + } + }, + "response": { + "type": "json" + }, + "examples": null + }, + "endpoint_union.aliasedObjectUnion": { + "auth": null, + "declaration": { + "name": { + "originalName": "aliasedObjectUnion", + "camelCase": { + "unsafeName": "aliasedObjectUnion", + "safeName": "aliasedObjectUnion" + }, + "snakeCase": { + "unsafeName": "aliased_object_union", + "safeName": "aliased_object_union" + }, + "screamingSnakeCase": { + "unsafeName": "ALIASED_OBJECT_UNION", + "safeName": "ALIASED_OBJECT_UNION" + }, + "pascalCase": { + "unsafeName": "AliasedObjectUnion", + "safeName": "AliasedObjectUnion" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "location": { + "method": "POST", + "path": "/aliased-object" + }, + "request": { + "type": "body", + "pathParameters": [], + "body": { + "type": "typeReference", + "value": { + "type": "named", + "value": "type_union:AliasedObjectUnion" + } + } + }, + "response": { + "type": "json" + }, + "examples": null + }, "endpoint_union.getWithBaseProperties": { "auth": null, "declaration": { diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/code-samples-open-api.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/code-samples-open-api.json index 64ec5c888a5a..0014d622297f 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/code-samples-open-api.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/code-samples-open-api.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "BearerAuth", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/multiple-request-bodies.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/multiple-request-bodies.json index dc4ed33ae477..d559eb852f8a 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/multiple-request-bodies.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/multiple-request-bodies.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearerAuth", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/names.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/names.json index 4a9141a8a773..b74360d4225a 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/names.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions-openapi/names.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "BearerAuth", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/accept-header.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/accept-header.json index d26ab919cd8e..adc3bb1cf85e 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/accept-header.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/accept-header.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/any-auth.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/any-auth.json index 854dd9cdd13e..e9b9ddade84b 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/any-auth.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/any-auth.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": "MY_TOKEN", + "tokenPlaceholder": null, "key": "Bearer", "docs": null }, @@ -34,6 +35,7 @@ }, "prefix": null, "headerEnvVar": "MY_API_KEY", + "headerPlaceholder": null, "key": "ApiKey", "docs": null }, @@ -217,9 +219,11 @@ "username": "username", "usernameEnvVar": "MY_USERNAME", "usernameOmit": null, + "usernamePlaceholder": null, "password": "password", "passwordEnvVar": "MY_PASSWORD", "passwordOmit": null, + "passwordPlaceholder": null, "key": "Basic", "docs": null }, diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-environment-variables.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-environment-variables.json index 2c622e7cf124..1ef1b94b0a6d 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-environment-variables.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-environment-variables.json @@ -13,9 +13,11 @@ "username": "username", "usernameEnvVar": "USERNAME", "usernameOmit": null, + "usernamePlaceholder": null, "password": "accessToken", "passwordEnvVar": "PASSWORD", "passwordOmit": null, + "passwordPlaceholder": null, "key": "Basic", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-pw-omitted.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-pw-omitted.json index b5348a52d3c1..f731a4f30b50 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-pw-omitted.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth-pw-omitted.json @@ -13,9 +13,11 @@ "username": "username", "usernameEnvVar": null, "usernameOmit": null, + "usernamePlaceholder": null, "password": "password", "passwordEnvVar": null, "passwordOmit": true, + "passwordPlaceholder": null, "key": "Basic", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth.json index 4f3026bc8c18..de257be12bc2 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/basic-auth.json @@ -13,9 +13,11 @@ "username": "username", "usernameEnvVar": null, "usernameOmit": null, + "usernamePlaceholder": null, "password": "password", "passwordEnvVar": null, "passwordOmit": null, + "passwordPlaceholder": null, "key": "basic", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/bearer-token-environment-variable.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/bearer-token-environment-variable.json index b360d95bd92a..b715eeb6f753 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/bearer-token-environment-variable.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/bearer-token-environment-variable.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "apiKey", "tokenEnvVar": "COURIER_API_KEY", + "tokenPlaceholder": null, "key": "Bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/client-side-params.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/client-side-params.json index 186a54a08090..62b3f13686fe 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/client-side-params.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/client-side-params.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/endpoint-security-auth.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/endpoint-security-auth.json index 470a97b0d28e..ad195b8805b7 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/endpoint-security-auth.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/endpoint-security-auth.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": "MY_TOKEN", + "tokenPlaceholder": null, "key": "Bearer", "docs": null }, @@ -34,6 +35,7 @@ }, "prefix": null, "headerEnvVar": "MY_API_KEY", + "headerPlaceholder": null, "key": "ApiKey", "docs": null }, @@ -217,9 +219,11 @@ "username": "username", "usernameEnvVar": "MY_USERNAME", "usernameOmit": null, + "usernamePlaceholder": null, "password": "password", "passwordEnvVar": "MY_PASSWORD", "passwordOmit": null, + "passwordPlaceholder": null, "key": "Basic", "docs": null }, diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/examples.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/examples.json index 8b9f651d7a44..b0e4c7fc21de 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/examples.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/examples.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/exhaustive.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/exhaustive.json index 1224a7458624..b9434d0b7a00 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/exhaustive.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/exhaustive.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-content-type.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-content-type.json index d36c5596fba3..e1e1161255fb 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-content-type.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-content-type.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-deterministic-ordering.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-deterministic-ordering.json index 416d46997c18..e127797a7a16 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-deterministic-ordering.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-deterministic-ordering.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-undiscriminated-union-wire-tests.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-undiscriminated-union-wire-tests.json index 92966a6b03be..a10f85e1fecb 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-undiscriminated-union-wire-tests.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/go-undiscriminated-union-wire-tests.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth-environment-variable.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth-environment-variable.json index 60c0d75272c7..aea86b485551 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth-environment-variable.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth-environment-variable.json @@ -27,6 +27,7 @@ }, "prefix": "test_prefix", "headerEnvVar": "HEADER_TOKEN_ENV_VAR", + "headerPlaceholder": null, "key": "Header", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth.json index 69da6ba0cfb0..3b42c5214950 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/header-auth.json @@ -27,6 +27,7 @@ }, "prefix": "test_prefix", "headerEnvVar": null, + "headerPlaceholder": null, "key": "Header", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/idempotency-headers.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/idempotency-headers.json index d4e566c783db..9cd62f62cb37 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/idempotency-headers.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/idempotency-headers.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/imdb.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/imdb.json index 5b702919e7ea..c598ec7af286 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/imdb.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/imdb.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-builder-extension.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-builder-extension.json index a329b4e956cd..4da7f14cc4ee 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-builder-extension.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-builder-extension.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-custom-package-prefix.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-custom-package-prefix.json index c3377d1b86ef..25f7c390da23 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-custom-package-prefix.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-custom-package-prefix.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-websocket-shared-discriminator.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-websocket-shared-discriminator.json new file mode 100644 index 000000000000..d2aa4330ec3d --- /dev/null +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/java-websocket-shared-discriminator.json @@ -0,0 +1,2035 @@ +{ + "selfHosted": false, + "fdrApiDefinitionId": null, + "apiVersion": null, + "apiName": "java-websocket-shared-discriminator", + "apiDisplayName": null, + "apiDocs": null, + "auth": { + "requirement": "ALL", + "schemes": [], + "docs": null + }, + "headers": [], + "idempotencyHeaders": [], + "types": { + "type_realtime:SendEvent": { + "inline": null, + "name": { + "name": "SendEvent", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:SendEvent" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "text", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_realtime:ConversationHistoryMessage": { + "inline": null, + "name": { + "name": "ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationHistoryMessage" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "type", + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "History" + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "role", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "content", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_realtime:FunctionCallHistoryMessage": { + "inline": null, + "name": { + "name": "FunctionCallHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:FunctionCallHistoryMessage" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "type", + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "History" + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "function_calls", + "valueType": { + "_type": "container", + "container": { + "_type": "list", + "list": { + "_type": "named", + "name": "FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:FunctionCall", + "default": null, + "inline": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [ + "type_realtime:FunctionCall" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_realtime:ConversationTextMessage": { + "inline": null, + "name": { + "name": "ConversationTextMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationTextMessage" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "type", + "valueType": { + "_type": "container", + "container": { + "_type": "literal", + "literal": { + "type": "string", + "string": "ConversationText" + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "text", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "confidence", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "DOUBLE", + "v2": { + "type": "double", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_realtime:FunctionCall": { + "inline": null, + "name": { + "name": "FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:FunctionCall" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "id", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "name", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "arguments", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + } + }, + "errors": {}, + "services": {}, + "constants": { + "errorInstanceIdKey": "errorInstanceId" + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": {}, + "sharedTypes": [ + "type_realtime:SendEvent", + "type_realtime:ConversationHistoryMessage", + "type_realtime:FunctionCallHistoryMessage", + "type_realtime:ConversationTextMessage", + "type_realtime:FunctionCall" + ] + }, + "webhookGroups": {}, + "websocketChannels": { + "channel_realtime": { + "path": { + "head": "/realtime", + "parts": [] + }, + "baseUrl": null, + "auth": false, + "name": "realtime", + "displayName": null, + "connectMethodName": null, + "headers": [], + "pathParameters": [], + "queryParameters": [], + "messages": [ + { + "type": "send", + "origin": "client", + "body": { + "type": "reference", + "bodyType": { + "_type": "named", + "name": "SendEvent", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:SendEvent", + "default": null, + "inline": null + }, + "docs": null + }, + "displayName": "Send", + "methodName": null, + "availability": null, + "docs": null + }, + { + "type": "conversation_history", + "origin": "server", + "body": { + "type": "reference", + "bodyType": { + "_type": "named", + "name": "ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationHistoryMessage", + "default": null, + "inline": null + }, + "docs": null + }, + "displayName": "ConversationHistory", + "methodName": null, + "availability": null, + "docs": null + }, + { + "type": "function_call_history", + "origin": "server", + "body": { + "type": "reference", + "bodyType": { + "_type": "named", + "name": "FunctionCallHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:FunctionCallHistoryMessage", + "default": null, + "inline": null + }, + "docs": null + }, + "displayName": "FunctionCallHistory", + "methodName": null, + "availability": null, + "docs": null + }, + { + "type": "conversation_text", + "origin": "server", + "body": { + "type": "reference", + "bodyType": { + "_type": "named", + "name": "ConversationTextMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationTextMessage", + "default": null, + "inline": null + }, + "docs": null + }, + "displayName": "ConversationText", + "methodName": null, + "availability": null, + "docs": null + } + ], + "examples": [ + { + "name": "Conversation history", + "url": "/realtime", + "pathParameters": [], + "headers": [], + "queryParameters": [], + "messages": [ + { + "type": "send", + "body": { + "type": "reference", + "shape": { + "type": "named", + "typeName": { + "typeId": "type_realtime:SendEvent", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "SendEvent", + "displayName": null + }, + "shape": { + "type": "object", + "properties": [ + { + "name": "text", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "hello" + } + } + }, + "jsonExample": "hello" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:SendEvent", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "SendEvent", + "displayName": null + }, + "propertyAccess": null + } + ], + "extraProperties": null + } + }, + "jsonExample": { + "text": "hello" + } + } + }, + { + "type": "conversation_history", + "body": { + "type": "reference", + "shape": { + "type": "named", + "typeName": { + "typeId": "type_realtime:ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "ConversationHistoryMessage", + "displayName": null + }, + "shape": { + "type": "object", + "properties": [ + { + "name": "role", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "user" + } + } + }, + "jsonExample": "user" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "ConversationHistoryMessage", + "displayName": null + }, + "propertyAccess": null + }, + { + "name": "content", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "hello" + } + } + }, + "jsonExample": "hello" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "ConversationHistoryMessage", + "displayName": null + }, + "propertyAccess": null + } + ], + "extraProperties": null + } + }, + "jsonExample": { + "role": "user", + "content": "hello" + } + } + }, + { + "type": "function_call_history", + "body": { + "type": "reference", + "shape": { + "type": "named", + "typeName": { + "typeId": "type_realtime:FunctionCallHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "FunctionCallHistoryMessage", + "displayName": null + }, + "shape": { + "type": "object", + "properties": [ + { + "name": "function_calls", + "value": { + "shape": { + "type": "container", + "container": { + "type": "list", + "list": [ + { + "shape": { + "type": "named", + "typeName": { + "typeId": "type_realtime:FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "FunctionCall", + "displayName": null + }, + "shape": { + "type": "object", + "properties": [ + { + "name": "id", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "fc_123" + } + } + }, + "jsonExample": "fc_123" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "FunctionCall", + "displayName": null + }, + "propertyAccess": null + }, + { + "name": "name", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "lookup" + } + } + }, + "jsonExample": "lookup" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "FunctionCall", + "displayName": null + }, + "propertyAccess": null + }, + { + "name": "arguments", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "{}" + } + } + }, + "jsonExample": "{}" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "FunctionCall", + "displayName": null + }, + "propertyAccess": null + } + ], + "extraProperties": null + } + }, + "jsonExample": { + "id": "fc_123", + "name": "lookup", + "arguments": "{}" + } + } + ], + "itemType": { + "_type": "named", + "name": "FunctionCall", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:FunctionCall", + "default": null, + "inline": null + } + } + }, + "jsonExample": [ + { + "id": "fc_123", + "name": "lookup", + "arguments": "{}" + } + ] + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:FunctionCallHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "FunctionCallHistoryMessage", + "displayName": null + }, + "propertyAccess": null + } + ], + "extraProperties": null + } + }, + "jsonExample": { + "function_calls": [ + { + "id": "fc_123", + "name": "lookup", + "arguments": "{}" + } + ] + } + } + }, + { + "type": "conversation_text", + "body": { + "type": "reference", + "shape": { + "type": "named", + "typeName": { + "typeId": "type_realtime:ConversationTextMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "ConversationTextMessage", + "displayName": null + }, + "shape": { + "type": "object", + "properties": [ + { + "name": "text", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "Hi there" + } + } + }, + "jsonExample": "Hi there" + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:ConversationTextMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "ConversationTextMessage", + "displayName": null + }, + "propertyAccess": null + }, + { + "name": "confidence", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "double", + "double": 0.95 + } + }, + "jsonExample": 0.95 + }, + "originalTypeDeclaration": { + "typeId": "type_realtime:ConversationTextMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "name": "ConversationTextMessage", + "displayName": null + }, + "propertyAccess": null + } + ], + "extraProperties": null + } + }, + "jsonExample": { + "text": "Hi there", + "confidence": 0.95 + } + } + } + ], + "docs": null + }, + { + "name": null, + "pathParameters": [], + "headers": [], + "queryParameters": [], + "messages": [ + { + "type": "send", + "body": { + "type": "reference", + "shape": { + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "text", + "originalTypeDeclaration": { + "name": "SendEvent", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:SendEvent" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "text" + } + } + }, + "jsonExample": "text" + }, + "propertyAccess": null + } + ], + "extraProperties": null + }, + "typeName": { + "name": "SendEvent", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:SendEvent" + } + }, + "jsonExample": { + "text": "text" + } + } + }, + { + "type": "conversation_history", + "body": { + "type": "reference", + "shape": { + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "type", + "originalTypeDeclaration": { + "name": "ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationHistoryMessage" + }, + "value": { + "shape": { + "type": "container", + "container": { + "type": "literal", + "literal": { + "type": "string", + "string": { + "original": "History" + } + } + } + }, + "jsonExample": "History" + }, + "propertyAccess": null + }, + { + "name": "role", + "originalTypeDeclaration": { + "name": "ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationHistoryMessage" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "role" + } + } + }, + "jsonExample": "role" + }, + "propertyAccess": null + }, + { + "name": "content", + "originalTypeDeclaration": { + "name": "ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationHistoryMessage" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "content" + } + } + }, + "jsonExample": "content" + }, + "propertyAccess": null + } + ], + "extraProperties": null + }, + "typeName": { + "name": "ConversationHistoryMessage", + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "displayName": null, + "typeId": "type_realtime:ConversationHistoryMessage" + } + }, + "jsonExample": { + "type": "History", + "role": "role", + "content": "content" + } + } + } + ], + "url": "/realtime", + "docs": null + } + ], + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + }, + "readmeConfig": null, + "sourceConfig": null, + "publishConfig": null, + "dynamic": { + "version": "1.0.0", + "types": { + "type_realtime:SendEvent": { + "type": "object", + "declaration": { + "name": { + "originalName": "SendEvent", + "camelCase": { + "unsafeName": "sendEvent", + "safeName": "sendEvent" + }, + "snakeCase": { + "unsafeName": "send_event", + "safeName": "send_event" + }, + "screamingSnakeCase": { + "unsafeName": "SEND_EVENT", + "safeName": "SEND_EVENT" + }, + "pascalCase": { + "unsafeName": "SendEvent", + "safeName": "SendEvent" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "text", + "name": { + "originalName": "text", + "camelCase": { + "unsafeName": "text", + "safeName": "text" + }, + "snakeCase": { + "unsafeName": "text", + "safeName": "text" + }, + "screamingSnakeCase": { + "unsafeName": "TEXT", + "safeName": "TEXT" + }, + "pascalCase": { + "unsafeName": "Text", + "safeName": "Text" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:ConversationHistoryMessage": { + "type": "object", + "declaration": { + "name": { + "originalName": "ConversationHistoryMessage", + "camelCase": { + "unsafeName": "conversationHistoryMessage", + "safeName": "conversationHistoryMessage" + }, + "snakeCase": { + "unsafeName": "conversation_history_message", + "safeName": "conversation_history_message" + }, + "screamingSnakeCase": { + "unsafeName": "CONVERSATION_HISTORY_MESSAGE", + "safeName": "CONVERSATION_HISTORY_MESSAGE" + }, + "pascalCase": { + "unsafeName": "ConversationHistoryMessage", + "safeName": "ConversationHistoryMessage" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "type", + "name": { + "originalName": "type", + "camelCase": { + "unsafeName": "type", + "safeName": "type" + }, + "snakeCase": { + "unsafeName": "type", + "safeName": "type" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE", + "safeName": "TYPE" + }, + "pascalCase": { + "unsafeName": "Type", + "safeName": "Type" + } + } + }, + "typeReference": { + "type": "literal", + "value": { + "type": "string", + "value": "History" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "role", + "name": { + "originalName": "role", + "camelCase": { + "unsafeName": "role", + "safeName": "role" + }, + "snakeCase": { + "unsafeName": "role", + "safeName": "role" + }, + "screamingSnakeCase": { + "unsafeName": "ROLE", + "safeName": "ROLE" + }, + "pascalCase": { + "unsafeName": "Role", + "safeName": "Role" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "content", + "name": { + "originalName": "content", + "camelCase": { + "unsafeName": "content", + "safeName": "content" + }, + "snakeCase": { + "unsafeName": "content", + "safeName": "content" + }, + "screamingSnakeCase": { + "unsafeName": "CONTENT", + "safeName": "CONTENT" + }, + "pascalCase": { + "unsafeName": "Content", + "safeName": "Content" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:FunctionCallHistoryMessage": { + "type": "object", + "declaration": { + "name": { + "originalName": "FunctionCallHistoryMessage", + "camelCase": { + "unsafeName": "functionCallHistoryMessage", + "safeName": "functionCallHistoryMessage" + }, + "snakeCase": { + "unsafeName": "function_call_history_message", + "safeName": "function_call_history_message" + }, + "screamingSnakeCase": { + "unsafeName": "FUNCTION_CALL_HISTORY_MESSAGE", + "safeName": "FUNCTION_CALL_HISTORY_MESSAGE" + }, + "pascalCase": { + "unsafeName": "FunctionCallHistoryMessage", + "safeName": "FunctionCallHistoryMessage" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "type", + "name": { + "originalName": "type", + "camelCase": { + "unsafeName": "type", + "safeName": "type" + }, + "snakeCase": { + "unsafeName": "type", + "safeName": "type" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE", + "safeName": "TYPE" + }, + "pascalCase": { + "unsafeName": "Type", + "safeName": "Type" + } + } + }, + "typeReference": { + "type": "literal", + "value": { + "type": "string", + "value": "History" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "function_calls", + "name": { + "originalName": "function_calls", + "camelCase": { + "unsafeName": "functionCalls", + "safeName": "functionCalls" + }, + "snakeCase": { + "unsafeName": "function_calls", + "safeName": "function_calls" + }, + "screamingSnakeCase": { + "unsafeName": "FUNCTION_CALLS", + "safeName": "FUNCTION_CALLS" + }, + "pascalCase": { + "unsafeName": "FunctionCalls", + "safeName": "FunctionCalls" + } + } + }, + "typeReference": { + "type": "list", + "value": { + "type": "named", + "value": "type_realtime:FunctionCall" + } + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:ConversationTextMessage": { + "type": "object", + "declaration": { + "name": { + "originalName": "ConversationTextMessage", + "camelCase": { + "unsafeName": "conversationTextMessage", + "safeName": "conversationTextMessage" + }, + "snakeCase": { + "unsafeName": "conversation_text_message", + "safeName": "conversation_text_message" + }, + "screamingSnakeCase": { + "unsafeName": "CONVERSATION_TEXT_MESSAGE", + "safeName": "CONVERSATION_TEXT_MESSAGE" + }, + "pascalCase": { + "unsafeName": "ConversationTextMessage", + "safeName": "ConversationTextMessage" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "type", + "name": { + "originalName": "type", + "camelCase": { + "unsafeName": "type", + "safeName": "type" + }, + "snakeCase": { + "unsafeName": "type", + "safeName": "type" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE", + "safeName": "TYPE" + }, + "pascalCase": { + "unsafeName": "Type", + "safeName": "Type" + } + } + }, + "typeReference": { + "type": "literal", + "value": { + "type": "string", + "value": "ConversationText" + } + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "text", + "name": { + "originalName": "text", + "camelCase": { + "unsafeName": "text", + "safeName": "text" + }, + "snakeCase": { + "unsafeName": "text", + "safeName": "text" + }, + "screamingSnakeCase": { + "unsafeName": "TEXT", + "safeName": "TEXT" + }, + "pascalCase": { + "unsafeName": "Text", + "safeName": "Text" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "confidence", + "name": { + "originalName": "confidence", + "camelCase": { + "unsafeName": "confidence", + "safeName": "confidence" + }, + "snakeCase": { + "unsafeName": "confidence", + "safeName": "confidence" + }, + "screamingSnakeCase": { + "unsafeName": "CONFIDENCE", + "safeName": "CONFIDENCE" + }, + "pascalCase": { + "unsafeName": "Confidence", + "safeName": "Confidence" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "DOUBLE" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_realtime:FunctionCall": { + "type": "object", + "declaration": { + "name": { + "originalName": "FunctionCall", + "camelCase": { + "unsafeName": "functionCall", + "safeName": "functionCall" + }, + "snakeCase": { + "unsafeName": "function_call", + "safeName": "function_call" + }, + "screamingSnakeCase": { + "unsafeName": "FUNCTION_CALL", + "safeName": "FUNCTION_CALL" + }, + "pascalCase": { + "unsafeName": "FunctionCall", + "safeName": "FunctionCall" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + ], + "packagePath": [], + "file": { + "originalName": "realtime", + "camelCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "snakeCase": { + "unsafeName": "realtime", + "safeName": "realtime" + }, + "screamingSnakeCase": { + "unsafeName": "REALTIME", + "safeName": "REALTIME" + }, + "pascalCase": { + "unsafeName": "Realtime", + "safeName": "Realtime" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "id", + "name": { + "originalName": "id", + "camelCase": { + "unsafeName": "id", + "safeName": "id" + }, + "snakeCase": { + "unsafeName": "id", + "safeName": "id" + }, + "screamingSnakeCase": { + "unsafeName": "ID", + "safeName": "ID" + }, + "pascalCase": { + "unsafeName": "ID", + "safeName": "ID" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "name", + "name": { + "originalName": "name", + "camelCase": { + "unsafeName": "name", + "safeName": "name" + }, + "snakeCase": { + "unsafeName": "name", + "safeName": "name" + }, + "screamingSnakeCase": { + "unsafeName": "NAME", + "safeName": "NAME" + }, + "pascalCase": { + "unsafeName": "Name", + "safeName": "Name" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "arguments", + "name": { + "originalName": "arguments", + "camelCase": { + "unsafeName": "arguments", + "safeName": "arguments" + }, + "snakeCase": { + "unsafeName": "arguments", + "safeName": "arguments" + }, + "screamingSnakeCase": { + "unsafeName": "ARGUMENTS", + "safeName": "ARGUMENTS" + }, + "pascalCase": { + "unsafeName": "Arguments", + "safeName": "Arguments" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + } + }, + "headers": [], + "endpoints": {}, + "pathParameters": [], + "environments": null, + "variables": null, + "generatorConfig": null + }, + "audiences": null, + "generationMetadata": null, + "apiPlayground": true, + "casingsConfig": { + "generationLanguage": null, + "keywords": null, + "smartCasing": true + }, + "subpackages": { + "subpackage_realtime": { + "name": "realtime", + "displayName": null, + "fernFilepath": { + "allParts": [ + "realtime" + ], + "packagePath": [], + "file": "realtime" + }, + "service": null, + "types": [ + "type_realtime:SendEvent", + "type_realtime:ConversationHistoryMessage", + "type_realtime:FunctionCallHistoryMessage", + "type_realtime:ConversationTextMessage", + "type_realtime:FunctionCall" + ], + "errors": [], + "subpackages": [], + "navigationConfig": null, + "webhooks": null, + "websocket": "channel_realtime", + "hasEndpointsInTree": false, + "docs": null + } + }, + "rootPackage": { + "fernFilepath": { + "allParts": [], + "packagePath": [], + "file": null + }, + "websocket": null, + "service": null, + "types": [], + "errors": [], + "subpackages": [ + "subpackage_realtime" + ], + "webhooks": null, + "navigationConfig": null, + "hasEndpointsInTree": false, + "docs": null + }, + "sdkConfig": { + "isAuthMandatory": false, + "hasStreamingEndpoints": false, + "hasPaginatedEndpoints": false, + "hasFileDownloadEndpoints": false, + "platformHeaders": { + "language": "X-Fern-Language", + "sdkName": "X-Fern-SDK-Name", + "sdkVersion": "X-Fern-SDK-Version", + "userAgent": null + } + } +} \ No newline at end of file diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-no-default.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-no-default.json index 39bd410c9aa9..0982cc5766df 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-no-default.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-no-default.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-reference.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-reference.json index 7b9fe39f5931..990c5c2c7019 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-reference.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment-reference.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "BearerAuth", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment.json index a91544c50037..c0d2181b0a2f 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multi-url-environment.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multiple-request-bodies.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multiple-request-bodies.json index ad06d63b5e0a..9181f8fe1b6c 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multiple-request-bodies.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/multiple-request-bodies.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "BearerAuthScheme", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/no-environment.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/no-environment.json index 82418e745220..dae6068c5549 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/no-environment.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/no-environment.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-custom.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-custom.json index df47d8b96958..b282686fb3af 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-custom.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-custom.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-uri-path.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-uri-path.json index d19e46dee4d7..2a145bf9b754 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-uri-path.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination-uri-path.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination.json index 43d7301597e1..30d927e09bec 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/pagination.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/simple-api.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/simple-api.json index 56900c7a27f7..aaa3f95bd6cb 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/simple-api.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/simple-api.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-default.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-default.json index b9a4dbb76dc8..ecda6fc7e697 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-default.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-default.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-no-default.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-no-default.json index 9708194fce65..2a9473963b8c 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-no-default.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/single-url-environment-no-default.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/trace.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/trace.json index 933b384d1a24..6b8f82ee3fbe 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/trace.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/trace.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/ts-express-casing.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/ts-express-casing.json index a88ebad6b0ec..184bf10f1d2f 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/ts-express-casing.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/ts-express-casing.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/undiscriminated-unions.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/undiscriminated-unions.json index 2575a1a093cb..8bc957b77e7a 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/undiscriminated-unions.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/undiscriminated-unions.json @@ -2056,64 +2056,160 @@ "v2Examples": null, "availability": null, "docs": "Union with multiple named type aliases that all resolve to the same C# type (string).\nWithout the fix, this would generate duplicate implicit operators:\n public static implicit operator UnionWithTypeAliases(string value) => ...\n public static implicit operator UnionWithTypeAliases(string value) => ...\n public static implicit operator UnionWithTypeAliases(string value) => ...\ncausing CS0557 compiler error." - } - }, - "errors": {}, - "services": { - "service_union": { + }, + "type_union:LeafTypeA": { + "inline": null, + "name": { + "name": "LeafTypeA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafTypeA" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "alpha", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "beta", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "INTEGER", + "v2": { + "type": "integer", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, "availability": null, + "docs": null + }, + "type_union:LeafTypeB": { + "inline": null, "name": { + "name": "LeafTypeB", "fernFilepath": { "allParts": [ "union" ], "packagePath": [], "file": "union" - } + }, + "displayName": null, + "typeId": "type_union:LeafTypeB" }, - "displayName": null, - "basePath": { - "head": "/", - "parts": [] + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "gamma", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] }, - "headers": [], - "pathParameters": [], + "referencedTypes": [], "encoding": { "json": {}, "proto": null }, - "transport": { - "type": "http" + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_union:NestedObjectUnion": { + "inline": null, + "name": { + "name": "NestedObjectUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NestedObjectUnion" }, - "endpoints": [ - { - "id": "endpoint_union.get", - "name": "get", - "displayName": null, - "auth": false, - "security": null, - "idempotent": false, - "baseUrl": null, - "v2BaseUrls": null, - "method": "POST", - "basePath": null, - "path": { - "head": "", - "parts": [] - }, - "fullPath": { - "head": "", - "parts": [] - }, - "pathParameters": [], - "allPathParameters": [], - "queryParameters": [], - "headers": [], - "requestBody": { - "type": "reference", - "requestBodyType": { + "shape": { + "_type": "undiscriminatedUnion", + "baseProperties": null, + "members": [ + { + "type": { "_type": "named", - "name": "MyUnion", + "name": "LeafTypeA", "fernFilepath": { "allParts": [ "union" @@ -2121,242 +2217,893 @@ "packagePath": [], "file": "union" }, - "displayName": null, - "typeId": "type_union:MyUnion", + "displayName": "Leaf Type A", + "typeId": "type_union:LeafTypeA", "default": null, "inline": null }, - "docs": null, - "contentType": null, - "v2Examples": null - }, - "v2RequestBodies": null, - "sdkRequest": { - "shape": { - "type": "justRequestBody", - "value": { - "type": "typeReference", - "requestBodyType": { - "_type": "named", - "name": "MyUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:MyUnion", - "default": null, - "inline": null - }, - "docs": null, - "contentType": null, - "v2Examples": null - } - }, - "requestParameterName": "request", - "streamParameter": null + "docs": null }, - "response": { - "body": { - "type": "json", - "value": { - "type": "response", - "responseBodyType": { - "_type": "named", - "name": "MyUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:MyUnion", - "default": null, - "inline": null - }, - "docs": null, - "v2Examples": null - } + { + "type": { + "_type": "named", + "name": "LeafTypeB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": "Leaf Type B", + "typeId": "type_union:LeafTypeB", + "default": null, + "inline": null }, - "status-code": null, - "isWildcardStatusCode": null, "docs": null - }, - "v2Responses": null, - "errors": [], - "userSpecifiedExamples": [], - "autogeneratedExamples": [ - { - "example": { - "id": "d0a6f329", - "url": "", - "name": null, - "endpointHeaders": [], - "endpointPathParameters": [], - "queryParameters": [], - "servicePathParameters": [], - "serviceHeaders": [], - "rootPathParameters": [], - "request": { - "type": "reference", - "shape": { - "type": "named", - "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" - } - } - }, - "jsonExample": "string" - } - }, - "typeName": { - "name": "MyUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:MyUnion" - } - }, - "jsonExample": "string" - }, - "response": { - "type": "ok", - "value": { - "type": "body", - "value": { - "shape": { - "type": "named", - "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" - } - } - }, - "jsonExample": "string" - } - }, - "typeName": { - "name": "MyUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:MyUnion" - } - }, - "jsonExample": "string" - } - } - }, - "docs": null - } - } + } + ] + }, + "referencedTypes": [ + "type_union:LeafTypeA", + "type_union:LeafTypeB" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": "Inner union with two object variants that have disjoint required keys.\nTests that required-key guards work correctly inside nested union contexts." + }, + "type_union:WrapperObject": { + "inline": null, + "name": { + "name": "WrapperObject", + "fernFilepath": { + "allParts": [ + "union" ], - "pagination": null, - "transport": null, - "v2Examples": null, - "source": null, - "audiences": null, - "retries": null, - "apiPlayground": null, - "responseHeaders": [], - "availability": null, - "docs": null + "packagePath": [], + "file": "union" }, - { - "id": "endpoint_union.getMetadata", - "name": "getMetadata", - "displayName": null, - "auth": false, - "security": null, - "idempotent": false, - "baseUrl": null, - "v2BaseUrls": null, - "method": "GET", - "basePath": null, - "path": { - "head": "/metadata", - "parts": [] - }, - "fullPath": { - "head": "/metadata", - "parts": [] + "displayName": null, + "typeId": "type_union:WrapperObject" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "inner", + "valueType": { + "_type": "named", + "name": "NestedObjectUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NestedObjectUnion", + "default": null, + "inline": null + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null }, - "pathParameters": [], - "allPathParameters": [], - "queryParameters": [], - "headers": [], - "requestBody": null, - "v2RequestBodies": null, - "sdkRequest": null, - "response": { - "body": { - "type": "json", - "value": { - "type": "response", - "responseBodyType": { - "_type": "named", - "name": "Metadata", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:Metadata", + { + "name": "label", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", "default": null, - "inline": null - }, - "docs": null, - "v2Examples": null + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [ + "type_union:NestedObjectUnion", + "type_union:LeafTypeA", + "type_union:LeafTypeB" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_union:OuterNestedUnion": { + "inline": null, + "name": { + "name": "OuterNestedUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:OuterNestedUnion" + }, + "shape": { + "_type": "undiscriminatedUnion", + "baseProperties": null, + "members": [ + { + "type": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } } }, - "status-code": null, - "isWildcardStatusCode": null, "docs": null }, - "v2Responses": null, - "errors": [], - "userSpecifiedExamples": [ - { - "example": { - "id": "ce7f971a", - "name": null, - "url": "/metadata", - "rootPathParameters": [], - "endpointPathParameters": [], - "servicePathParameters": [], + { + "type": { + "_type": "named", + "name": "WrapperObject", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": "Wrapper Object", + "typeId": "type_union:WrapperObject", + "default": null, + "inline": null + }, + "docs": null + } + ] + }, + "referencedTypes": [ + "type_union:WrapperObject", + "type_union:NestedObjectUnion", + "type_union:LeafTypeA", + "type_union:LeafTypeB" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": "Outer union where one variant is an object containing a nested union field.\nTests that the deserializer correctly handles transitive union deserialization." + }, + "type_union:AliasedLeafA": { + "inline": null, + "name": { + "name": "AliasedLeafA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:AliasedLeafA" + }, + "shape": { + "_type": "alias", + "aliasOf": { + "_type": "named", + "name": "LeafObjectA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectA", + "default": null, + "inline": null + }, + "resolvedType": { + "_type": "named", + "name": { + "name": "LeafObjectA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectA" + }, + "shape": "OBJECT" + } + }, + "referencedTypes": [ + "type_union:LeafObjectA" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": "An alias around LeafObjectA." + }, + "type_union:AliasedLeafB": { + "inline": null, + "name": { + "name": "AliasedLeafB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:AliasedLeafB" + }, + "shape": { + "_type": "alias", + "aliasOf": { + "_type": "named", + "name": "AliasToLeafB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:AliasToLeafB", + "default": null, + "inline": null + }, + "resolvedType": { + "_type": "named", + "name": { + "name": "LeafObjectB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectB" + }, + "shape": "OBJECT" + } + }, + "referencedTypes": [ + "type_union:AliasToLeafB", + "type_union:LeafObjectB" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": "An alias around an alias around LeafObjectB, to exercise the alias-walk loop." + }, + "type_union:AliasToLeafB": { + "inline": null, + "name": { + "name": "AliasToLeafB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:AliasToLeafB" + }, + "shape": { + "_type": "alias", + "aliasOf": { + "_type": "named", + "name": "LeafObjectB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectB", + "default": null, + "inline": null + }, + "resolvedType": { + "_type": "named", + "name": { + "name": "LeafObjectB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectB" + }, + "shape": "OBJECT" + } + }, + "referencedTypes": [ + "type_union:LeafObjectB" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_union:LeafObjectA": { + "inline": null, + "name": { + "name": "LeafObjectA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectA" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "onlyInA", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + }, + { + "name": "sharedNumber", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "INTEGER", + "v2": { + "type": "integer", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_union:LeafObjectB": { + "inline": null, + "name": { + "name": "LeafObjectB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectB" + }, + "shape": { + "_type": "object", + "extends": [], + "properties": [ + { + "name": "onlyInB", + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "propertyAccess": null, + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "availability": null, + "docs": null + } + ], + "extra-properties": false, + "extendedProperties": [] + }, + "referencedTypes": [], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": null + }, + "type_union:AliasedObjectUnion": { + "inline": null, + "name": { + "name": "AliasedObjectUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:AliasedObjectUnion" + }, + "shape": { + "_type": "undiscriminatedUnion", + "baseProperties": null, + "members": [ + { + "type": { + "_type": "named", + "name": "AliasedLeafA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": "Aliased Leaf A", + "typeId": "type_union:AliasedLeafA", + "default": null, + "inline": null + }, + "docs": null + }, + { + "type": { + "_type": "named", + "name": "AliasedLeafB", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": "Aliased Leaf B", + "typeId": "type_union:AliasedLeafB", + "default": null, + "inline": null + }, + "docs": null + } + ] + }, + "referencedTypes": [ + "type_union:AliasedLeafA", + "type_union:LeafObjectA", + "type_union:AliasedLeafB", + "type_union:AliasToLeafB", + "type_union:LeafObjectB" + ], + "encoding": { + "json": {}, + "proto": null + }, + "source": null, + "userProvidedExamples": [], + "autogeneratedExamples": [], + "v2Examples": null, + "availability": null, + "docs": "Undiscriminated union whose members are named aliases of object types\n(including an alias-of-alias). Required keys are disjoint, so a correct\ndeserializer must emit containsKey() guards for each alias variant." + } + }, + "errors": {}, + "services": { + "service_union": { + "availability": null, + "name": { + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + } + }, + "displayName": null, + "basePath": { + "head": "/", + "parts": [] + }, + "headers": [], + "pathParameters": [], + "encoding": { + "json": {}, + "proto": null + }, + "transport": { + "type": "http" + }, + "endpoints": [ + { + "id": "endpoint_union.get", + "name": "get", + "displayName": null, + "auth": false, + "security": null, + "idempotent": false, + "baseUrl": null, + "v2BaseUrls": null, + "method": "POST", + "basePath": null, + "path": { + "head": "", + "parts": [] + }, + "fullPath": { + "head": "", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "reference", + "requestBodyType": { + "_type": "named", + "name": "MyUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:MyUnion", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + }, + "v2RequestBodies": null, + "sdkRequest": { + "shape": { + "type": "justRequestBody", + "value": { + "type": "typeReference", + "requestBodyType": { + "_type": "named", + "name": "MyUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:MyUnion", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + } + }, + "requestParameterName": "request", + "streamParameter": null + }, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": "MyUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:MyUnion", + "default": null, + "inline": null + }, + "docs": null, + "v2Examples": null + } + }, + "status-code": null, + "isWildcardStatusCode": null, + "docs": null + }, + "v2Responses": null, + "errors": [], + "userSpecifiedExamples": [], + "autogeneratedExamples": [ + { + "example": { + "id": "d0a6f329", + "url": "", + "name": null, + "endpointHeaders": [], + "endpointPathParameters": [], + "queryParameters": [], + "servicePathParameters": [], + "serviceHeaders": [], + "rootPathParameters": [], + "request": { + "type": "reference", + "shape": { + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + } + }, + "typeName": { + "name": "MyUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:MyUnion" + } + }, + "jsonExample": "string" + }, + "response": { + "type": "ok", + "value": { + "type": "body", + "value": { + "shape": { + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + } + }, + "typeName": { + "name": "MyUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:MyUnion" + } + }, + "jsonExample": "string" + } + } + }, + "docs": null + } + } + ], + "pagination": null, + "transport": null, + "v2Examples": null, + "source": null, + "audiences": null, + "retries": null, + "apiPlayground": null, + "responseHeaders": [], + "availability": null, + "docs": null + }, + { + "id": "endpoint_union.getMetadata", + "name": "getMetadata", + "displayName": null, + "auth": false, + "security": null, + "idempotent": false, + "baseUrl": null, + "v2BaseUrls": null, + "method": "GET", + "basePath": null, + "path": { + "head": "/metadata", + "parts": [] + }, + "fullPath": { + "head": "/metadata", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": null, + "v2RequestBodies": null, + "sdkRequest": null, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": "Metadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:Metadata", + "default": null, + "inline": null + }, + "docs": null, + "v2Examples": null + } + }, + "status-code": null, + "isWildcardStatusCode": null, + "docs": null + }, + "v2Responses": null, + "errors": [], + "userSpecifiedExamples": [ + { + "example": { + "id": "ce7f971a", + "name": null, + "url": "/metadata", + "rootPathParameters": [], + "endpointPathParameters": [], + "servicePathParameters": [], "endpointHeaders": [], "serviceHeaders": [], "queryParameters": [], @@ -3434,38 +4181,520 @@ } } }, - "jsonExample": { - "string": { - "key": "value" - } - } - }, - "originalTypeDeclaration": { - "typeId": "type_union:Request", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "name": "Request", - "displayName": null + "jsonExample": { + "string": { + "key": "value" + } + } + }, + "originalTypeDeclaration": { + "typeId": "type_union:Request", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "name": "Request", + "displayName": null + }, + "propertyAccess": null + } + ], + "extraProperties": null + } + }, + "jsonExample": { + "union": { + "string": { + "key": "value" + } + } + } + }, + "response": { + "type": "ok", + "value": { + "type": "body", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "boolean", + "boolean": true + } + }, + "jsonExample": true + } + } + }, + "docs": null + }, + "codeSamples": null + } + ], + "autogeneratedExamples": [ + { + "example": { + "id": "6da7959a", + "url": "/call", + "name": null, + "endpointHeaders": [], + "endpointPathParameters": [], + "queryParameters": [], + "servicePathParameters": [], + "serviceHeaders": [], + "rootPathParameters": [], + "request": { + "type": "reference", + "shape": { + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "union", + "originalTypeDeclaration": { + "name": "Request", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:Request" + }, + "value": { + "shape": { + "type": "container", + "container": { + "type": "optional", + "optional": null, + "valueType": { + "_type": "named", + "name": "MetadataUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:MetadataUnion", + "default": null, + "inline": null + } + } + } + }, + "propertyAccess": null + } + ], + "extraProperties": null + }, + "typeName": { + "name": "Request", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:Request" + } + }, + "jsonExample": {} + }, + "response": { + "type": "ok", + "value": { + "type": "body", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "boolean", + "boolean": true + } + }, + "jsonExample": true + } + } + }, + "docs": null + } + } + ], + "pagination": null, + "transport": null, + "v2Examples": null, + "source": null, + "audiences": null, + "retries": null, + "apiPlayground": null, + "responseHeaders": [], + "availability": null, + "docs": null + }, + { + "id": "endpoint_union.duplicateTypesUnion", + "name": "duplicateTypesUnion", + "displayName": null, + "auth": false, + "security": null, + "idempotent": false, + "baseUrl": null, + "v2BaseUrls": null, + "method": "POST", + "basePath": null, + "path": { + "head": "/duplicate", + "parts": [] + }, + "fullPath": { + "head": "/duplicate", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "reference", + "requestBodyType": { + "_type": "named", + "name": "UnionWithDuplicateTypes", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:UnionWithDuplicateTypes", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + }, + "v2RequestBodies": null, + "sdkRequest": { + "shape": { + "type": "justRequestBody", + "value": { + "type": "typeReference", + "requestBodyType": { + "_type": "named", + "name": "UnionWithDuplicateTypes", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:UnionWithDuplicateTypes", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + } + }, + "requestParameterName": "request", + "streamParameter": null + }, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "named", + "name": "UnionWithDuplicateTypes", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:UnionWithDuplicateTypes", + "default": null, + "inline": null + }, + "docs": null, + "v2Examples": null + } + }, + "status-code": null, + "isWildcardStatusCode": null, + "docs": null + }, + "v2Responses": null, + "errors": [], + "userSpecifiedExamples": [], + "autogeneratedExamples": [ + { + "example": { + "id": "6c3861a1", + "url": "/duplicate", + "name": null, + "endpointHeaders": [], + "endpointPathParameters": [], + "queryParameters": [], + "servicePathParameters": [], + "serviceHeaders": [], + "rootPathParameters": [], + "request": { + "type": "reference", + "shape": { + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + } + }, + "typeName": { + "name": "UnionWithDuplicateTypes", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:UnionWithDuplicateTypes" + } + }, + "jsonExample": "string" + }, + "response": { + "type": "ok", + "value": { + "type": "body", + "value": { + "shape": { + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + } + }, + "typeName": { + "name": "UnionWithDuplicateTypes", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" }, - "propertyAccess": null + "displayName": null, + "typeId": "type_union:UnionWithDuplicateTypes" } - ], - "extraProperties": null + }, + "jsonExample": "string" } + } + }, + "docs": null + } + } + ], + "pagination": null, + "transport": null, + "v2Examples": null, + "source": null, + "audiences": null, + "retries": null, + "apiPlayground": null, + "responseHeaders": [], + "availability": null, + "docs": null + }, + { + "id": "endpoint_union.nestedUnions", + "name": "nestedUnions", + "displayName": null, + "auth": false, + "security": null, + "idempotent": false, + "baseUrl": null, + "v2BaseUrls": null, + "method": "POST", + "basePath": null, + "path": { + "head": "/nested", + "parts": [] + }, + "fullPath": { + "head": "/nested", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "reference", + "requestBodyType": { + "_type": "named", + "name": "NestedUnionRoot", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NestedUnionRoot", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + }, + "v2RequestBodies": null, + "sdkRequest": { + "shape": { + "type": "justRequestBody", + "value": { + "type": "typeReference", + "requestBodyType": { + "_type": "named", + "name": "NestedUnionRoot", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" }, - "jsonExample": { - "union": { - "string": { - "key": "value" - } + "displayName": null, + "typeId": "type_union:NestedUnionRoot", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + } + }, + "requestParameterName": "request", + "streamParameter": null + }, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null } } }, + "docs": null, + "v2Examples": null + } + }, + "status-code": null, + "isWildcardStatusCode": null, + "docs": null + }, + "v2Responses": null, + "errors": [], + "userSpecifiedExamples": [], + "autogeneratedExamples": [ + { + "example": { + "id": "573ea2eb", + "url": "/nested", + "name": null, + "endpointHeaders": [], + "endpointPathParameters": [], + "queryParameters": [], + "servicePathParameters": [], + "serviceHeaders": [], + "rootPathParameters": [], + "request": { + "type": "reference", + "shape": { + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" + } + } + }, + "jsonExample": "string" + } + }, + "typeName": { + "name": "NestedUnionRoot", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NestedUnionRoot" + } + }, + "jsonExample": "string" + }, "response": { "type": "ok", "value": { @@ -3474,24 +4703,136 @@ "shape": { "type": "primitive", "primitive": { - "type": "boolean", - "boolean": true + "type": "string", + "string": { + "original": "string" + } } }, - "jsonExample": true + "jsonExample": "string" } } }, "docs": null - }, - "codeSamples": null + } } ], + "pagination": null, + "transport": null, + "v2Examples": null, + "source": null, + "audiences": null, + "retries": null, + "apiPlayground": null, + "responseHeaders": [], + "availability": null, + "docs": null + }, + { + "id": "endpoint_union.nestedObjectUnions", + "name": "nestedObjectUnions", + "displayName": null, + "auth": false, + "security": null, + "idempotent": false, + "baseUrl": null, + "v2BaseUrls": null, + "method": "POST", + "basePath": null, + "path": { + "head": "/nested-objects", + "parts": [] + }, + "fullPath": { + "head": "/nested-objects", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "reference", + "requestBodyType": { + "_type": "named", + "name": "OuterNestedUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:OuterNestedUnion", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + }, + "v2RequestBodies": null, + "sdkRequest": { + "shape": { + "type": "justRequestBody", + "value": { + "type": "typeReference", + "requestBodyType": { + "_type": "named", + "name": "OuterNestedUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:OuterNestedUnion", + "default": null, + "inline": null + }, + "docs": null, + "contentType": null, + "v2Examples": null + } + }, + "requestParameterName": "request", + "streamParameter": null + }, + "response": { + "body": { + "type": "json", + "value": { + "type": "response", + "responseBodyType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "docs": null, + "v2Examples": null + } + }, + "status-code": null, + "isWildcardStatusCode": null, + "docs": null + }, + "v2Responses": null, + "errors": [], + "userSpecifiedExamples": [], "autogeneratedExamples": [ { "example": { - "id": "6da7959a", - "url": "/call", + "id": "c380fb0f", + "url": "/nested-objects", "name": null, "endpointHeaders": [], "endpointPathParameters": [], @@ -3502,55 +4843,25 @@ "request": { "type": "reference", "shape": { - "type": "named", - "shape": { - "type": "object", - "properties": [ - { - "name": "union", - "originalTypeDeclaration": { - "name": "Request", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:Request" - }, - "value": { - "shape": { - "type": "container", - "container": { - "type": "optional", - "optional": null, - "valueType": { - "_type": "named", - "name": "MetadataUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:MetadataUnion", - "default": null, - "inline": null - } - } + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" } - }, - "propertyAccess": null - } - ], - "extraProperties": null + } + }, + "jsonExample": "string" + } }, "typeName": { - "name": "Request", + "name": "OuterNestedUnion", "fernFilepath": { "allParts": [ "union" @@ -3559,10 +4870,10 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:Request" + "typeId": "type_union:OuterNestedUnion" } }, - "jsonExample": {} + "jsonExample": "string" }, "response": { "type": "ok", @@ -3572,11 +4883,13 @@ "shape": { "type": "primitive", "primitive": { - "type": "boolean", - "boolean": true + "type": "string", + "string": { + "original": "string" + } } }, - "jsonExample": true + "jsonExample": "string" } } }, @@ -3596,8 +4909,8 @@ "docs": null }, { - "id": "endpoint_union.duplicateTypesUnion", - "name": "duplicateTypesUnion", + "id": "endpoint_union.aliasedObjectUnion", + "name": "aliasedObjectUnion", "displayName": null, "auth": false, "security": null, @@ -3607,11 +4920,11 @@ "method": "POST", "basePath": null, "path": { - "head": "/duplicate", + "head": "/aliased-object", "parts": [] }, "fullPath": { - "head": "/duplicate", + "head": "/aliased-object", "parts": [] }, "pathParameters": [], @@ -3622,7 +4935,7 @@ "type": "reference", "requestBodyType": { "_type": "named", - "name": "UnionWithDuplicateTypes", + "name": "AliasedObjectUnion", "fernFilepath": { "allParts": [ "union" @@ -3631,7 +4944,7 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:UnionWithDuplicateTypes", + "typeId": "type_union:AliasedObjectUnion", "default": null, "inline": null }, @@ -3647,7 +4960,7 @@ "type": "typeReference", "requestBodyType": { "_type": "named", - "name": "UnionWithDuplicateTypes", + "name": "AliasedObjectUnion", "fernFilepath": { "allParts": [ "union" @@ -3656,7 +4969,7 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:UnionWithDuplicateTypes", + "typeId": "type_union:AliasedObjectUnion", "default": null, "inline": null }, @@ -3674,19 +4987,15 @@ "value": { "type": "response", "responseBodyType": { - "_type": "named", - "name": "UnionWithDuplicateTypes", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:UnionWithDuplicateTypes", - "default": null, - "inline": null + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } }, "docs": null, "v2Examples": null @@ -3702,8 +5011,8 @@ "autogeneratedExamples": [ { "example": { - "id": "6c3861a1", - "url": "/duplicate", + "id": "44120f0f", + "url": "/aliased-object", "name": null, "endpointHeaders": [], "endpointPathParameters": [], @@ -3720,19 +5029,112 @@ "index": 0, "singleUnionType": { "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" + "type": "named", + "shape": { + "type": "alias", + "value": { + "shape": { + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "onlyInA", + "originalTypeDeclaration": { + "name": "LeafObjectA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectA" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "onlyInA" + } + } + }, + "jsonExample": "onlyInA" + }, + "propertyAccess": null + }, + { + "name": "sharedNumber", + "originalTypeDeclaration": { + "name": "LeafObjectA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectA" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "integer", + "integer": 1 + } + }, + "jsonExample": 1 + }, + "propertyAccess": null + } + ], + "extraProperties": null + }, + "typeName": { + "name": "LeafObjectA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:LeafObjectA" + } + }, + "jsonExample": { + "onlyInA": "onlyInA", + "sharedNumber": 1 + } } + }, + "typeName": { + "name": "AliasedLeafA", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:AliasedLeafA" } }, - "jsonExample": "string" + "jsonExample": { + "onlyInA": "onlyInA", + "sharedNumber": 1 + } } }, "typeName": { - "name": "UnionWithDuplicateTypes", + "name": "AliasedObjectUnion", "fernFilepath": { "allParts": [ "union" @@ -3741,10 +5143,13 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:UnionWithDuplicateTypes" + "typeId": "type_union:AliasedObjectUnion" } }, - "jsonExample": "string" + "jsonExample": { + "onlyInA": "onlyInA", + "sharedNumber": 1 + } }, "response": { "type": "ok", @@ -3752,34 +5157,12 @@ "type": "body", "value": { "shape": { - "type": "named", - "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" - } - } - }, - "jsonExample": "string" + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" } - }, - "typeName": { - "name": "UnionWithDuplicateTypes", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:UnionWithDuplicateTypes" } }, "jsonExample": "string" @@ -3802,8 +5185,8 @@ "docs": null }, { - "id": "endpoint_union.nestedUnions", - "name": "nestedUnions", + "id": "endpoint_union.getWithBaseProperties", + "name": "getWithBaseProperties", "displayName": null, "auth": false, "security": null, @@ -3813,11 +5196,11 @@ "method": "POST", "basePath": null, "path": { - "head": "/nested", + "head": "/with-base-properties", "parts": [] }, "fullPath": { - "head": "/nested", + "head": "/with-base-properties", "parts": [] }, "pathParameters": [], @@ -3828,7 +5211,7 @@ "type": "reference", "requestBodyType": { "_type": "named", - "name": "NestedUnionRoot", + "name": "UnionWithBaseProperties", "fernFilepath": { "allParts": [ "union" @@ -3837,7 +5220,7 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:NestedUnionRoot", + "typeId": "type_union:UnionWithBaseProperties", "default": null, "inline": null }, @@ -3853,7 +5236,7 @@ "type": "typeReference", "requestBodyType": { "_type": "named", - "name": "NestedUnionRoot", + "name": "UnionWithBaseProperties", "fernFilepath": { "allParts": [ "union" @@ -3862,7 +5245,7 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:NestedUnionRoot", + "typeId": "type_union:UnionWithBaseProperties", "default": null, "inline": null }, @@ -3880,15 +5263,19 @@ "value": { "type": "response", "responseBodyType": { - "_type": "primitive", - "primitive": { - "v1": "STRING", - "v2": { - "type": "string", - "default": null, - "validation": null - } - } + "_type": "named", + "name": "UnionWithBaseProperties", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:UnionWithBaseProperties", + "default": null, + "inline": null }, "docs": null, "v2Examples": null @@ -3904,8 +5291,8 @@ "autogeneratedExamples": [ { "example": { - "id": "573ea2eb", - "url": "/nested", + "id": "34a9e829", + "url": "/with-base-properties", "name": null, "endpointHeaders": [], "endpointPathParameters": [], @@ -3922,19 +5309,136 @@ "index": 0, "singleUnionType": { "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" - } + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "name", + "originalTypeDeclaration": { + "name": "NamedMetadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NamedMetadata" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "name" + } + } + }, + "jsonExample": "name" + }, + "propertyAccess": null + }, + { + "name": "value", + "originalTypeDeclaration": { + "name": "NamedMetadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NamedMetadata" + }, + "value": { + "shape": { + "type": "container", + "container": { + "type": "map", + "map": [ + { + "key": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "value" + } + } + }, + "jsonExample": "value" + }, + "value": { + "shape": { + "type": "unknown", + "unknown": { + "key": "value" + } + }, + "jsonExample": { + "key": "value" + } + } + } + ], + "keyType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "valueType": { + "_type": "unknown" + } + } + }, + "jsonExample": { + "value": { + "key": "value" + } + } + }, + "propertyAccess": null + } + ], + "extraProperties": null + }, + "typeName": { + "name": "NamedMetadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NamedMetadata" } }, - "jsonExample": "string" + "jsonExample": { + "name": "name", + "value": { + "value": { + "key": "value" + } + } + } } }, "typeName": { - "name": "NestedUnionRoot", + "name": "UnionWithBaseProperties", "fernFilepath": { "allParts": [ "union" @@ -3943,10 +5447,17 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:NestedUnionRoot" + "typeId": "type_union:UnionWithBaseProperties" } }, - "jsonExample": "string" + "jsonExample": { + "name": "name", + "value": { + "value": { + "key": "value" + } + } + } }, "response": { "type": "ok", @@ -3954,15 +5465,161 @@ "type": "body", "value": { "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "name", + "originalTypeDeclaration": { + "name": "NamedMetadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NamedMetadata" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "name" + } + } + }, + "jsonExample": "name" + }, + "propertyAccess": null + }, + { + "name": "value", + "originalTypeDeclaration": { + "name": "NamedMetadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NamedMetadata" + }, + "value": { + "shape": { + "type": "container", + "container": { + "type": "map", + "map": [ + { + "key": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "value" + } + } + }, + "jsonExample": "value" + }, + "value": { + "shape": { + "type": "unknown", + "unknown": { + "key": "value" + } + }, + "jsonExample": { + "key": "value" + } + } + } + ], + "keyType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "valueType": { + "_type": "unknown" + } + } + }, + "jsonExample": { + "value": { + "key": "value" + } + } + }, + "propertyAccess": null + } + ], + "extraProperties": null + }, + "typeName": { + "name": "NamedMetadata", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:NamedMetadata" + } + }, + "jsonExample": { + "name": "name", + "value": { + "value": { + "key": "value" + } + } + } } + }, + "typeName": { + "name": "UnionWithBaseProperties", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:UnionWithBaseProperties" } }, - "jsonExample": "string" + "jsonExample": { + "name": "name", + "value": { + "value": { + "key": "value" + } + } + } } } }, @@ -3982,8 +5639,8 @@ "docs": null }, { - "id": "endpoint_union.getWithBaseProperties", - "name": "getWithBaseProperties", + "id": "endpoint_union.testCamelCaseProperties", + "name": "testCamelCaseProperties", "displayName": null, "auth": false, "security": null, @@ -3993,11 +5650,11 @@ "method": "POST", "basePath": null, "path": { - "head": "/with-base-properties", + "head": "/camel-case", "parts": [] }, "fullPath": { - "head": "/with-base-properties", + "head": "/camel-case", "parts": [] }, "pathParameters": [], @@ -4005,35 +5662,15 @@ "queryParameters": [], "headers": [], "requestBody": { - "type": "reference", - "requestBodyType": { - "_type": "named", - "name": "UnionWithBaseProperties", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:UnionWithBaseProperties", - "default": null, - "inline": null - }, - "docs": null, - "contentType": null, - "v2Examples": null - }, - "v2RequestBodies": null, - "sdkRequest": { - "shape": { - "type": "justRequestBody", - "value": { - "type": "typeReference", - "requestBodyType": { + "type": "inlinedRequestBody", + "name": "PaymentRequest", + "extends": [], + "properties": [ + { + "name": "paymentMethod", + "valueType": { "_type": "named", - "name": "UnionWithBaseProperties", + "name": "PaymentMethodUnion", "fernFilepath": { "allParts": [ "union" @@ -4042,14 +5679,33 @@ "file": "union" }, "displayName": null, - "typeId": "type_union:UnionWithBaseProperties", + "typeId": "type_union:PaymentMethodUnion", "default": null, "inline": null }, - "docs": null, - "contentType": null, - "v2Examples": null + "v2Examples": { + "userSpecifiedExamples": {}, + "autogeneratedExamples": {} + }, + "propertyAccess": null, + "availability": null, + "docs": null } + ], + "extra-properties": false, + "extendedProperties": [], + "docs": null, + "v2Examples": null, + "contentType": null + }, + "v2RequestBodies": null, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": "PaymentRequest", + "bodyKey": "body", + "includePathParameters": false, + "onlyPathParameters": false }, "requestParameterName": "request", "streamParameter": null @@ -4060,19 +5716,15 @@ "value": { "type": "response", "responseBodyType": { - "_type": "named", - "name": "UnionWithBaseProperties", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:UnionWithBaseProperties", - "default": null, - "inline": null + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } }, "docs": null, "v2Examples": null @@ -4084,64 +5736,46 @@ }, "v2Responses": null, "errors": [], - "userSpecifiedExamples": [], - "autogeneratedExamples": [ + "userSpecifiedExamples": [ { "example": { - "id": "34a9e829", - "url": "/with-base-properties", + "id": "bde8080f", "name": null, - "endpointHeaders": [], + "url": "/camel-case", + "rootPathParameters": [], "endpointPathParameters": [], - "queryParameters": [], "servicePathParameters": [], + "endpointHeaders": [], "serviceHeaders": [], - "rootPathParameters": [], + "queryParameters": [], "request": { - "type": "reference", - "shape": { - "type": "named", - "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": "paymentMethod", + "value": { "shape": { "type": "named", + "typeName": { + "typeId": "type_union:PaymentMethodUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "name": "PaymentMethodUnion", + "displayName": null + }, "shape": { - "type": "object", - "properties": [ - { - "name": "name", - "originalTypeDeclaration": { - "name": "NamedMetadata", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:NamedMetadata" - }, - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "name" - } - } - }, - "jsonExample": "name" - }, - "propertyAccess": null - }, - { - "name": "value", - "originalTypeDeclaration": { - "name": "NamedMetadata", + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { + "shape": { + "type": "named", + "typeName": { + "typeId": "type_union:TokenizeCard", "fernFilepath": { "allParts": [ "union" @@ -4149,110 +5783,92 @@ "packagePath": [], "file": "union" }, - "displayName": null, - "typeId": "type_union:NamedMetadata" + "name": "TokenizeCard", + "displayName": null }, - "value": { - "shape": { - "type": "container", - "container": { - "type": "map", - "map": [ - { - "key": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "value" - } - } - }, - "jsonExample": "value" - }, - "value": { - "shape": { - "type": "unknown", - "unknown": { - "key": "value" - } - }, - "jsonExample": { - "key": "value" + "shape": { + "type": "object", + "properties": [ + { + "name": "method", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "card" } } - } - ], - "keyType": { - "_type": "primitive", - "primitive": { - "v1": "STRING", - "v2": { + }, + "jsonExample": "card" + }, + "originalTypeDeclaration": { + "typeId": "type_union:TokenizeCard", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "name": "TokenizeCard", + "displayName": null + }, + "propertyAccess": null + }, + { + "name": "cardNumber", + "value": { + "shape": { + "type": "primitive", + "primitive": { "type": "string", - "default": null, - "validation": null + "string": { + "original": "1234567890123456" + } } - } + }, + "jsonExample": "1234567890123456" }, - "valueType": { - "_type": "unknown" - } - } - }, - "jsonExample": { - "value": { - "key": "value" + "originalTypeDeclaration": { + "typeId": "type_union:TokenizeCard", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "name": "TokenizeCard", + "displayName": null + }, + "propertyAccess": null } - } - }, - "propertyAccess": null + ], + "extraProperties": null + } + }, + "jsonExample": { + "method": "card", + "cardNumber": "1234567890123456" } - ], - "extraProperties": null - }, - "typeName": { - "name": "NamedMetadata", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:NamedMetadata" + } } }, "jsonExample": { - "name": "name", - "value": { - "value": { - "key": "value" - } - } + "method": "card", + "cardNumber": "1234567890123456" } - } - }, - "typeName": { - "name": "UnionWithBaseProperties", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" }, - "displayName": null, - "typeId": "type_union:UnionWithBaseProperties" + "originalTypeDeclaration": null } - }, + ], + "extraProperties": null, "jsonExample": { - "name": "name", - "value": { - "value": { - "key": "value" - } + "paymentMethod": { + "method": "card", + "cardNumber": "1234567890123456" } } }, @@ -4262,678 +5878,945 @@ "type": "body", "value": { "shape": { - "type": "named", + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "success" + } + } + }, + "jsonExample": "success" + } + } + }, + "docs": null + }, + "codeSamples": null + } + ], + "autogeneratedExamples": [ + { + "example": { + "id": "4593ae88", + "url": "/camel-case", + "name": null, + "endpointHeaders": [], + "endpointPathParameters": [], + "queryParameters": [], + "servicePathParameters": [], + "serviceHeaders": [], + "rootPathParameters": [], + "request": { + "type": "inlinedRequestBody", + "properties": [ + { + "name": "paymentMethod", + "originalTypeDeclaration": null, + "value": { "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { - "shape": { - "type": "named", + "type": "named", + "shape": { + "type": "undiscriminatedUnion", + "index": 0, + "singleUnionType": { "shape": { - "type": "object", - "properties": [ - { - "name": "name", - "originalTypeDeclaration": { - "name": "NamedMetadata", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" + "type": "named", + "shape": { + "type": "object", + "properties": [ + { + "name": "method", + "originalTypeDeclaration": { + "name": "TokenizeCard", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:TokenizeCard" }, - "displayName": null, - "typeId": "type_union:NamedMetadata" - }, - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "name" + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "method" + } } - } - }, - "jsonExample": "name" - }, - "propertyAccess": null - }, - { - "name": "value", - "originalTypeDeclaration": { - "name": "NamedMetadata", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" + }, + "jsonExample": "method" }, - "displayName": null, - "typeId": "type_union:NamedMetadata" + "propertyAccess": null }, - "value": { - "shape": { - "type": "container", - "container": { - "type": "map", - "map": [ - { - "key": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "value" - } - } - }, - "jsonExample": "value" - }, - "value": { - "shape": { - "type": "unknown", - "unknown": { - "key": "value" - } - }, - "jsonExample": { - "key": "value" - } - } - } + { + "name": "cardNumber", + "originalTypeDeclaration": { + "name": "TokenizeCard", + "fernFilepath": { + "allParts": [ + "union" ], - "keyType": { - "_type": "primitive", - "primitive": { - "v1": "STRING", - "v2": { - "type": "string", - "default": null, - "validation": null - } + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:TokenizeCard" + }, + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "cardNumber" } - }, - "valueType": { - "_type": "unknown" } - } + }, + "jsonExample": "cardNumber" }, - "jsonExample": { - "value": { - "key": "value" - } - } - }, - "propertyAccess": null - } - ], - "extraProperties": null - }, - "typeName": { - "name": "NamedMetadata", - "fernFilepath": { - "allParts": [ - "union" + "propertyAccess": null + } ], - "packagePath": [], - "file": "union" + "extraProperties": null }, - "displayName": null, - "typeId": "type_union:NamedMetadata" - } - }, - "jsonExample": { - "name": "name", - "value": { - "value": { - "key": "value" + "typeName": { + "name": "TokenizeCard", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:TokenizeCard" } + }, + "jsonExample": { + "method": "method", + "cardNumber": "cardNumber" } } + }, + "typeName": { + "name": "PaymentMethodUnion", + "fernFilepath": { + "allParts": [ + "union" + ], + "packagePath": [], + "file": "union" + }, + "displayName": null, + "typeId": "type_union:PaymentMethodUnion" } }, - "typeName": { - "name": "UnionWithBaseProperties", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:UnionWithBaseProperties" + "jsonExample": { + "method": "method", + "cardNumber": "cardNumber" } - }, - "jsonExample": { - "name": "name", - "value": { - "value": { - "key": "value" + } + } + ], + "extraProperties": null, + "jsonExample": { + "paymentMethod": { + "method": "method", + "cardNumber": "cardNumber" + } + } + }, + "response": { + "type": "ok", + "value": { + "type": "body", + "value": { + "shape": { + "type": "primitive", + "primitive": { + "type": "string", + "string": { + "original": "string" } } - } + }, + "jsonExample": "string" } } }, - "docs": null + "docs": null + } + } + ], + "pagination": null, + "transport": null, + "v2Examples": null, + "source": null, + "audiences": null, + "retries": null, + "apiPlayground": null, + "responseHeaders": [], + "availability": null, + "docs": null + } + ], + "audiences": null + } + }, + "constants": { + "errorInstanceIdKey": "errorInstanceId" + }, + "environments": null, + "errorDiscriminationStrategy": { + "type": "statusCode" + }, + "basePath": null, + "pathParameters": [], + "variables": [], + "serviceTypeReferenceInfo": { + "typesReferencedOnlyByService": { + "service_union": [ + "type_union:Request", + "type_union:MyUnion", + "type_union:NestedUnionL2", + "type_union:NestedUnionL1", + "type_union:NestedUnionRoot", + "type_union:UnionWithDuplicateTypes", + "type_union:MetadataUnion", + "type_union:NamedMetadata", + "type_union:OptionalMetadata", + "type_union:Metadata", + "type_union:Key", + "type_union:KeyType", + "type_union:UnionWithBaseProperties", + "type_union:PaymentMethodUnion", + "type_union:TokenizeCard", + "type_union:ConvertToken", + "type_union:LeafTypeA", + "type_union:LeafTypeB", + "type_union:NestedObjectUnion", + "type_union:WrapperObject", + "type_union:OuterNestedUnion", + "type_union:AliasedLeafA", + "type_union:AliasedLeafB", + "type_union:AliasToLeafB", + "type_union:LeafObjectA", + "type_union:LeafObjectB", + "type_union:AliasedObjectUnion" + ] + }, + "sharedTypes": [ + "type_union:TypeWithOptionalUnion", + "type_union:UnionWithIdenticalStrings", + "type_union:UnionWithIdenticalPrimitives", + "type_union:UnionWithReservedNames", + "type_union:UserId", + "type_union:Name", + "type_union:UnionWithTypeAliases" + ] + }, + "webhookGroups": {}, + "websocketChannels": {}, + "readmeConfig": null, + "sourceConfig": null, + "publishConfig": null, + "dynamic": { + "version": "1.0.0", + "types": { + "type_union:Request": { + "type": "object", + "declaration": { + "name": { + "originalName": "Request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "union", + "name": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "named", + "value": "type_union:MetadataUnion" } + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:TypeWithOptionalUnion": { + "type": "object", + "declaration": { + "name": { + "originalName": "TypeWithOptionalUnion", + "camelCase": { + "unsafeName": "typeWithOptionalUnion", + "safeName": "typeWithOptionalUnion" + }, + "snakeCase": { + "unsafeName": "type_with_optional_union", + "safeName": "type_with_optional_union" + }, + "screamingSnakeCase": { + "unsafeName": "TYPE_WITH_OPTIONAL_UNION", + "safeName": "TYPE_WITH_OPTIONAL_UNION" + }, + "pascalCase": { + "unsafeName": "TypeWithOptionalUnion", + "safeName": "TypeWithOptionalUnion" } - ], - "pagination": null, - "transport": null, - "v2Examples": null, - "source": null, - "audiences": null, - "retries": null, - "apiPlayground": null, - "responseHeaders": [], - "availability": null, - "docs": null - }, - { - "id": "endpoint_union.testCamelCaseProperties", - "name": "testCamelCaseProperties", - "displayName": null, - "auth": false, - "security": null, - "idempotent": false, - "baseUrl": null, - "v2BaseUrls": null, - "method": "POST", - "basePath": null, - "path": { - "head": "/camel-case", - "parts": [] }, - "fullPath": { - "head": "/camel-case", - "parts": [] + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "myUnion", + "name": { + "originalName": "myUnion", + "camelCase": { + "unsafeName": "myUnion", + "safeName": "myUnion" + }, + "snakeCase": { + "unsafeName": "my_union", + "safeName": "my_union" + }, + "screamingSnakeCase": { + "unsafeName": "MY_UNION", + "safeName": "MY_UNION" + }, + "pascalCase": { + "unsafeName": "MyUnion", + "safeName": "MyUnion" + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "named", + "value": "type_union:MyUnion" + } + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false + }, + "type_union:MyUnion": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "MyUnion", + "camelCase": { + "unsafeName": "myUnion", + "safeName": "myUnion" + }, + "snakeCase": { + "unsafeName": "my_union", + "safeName": "my_union" + }, + "screamingSnakeCase": { + "unsafeName": "MY_UNION", + "safeName": "MY_UNION" + }, + "pascalCase": { + "unsafeName": "MyUnion", + "safeName": "MyUnion" + } }, - "pathParameters": [], - "allPathParameters": [], - "queryParameters": [], - "headers": [], - "requestBody": { - "type": "inlinedRequestBody", - "name": "PaymentRequest", - "extends": [], - "properties": [ + "fernFilepath": { + "allParts": [ { - "name": "paymentMethod", - "valueType": { - "_type": "named", - "name": "PaymentMethodUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:PaymentMethodUnion", - "default": null, - "inline": null + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" }, - "v2Examples": { - "userSpecifiedExamples": {}, - "autogeneratedExamples": {} + "snakeCase": { + "unsafeName": "union", + "safeName": "union" }, - "propertyAccess": null, - "availability": null, - "docs": null + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } } ], - "extra-properties": false, - "extendedProperties": [], - "docs": null, - "v2Examples": null, - "contentType": null + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "types": [ + { + "type": "primitive", + "value": "STRING" }, - "v2RequestBodies": null, - "sdkRequest": { - "shape": { - "type": "wrapper", - "wrapperName": "PaymentRequest", - "bodyKey": "body", - "includePathParameters": false, - "onlyPathParameters": false - }, - "requestParameterName": "request", - "streamParameter": null + { + "type": "list", + "value": { + "type": "primitive", + "value": "STRING" + } }, - "response": { - "body": { - "type": "json", + { + "type": "primitive", + "value": "INTEGER" + }, + { + "type": "list", + "value": { + "type": "primitive", + "value": "INTEGER" + } + }, + { + "type": "list", + "value": { + "type": "list", "value": { - "type": "response", - "responseBodyType": { - "_type": "primitive", - "primitive": { - "v1": "STRING", - "v2": { - "type": "string", - "default": null, - "validation": null - } - } - }, - "docs": null, - "v2Examples": null + "type": "primitive", + "value": "INTEGER" } + } + }, + { + "type": "set", + "value": { + "type": "primitive", + "value": "STRING" + } + } + ] + }, + "type_union:NestedUnionL2": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "NestedUnionL2", + "camelCase": { + "unsafeName": "nestedUnionL2", + "safeName": "nestedUnionL2" }, - "status-code": null, - "isWildcardStatusCode": null, - "docs": null + "snakeCase": { + "unsafeName": "nested_union_l2", + "safeName": "nested_union_l2" + }, + "screamingSnakeCase": { + "unsafeName": "NESTED_UNION_L2", + "safeName": "NESTED_UNION_L2" + }, + "pascalCase": { + "unsafeName": "NestedUnionL2", + "safeName": "NestedUnionL2" + } }, - "v2Responses": null, - "errors": [], - "userSpecifiedExamples": [ - { - "example": { - "id": "bde8080f", - "name": null, - "url": "/camel-case", - "rootPathParameters": [], - "endpointPathParameters": [], - "servicePathParameters": [], - "endpointHeaders": [], - "serviceHeaders": [], - "queryParameters": [], - "request": { - "type": "inlinedRequestBody", - "properties": [ - { - "name": "paymentMethod", - "value": { - "shape": { - "type": "named", - "typeName": { - "typeId": "type_union:PaymentMethodUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "name": "PaymentMethodUnion", - "displayName": null - }, - "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { - "shape": { - "type": "named", - "typeName": { - "typeId": "type_union:TokenizeCard", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "name": "TokenizeCard", - "displayName": null - }, - "shape": { - "type": "object", - "properties": [ - { - "name": "method", - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "card" - } - } - }, - "jsonExample": "card" - }, - "originalTypeDeclaration": { - "typeId": "type_union:TokenizeCard", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "name": "TokenizeCard", - "displayName": null - }, - "propertyAccess": null - }, - { - "name": "cardNumber", - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "1234567890123456" - } - } - }, - "jsonExample": "1234567890123456" - }, - "originalTypeDeclaration": { - "typeId": "type_union:TokenizeCard", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "name": "TokenizeCard", - "displayName": null - }, - "propertyAccess": null - } - ], - "extraProperties": null - } - }, - "jsonExample": { - "method": "card", - "cardNumber": "1234567890123456" - } - } - } - }, - "jsonExample": { - "method": "card", - "cardNumber": "1234567890123456" - } - }, - "originalTypeDeclaration": null - } - ], - "extraProperties": null, - "jsonExample": { - "paymentMethod": { - "method": "card", - "cardNumber": "1234567890123456" - } - } - }, - "response": { - "type": "ok", - "value": { - "type": "body", - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "success" - } - } - }, - "jsonExample": "success" - } - } + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" }, - "docs": null + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" }, - "codeSamples": null + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } } - ], - "autogeneratedExamples": [ - { - "example": { - "id": "4593ae88", - "url": "/camel-case", - "name": null, - "endpointHeaders": [], - "endpointPathParameters": [], - "queryParameters": [], - "servicePathParameters": [], - "serviceHeaders": [], - "rootPathParameters": [], - "request": { - "type": "inlinedRequestBody", - "properties": [ - { - "name": "paymentMethod", - "originalTypeDeclaration": null, - "value": { - "shape": { - "type": "named", - "shape": { - "type": "undiscriminatedUnion", - "index": 0, - "singleUnionType": { - "shape": { - "type": "named", - "shape": { - "type": "object", - "properties": [ - { - "name": "method", - "originalTypeDeclaration": { - "name": "TokenizeCard", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:TokenizeCard" - }, - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "method" - } - } - }, - "jsonExample": "method" - }, - "propertyAccess": null - }, - { - "name": "cardNumber", - "originalTypeDeclaration": { - "name": "TokenizeCard", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:TokenizeCard" - }, - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "cardNumber" - } - } - }, - "jsonExample": "cardNumber" - }, - "propertyAccess": null - } - ], - "extraProperties": null - }, - "typeName": { - "name": "TokenizeCard", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:TokenizeCard" - } - }, - "jsonExample": { - "method": "method", - "cardNumber": "cardNumber" - } - } - }, - "typeName": { - "name": "PaymentMethodUnion", - "fernFilepath": { - "allParts": [ - "union" - ], - "packagePath": [], - "file": "union" - }, - "displayName": null, - "typeId": "type_union:PaymentMethodUnion" - } - }, - "jsonExample": { - "method": "method", - "cardNumber": "cardNumber" - } - } - } - ], - "extraProperties": null, - "jsonExample": { - "paymentMethod": { - "method": "method", - "cardNumber": "cardNumber" - } - } + } + }, + "types": [ + { + "type": "primitive", + "value": "BOOLEAN" + }, + { + "type": "set", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + { + "type": "list", + "value": { + "type": "primitive", + "value": "STRING" + } + } + ] + }, + "type_union:NestedUnionL1": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "NestedUnionL1", + "camelCase": { + "unsafeName": "nestedUnionL1", + "safeName": "nestedUnionL1" + }, + "snakeCase": { + "unsafeName": "nested_union_l1", + "safeName": "nested_union_l1" + }, + "screamingSnakeCase": { + "unsafeName": "NESTED_UNION_L1", + "safeName": "NESTED_UNION_L1" + }, + "pascalCase": { + "unsafeName": "NestedUnionL1", + "safeName": "NestedUnionL1" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "types": [ + { + "type": "primitive", + "value": "INTEGER" + }, + { + "type": "set", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + { + "type": "list", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + { + "type": "named", + "value": "type_union:NestedUnionL2" + } + ] + }, + "type_union:NestedUnionRoot": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "NestedUnionRoot", + "camelCase": { + "unsafeName": "nestedUnionRoot", + "safeName": "nestedUnionRoot" + }, + "snakeCase": { + "unsafeName": "nested_union_root", + "safeName": "nested_union_root" + }, + "screamingSnakeCase": { + "unsafeName": "NESTED_UNION_ROOT", + "safeName": "NESTED_UNION_ROOT" + }, + "pascalCase": { + "unsafeName": "NestedUnionRoot", + "safeName": "NestedUnionRoot" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" }, - "response": { - "type": "ok", - "value": { - "type": "body", - "value": { - "shape": { - "type": "primitive", - "primitive": { - "type": "string", - "string": { - "original": "string" - } - } - }, - "jsonExample": "string" - } - } + "snakeCase": { + "unsafeName": "union", + "safeName": "union" }, - "docs": null + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" } } - ], - "pagination": null, - "transport": null, - "v2Examples": null, - "source": null, - "audiences": null, - "retries": null, - "apiPlayground": null, - "responseHeaders": [], - "availability": null, - "docs": null - } - ], - "audiences": null - } - }, - "constants": { - "errorInstanceIdKey": "errorInstanceId" - }, - "environments": null, - "errorDiscriminationStrategy": { - "type": "statusCode" - }, - "basePath": null, - "pathParameters": [], - "variables": [], - "serviceTypeReferenceInfo": { - "typesReferencedOnlyByService": { - "service_union": [ - "type_union:Request", - "type_union:MyUnion", - "type_union:NestedUnionL2", - "type_union:NestedUnionL1", - "type_union:NestedUnionRoot", - "type_union:UnionWithDuplicateTypes", - "type_union:MetadataUnion", - "type_union:NamedMetadata", - "type_union:OptionalMetadata", - "type_union:Metadata", - "type_union:Key", - "type_union:KeyType", - "type_union:UnionWithBaseProperties", - "type_union:PaymentMethodUnion", - "type_union:TokenizeCard", - "type_union:ConvertToken" - ] - }, - "sharedTypes": [ - "type_union:TypeWithOptionalUnion", - "type_union:UnionWithIdenticalStrings", - "type_union:UnionWithIdenticalPrimitives", - "type_union:UnionWithReservedNames", - "type_union:UserId", - "type_union:Name", - "type_union:UnionWithTypeAliases" - ] - }, - "webhookGroups": {}, - "websocketChannels": {}, - "readmeConfig": null, - "sourceConfig": null, - "publishConfig": null, - "dynamic": { - "version": "1.0.0", - "types": { - "type_union:Request": { - "type": "object", + } + }, + "types": [ + { + "type": "primitive", + "value": "STRING" + }, + { + "type": "list", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + { + "type": "named", + "value": "type_union:NestedUnionL1" + } + ] + }, + "type_union:UnionWithDuplicateTypes": { + "type": "undiscriminatedUnion", + "declaration": { + "name": { + "originalName": "UnionWithDuplicateTypes", + "camelCase": { + "unsafeName": "unionWithDuplicateTypes", + "safeName": "unionWithDuplicateTypes" + }, + "snakeCase": { + "unsafeName": "union_with_duplicate_types", + "safeName": "union_with_duplicate_types" + }, + "screamingSnakeCase": { + "unsafeName": "UNION_WITH_DUPLICATE_TYPES", + "safeName": "UNION_WITH_DUPLICATE_TYPES" + }, + "pascalCase": { + "unsafeName": "UnionWithDuplicateTypes", + "safeName": "UnionWithDuplicateTypes" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "types": [ + { + "type": "primitive", + "value": "STRING" + }, + { + "type": "list", + "value": { + "type": "primitive", + "value": "STRING" + } + }, + { + "type": "primitive", + "value": "INTEGER" + }, + { + "type": "set", + "value": { + "type": "primitive", + "value": "STRING" + } + } + ] + }, + "type_union:MetadataUnion": { + "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "Request", + "originalName": "MetadataUnion", "camelCase": { - "unsafeName": "request", - "safeName": "request" + "unsafeName": "metadataUnion", + "safeName": "metadataUnion" }, "snakeCase": { - "unsafeName": "request", - "safeName": "request" + "unsafeName": "metadata_union", + "safeName": "metadata_union" }, "screamingSnakeCase": { - "unsafeName": "REQUEST", - "safeName": "REQUEST" + "unsafeName": "METADATA_UNION", + "safeName": "METADATA_UNION" }, "pascalCase": { - "unsafeName": "Request", - "safeName": "Request" + "unsafeName": "MetadataUnion", + "safeName": "MetadataUnion" } }, "fernFilepath": { @@ -4980,11 +6863,42 @@ } } }, - "properties": [ + "types": [ { - "name": { - "wireValue": "union", - "name": { + "type": "named", + "value": "type_union:OptionalMetadata" + }, + { + "type": "named", + "value": "type_union:NamedMetadata" + } + ] + }, + "type_union:NamedMetadata": { + "type": "object", + "declaration": { + "name": { + "originalName": "NamedMetadata", + "camelCase": { + "unsafeName": "namedMetadata", + "safeName": "namedMetadata" + }, + "snakeCase": { + "unsafeName": "named_metadata", + "safeName": "named_metadata" + }, + "screamingSnakeCase": { + "unsafeName": "NAMED_METADATA", + "safeName": "NAMED_METADATA" + }, + "pascalCase": { + "unsafeName": "NamedMetadata", + "safeName": "NamedMetadata" + } + }, + "fernFilepath": { + "allParts": [ + { "originalName": "union", "camelCase": { "unsafeName": "union", @@ -5003,12 +6917,91 @@ "safeName": "Union" } } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "properties": [ + { + "name": { + "wireValue": "name", + "name": { + "originalName": "name", + "camelCase": { + "unsafeName": "name", + "safeName": "name" + }, + "snakeCase": { + "unsafeName": "name", + "safeName": "name" + }, + "screamingSnakeCase": { + "unsafeName": "NAME", + "safeName": "NAME" + }, + "pascalCase": { + "unsafeName": "Name", + "safeName": "Name" + } + } }, "typeReference": { - "type": "optional", + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "value", + "name": { + "originalName": "value", + "camelCase": { + "unsafeName": "value", + "safeName": "value" + }, + "snakeCase": { + "unsafeName": "value", + "safeName": "value" + }, + "screamingSnakeCase": { + "unsafeName": "VALUE", + "safeName": "VALUE" + }, + "pascalCase": { + "unsafeName": "Value", + "safeName": "Value" + } + } + }, + "typeReference": { + "type": "map", + "key": { + "type": "primitive", + "value": "STRING" + }, "value": { - "type": "named", - "value": "type_union:MetadataUnion" + "type": "unknown" } }, "propertyAccess": null, @@ -5018,26 +7011,106 @@ "extends": null, "additionalProperties": false }, - "type_union:TypeWithOptionalUnion": { - "type": "object", + "type_union:OptionalMetadata": { + "type": "alias", + "declaration": { + "name": { + "originalName": "OptionalMetadata", + "camelCase": { + "unsafeName": "optionalMetadata", + "safeName": "optionalMetadata" + }, + "snakeCase": { + "unsafeName": "optional_metadata", + "safeName": "optional_metadata" + }, + "screamingSnakeCase": { + "unsafeName": "OPTIONAL_METADATA", + "safeName": "OPTIONAL_METADATA" + }, + "pascalCase": { + "unsafeName": "OptionalMetadata", + "safeName": "OptionalMetadata" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "typeReference": { + "type": "optional", + "value": { + "type": "map", + "key": { + "type": "primitive", + "value": "STRING" + }, + "value": { + "type": "unknown" + } + } + } + }, + "type_union:Metadata": { + "type": "alias", "declaration": { "name": { - "originalName": "TypeWithOptionalUnion", + "originalName": "Metadata", "camelCase": { - "unsafeName": "typeWithOptionalUnion", - "safeName": "typeWithOptionalUnion" + "unsafeName": "metadata", + "safeName": "metadata" }, "snakeCase": { - "unsafeName": "type_with_optional_union", - "safeName": "type_with_optional_union" + "unsafeName": "metadata", + "safeName": "metadata" }, "screamingSnakeCase": { - "unsafeName": "TYPE_WITH_OPTIONAL_UNION", - "safeName": "TYPE_WITH_OPTIONAL_UNION" + "unsafeName": "METADATA", + "safeName": "METADATA" }, "pascalCase": { - "unsafeName": "TypeWithOptionalUnion", - "safeName": "TypeWithOptionalUnion" + "unsafeName": "Metadata", + "safeName": "Metadata" } }, "fernFilepath": { @@ -5084,64 +7157,38 @@ } } }, - "properties": [ - { - "name": { - "wireValue": "myUnion", - "name": { - "originalName": "myUnion", - "camelCase": { - "unsafeName": "myUnion", - "safeName": "myUnion" - }, - "snakeCase": { - "unsafeName": "my_union", - "safeName": "my_union" - }, - "screamingSnakeCase": { - "unsafeName": "MY_UNION", - "safeName": "MY_UNION" - }, - "pascalCase": { - "unsafeName": "MyUnion", - "safeName": "MyUnion" - } - } - }, - "typeReference": { - "type": "optional", - "value": { - "type": "named", - "value": "type_union:MyUnion" - } - }, - "propertyAccess": null, - "variable": null + "typeReference": { + "type": "map", + "key": { + "type": "named", + "value": "type_union:Key" + }, + "value": { + "type": "primitive", + "value": "STRING" } - ], - "extends": null, - "additionalProperties": false + } }, - "type_union:MyUnion": { + "type_union:Key": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "MyUnion", + "originalName": "Key", "camelCase": { - "unsafeName": "myUnion", - "safeName": "myUnion" + "unsafeName": "key", + "safeName": "key" }, "snakeCase": { - "unsafeName": "my_union", - "safeName": "my_union" + "unsafeName": "key", + "safeName": "key" }, "screamingSnakeCase": { - "unsafeName": "MY_UNION", - "safeName": "MY_UNION" + "unsafeName": "KEY", + "safeName": "KEY" }, "pascalCase": { - "unsafeName": "MyUnion", - "safeName": "MyUnion" + "unsafeName": "Key", + "safeName": "Key" } }, "fernFilepath": { @@ -5190,66 +7237,38 @@ }, "types": [ { - "type": "primitive", - "value": "STRING" - }, - { - "type": "list", - "value": { - "type": "primitive", - "value": "STRING" - } - }, - { - "type": "primitive", - "value": "INTEGER" - }, - { - "type": "list", - "value": { - "type": "primitive", - "value": "INTEGER" - } - }, - { - "type": "list", - "value": { - "type": "list", - "value": { - "type": "primitive", - "value": "INTEGER" - } - } + "type": "named", + "value": "type_union:KeyType" }, { - "type": "set", + "type": "literal", "value": { - "type": "primitive", - "value": "STRING" + "type": "string", + "value": "default" } } ] }, - "type_union:NestedUnionL2": { - "type": "undiscriminatedUnion", + "type_union:KeyType": { + "type": "enum", "declaration": { "name": { - "originalName": "NestedUnionL2", + "originalName": "KeyType", "camelCase": { - "unsafeName": "nestedUnionL2", - "safeName": "nestedUnionL2" + "unsafeName": "keyType", + "safeName": "keyType" }, "snakeCase": { - "unsafeName": "nested_union_l2", - "safeName": "nested_union_l2" + "unsafeName": "key_type", + "safeName": "key_type" }, "screamingSnakeCase": { - "unsafeName": "NESTED_UNION_L2", - "safeName": "NESTED_UNION_L2" + "unsafeName": "KEY_TYPE", + "safeName": "KEY_TYPE" }, "pascalCase": { - "unsafeName": "NestedUnionL2", - "safeName": "NestedUnionL2" + "unsafeName": "KeyType", + "safeName": "KeyType" } }, "fernFilepath": { @@ -5296,47 +7315,73 @@ } } }, - "types": [ - { - "type": "primitive", - "value": "BOOLEAN" - }, + "values": [ { - "type": "set", - "value": { - "type": "primitive", - "value": "STRING" + "wireValue": "name", + "name": { + "originalName": "name", + "camelCase": { + "unsafeName": "name", + "safeName": "name" + }, + "snakeCase": { + "unsafeName": "name", + "safeName": "name" + }, + "screamingSnakeCase": { + "unsafeName": "NAME", + "safeName": "NAME" + }, + "pascalCase": { + "unsafeName": "Name", + "safeName": "Name" + } } }, { - "type": "list", - "value": { - "type": "primitive", - "value": "STRING" + "wireValue": "value", + "name": { + "originalName": "value", + "camelCase": { + "unsafeName": "value", + "safeName": "value" + }, + "snakeCase": { + "unsafeName": "value", + "safeName": "value" + }, + "screamingSnakeCase": { + "unsafeName": "VALUE", + "safeName": "VALUE" + }, + "pascalCase": { + "unsafeName": "Value", + "safeName": "Value" + } } } ] }, - "type_union:NestedUnionL1": { + "type_union:UnionWithBaseProperties": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "NestedUnionL1", + "originalName": "UnionWithBaseProperties", "camelCase": { - "unsafeName": "nestedUnionL1", - "safeName": "nestedUnionL1" + "unsafeName": "unionWithBaseProperties", + "safeName": "unionWithBaseProperties" }, "snakeCase": { - "unsafeName": "nested_union_l1", - "safeName": "nested_union_l1" + "unsafeName": "union_with_base_properties", + "safeName": "union_with_base_properties" }, "screamingSnakeCase": { - "unsafeName": "NESTED_UNION_L1", - "safeName": "NESTED_UNION_L1" + "unsafeName": "UNION_WITH_BASE_PROPERTIES", + "safeName": "UNION_WITH_BASE_PROPERTIES" }, "pascalCase": { - "unsafeName": "NestedUnionL1", - "safeName": "NestedUnionL1" + "unsafeName": "UnionWithBaseProperties", + "safeName": "UnionWithBaseProperties" } }, "fernFilepath": { @@ -5385,49 +7430,35 @@ }, "types": [ { - "type": "primitive", - "value": "INTEGER" - }, - { - "type": "set", - "value": { - "type": "primitive", - "value": "STRING" - } - }, - { - "type": "list", - "value": { - "type": "primitive", - "value": "STRING" - } + "type": "named", + "value": "type_union:NamedMetadata" }, { "type": "named", - "value": "type_union:NestedUnionL2" + "value": "type_union:OptionalMetadata" } ] }, - "type_union:NestedUnionRoot": { + "type_union:UnionWithIdenticalStrings": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "NestedUnionRoot", + "originalName": "UnionWithIdenticalStrings", "camelCase": { - "unsafeName": "nestedUnionRoot", - "safeName": "nestedUnionRoot" + "unsafeName": "unionWithIdenticalStrings", + "safeName": "unionWithIdenticalStrings" }, "snakeCase": { - "unsafeName": "nested_union_root", - "safeName": "nested_union_root" + "unsafeName": "union_with_identical_strings", + "safeName": "union_with_identical_strings" }, "screamingSnakeCase": { - "unsafeName": "NESTED_UNION_ROOT", - "safeName": "NESTED_UNION_ROOT" + "unsafeName": "UNION_WITH_IDENTICAL_STRINGS", + "safeName": "UNION_WITH_IDENTICAL_STRINGS" }, "pascalCase": { - "unsafeName": "NestedUnionRoot", - "safeName": "NestedUnionRoot" + "unsafeName": "UnionWithIdenticalStrings", + "safeName": "UnionWithIdenticalStrings" } }, "fernFilepath": { @@ -5478,40 +7509,29 @@ { "type": "primitive", "value": "STRING" - }, - { - "type": "list", - "value": { - "type": "primitive", - "value": "STRING" - } - }, - { - "type": "named", - "value": "type_union:NestedUnionL1" } ] }, - "type_union:UnionWithDuplicateTypes": { + "type_union:UnionWithIdenticalPrimitives": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "UnionWithDuplicateTypes", + "originalName": "UnionWithIdenticalPrimitives", "camelCase": { - "unsafeName": "unionWithDuplicateTypes", - "safeName": "unionWithDuplicateTypes" + "unsafeName": "unionWithIdenticalPrimitives", + "safeName": "unionWithIdenticalPrimitives" }, "snakeCase": { - "unsafeName": "union_with_duplicate_types", - "safeName": "union_with_duplicate_types" + "unsafeName": "union_with_identical_primitives", + "safeName": "union_with_identical_primitives" }, "screamingSnakeCase": { - "unsafeName": "UNION_WITH_DUPLICATE_TYPES", - "safeName": "UNION_WITH_DUPLICATE_TYPES" + "unsafeName": "UNION_WITH_IDENTICAL_PRIMITIVES", + "safeName": "UNION_WITH_IDENTICAL_PRIMITIVES" }, "pascalCase": { - "unsafeName": "UnionWithDuplicateTypes", - "safeName": "UnionWithDuplicateTypes" + "unsafeName": "UnionWithIdenticalPrimitives", + "safeName": "UnionWithIdenticalPrimitives" } }, "fernFilepath": { @@ -5561,48 +7581,38 @@ "types": [ { "type": "primitive", - "value": "STRING" - }, - { - "type": "list", - "value": { - "type": "primitive", - "value": "STRING" - } + "value": "INTEGER" }, { "type": "primitive", - "value": "INTEGER" + "value": "DOUBLE" }, { - "type": "set", - "value": { - "type": "primitive", - "value": "STRING" - } + "type": "primitive", + "value": "STRING" } ] }, - "type_union:MetadataUnion": { + "type_union:PaymentMethodUnion": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "MetadataUnion", + "originalName": "PaymentMethodUnion", "camelCase": { - "unsafeName": "metadataUnion", - "safeName": "metadataUnion" + "unsafeName": "paymentMethodUnion", + "safeName": "paymentMethodUnion" }, "snakeCase": { - "unsafeName": "metadata_union", - "safeName": "metadata_union" + "unsafeName": "payment_method_union", + "safeName": "payment_method_union" }, "screamingSnakeCase": { - "unsafeName": "METADATA_UNION", - "safeName": "METADATA_UNION" + "unsafeName": "PAYMENT_METHOD_UNION", + "safeName": "PAYMENT_METHOD_UNION" }, "pascalCase": { - "unsafeName": "MetadataUnion", - "safeName": "MetadataUnion" + "unsafeName": "PaymentMethodUnion", + "safeName": "PaymentMethodUnion" } }, "fernFilepath": { @@ -5652,34 +7662,34 @@ "types": [ { "type": "named", - "value": "type_union:OptionalMetadata" + "value": "type_union:TokenizeCard" }, { "type": "named", - "value": "type_union:NamedMetadata" + "value": "type_union:ConvertToken" } ] }, - "type_union:NamedMetadata": { + "type_union:TokenizeCard": { "type": "object", "declaration": { "name": { - "originalName": "NamedMetadata", + "originalName": "TokenizeCard", "camelCase": { - "unsafeName": "namedMetadata", - "safeName": "namedMetadata" + "unsafeName": "tokenizeCard", + "safeName": "tokenizeCard" }, "snakeCase": { - "unsafeName": "named_metadata", - "safeName": "named_metadata" + "unsafeName": "tokenize_card", + "safeName": "tokenize_card" }, "screamingSnakeCase": { - "unsafeName": "NAMED_METADATA", - "safeName": "NAMED_METADATA" + "unsafeName": "TOKENIZE_CARD", + "safeName": "TOKENIZE_CARD" }, "pascalCase": { - "unsafeName": "NamedMetadata", - "safeName": "NamedMetadata" + "unsafeName": "TokenizeCard", + "safeName": "TokenizeCard" } }, "fernFilepath": { @@ -5729,24 +7739,24 @@ "properties": [ { "name": { - "wireValue": "name", + "wireValue": "method", "name": { - "originalName": "name", + "originalName": "method", "camelCase": { - "unsafeName": "name", - "safeName": "name" + "unsafeName": "method", + "safeName": "method" }, "snakeCase": { - "unsafeName": "name", - "safeName": "name" + "unsafeName": "method", + "safeName": "method" }, "screamingSnakeCase": { - "unsafeName": "NAME", - "safeName": "NAME" + "unsafeName": "METHOD", + "safeName": "METHOD" }, "pascalCase": { - "unsafeName": "Name", - "safeName": "Name" + "unsafeName": "Method", + "safeName": "Method" } } }, @@ -5759,36 +7769,30 @@ }, { "name": { - "wireValue": "value", + "wireValue": "cardNumber", "name": { - "originalName": "value", + "originalName": "cardNumber", "camelCase": { - "unsafeName": "value", - "safeName": "value" + "unsafeName": "cardNumber", + "safeName": "cardNumber" }, "snakeCase": { - "unsafeName": "value", - "safeName": "value" + "unsafeName": "card_number", + "safeName": "card_number" }, "screamingSnakeCase": { - "unsafeName": "VALUE", - "safeName": "VALUE" + "unsafeName": "CARD_NUMBER", + "safeName": "CARD_NUMBER" }, "pascalCase": { - "unsafeName": "Value", - "safeName": "Value" + "unsafeName": "CardNumber", + "safeName": "CardNumber" } } }, "typeReference": { - "type": "map", - "key": { - "type": "primitive", - "value": "STRING" - }, - "value": { - "type": "unknown" - } + "type": "primitive", + "value": "STRING" }, "propertyAccess": null, "variable": null @@ -5797,26 +7801,26 @@ "extends": null, "additionalProperties": false }, - "type_union:OptionalMetadata": { - "type": "alias", + "type_union:ConvertToken": { + "type": "object", "declaration": { "name": { - "originalName": "OptionalMetadata", + "originalName": "ConvertToken", "camelCase": { - "unsafeName": "optionalMetadata", - "safeName": "optionalMetadata" + "unsafeName": "convertToken", + "safeName": "convertToken" }, "snakeCase": { - "unsafeName": "optional_metadata", - "safeName": "optional_metadata" + "unsafeName": "convert_token", + "safeName": "convert_token" }, "screamingSnakeCase": { - "unsafeName": "OPTIONAL_METADATA", - "safeName": "OPTIONAL_METADATA" + "unsafeName": "CONVERT_TOKEN", + "safeName": "CONVERT_TOKEN" }, "pascalCase": { - "unsafeName": "OptionalMetadata", - "safeName": "OptionalMetadata" + "unsafeName": "ConvertToken", + "safeName": "ConvertToken" } }, "fernFilepath": { @@ -5863,40 +7867,91 @@ } } }, - "typeReference": { - "type": "optional", - "value": { - "type": "map", - "key": { + "properties": [ + { + "name": { + "wireValue": "method", + "name": { + "originalName": "method", + "camelCase": { + "unsafeName": "method", + "safeName": "method" + }, + "snakeCase": { + "unsafeName": "method", + "safeName": "method" + }, + "screamingSnakeCase": { + "unsafeName": "METHOD", + "safeName": "METHOD" + }, + "pascalCase": { + "unsafeName": "Method", + "safeName": "Method" + } + } + }, + "typeReference": { "type": "primitive", "value": "STRING" }, - "value": { - "type": "unknown" - } + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "tokenId", + "name": { + "originalName": "tokenId", + "camelCase": { + "unsafeName": "tokenID", + "safeName": "tokenID" + }, + "snakeCase": { + "unsafeName": "token_id", + "safeName": "token_id" + }, + "screamingSnakeCase": { + "unsafeName": "TOKEN_ID", + "safeName": "TOKEN_ID" + }, + "pascalCase": { + "unsafeName": "TokenID", + "safeName": "TokenID" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null } - } + ], + "extends": null, + "additionalProperties": false }, - "type_union:Metadata": { - "type": "alias", + "type_union:UnionWithReservedNames": { + "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "Metadata", + "originalName": "UnionWithReservedNames", "camelCase": { - "unsafeName": "metadata", - "safeName": "metadata" + "unsafeName": "unionWithReservedNames", + "safeName": "unionWithReservedNames" }, "snakeCase": { - "unsafeName": "metadata", - "safeName": "metadata" + "unsafeName": "union_with_reserved_names", + "safeName": "union_with_reserved_names" }, "screamingSnakeCase": { - "unsafeName": "METADATA", - "safeName": "METADATA" + "unsafeName": "UNION_WITH_RESERVED_NAMES", + "safeName": "UNION_WITH_RESERVED_NAMES" }, "pascalCase": { - "unsafeName": "Metadata", - "safeName": "Metadata" + "unsafeName": "UnionWithReservedNames", + "safeName": "UnionWithReservedNames" } }, "fernFilepath": { @@ -5943,38 +7998,47 @@ } } }, - "typeReference": { - "type": "map", - "key": { - "type": "named", - "value": "type_union:Key" + "types": [ + { + "type": "literal", + "value": { + "type": "string", + "value": "type" + } }, - "value": { + { + "type": "literal", + "value": { + "type": "string", + "value": "value" + } + }, + { "type": "primitive", "value": "STRING" } - } + ] }, - "type_union:Key": { - "type": "undiscriminatedUnion", + "type_union:UserId": { + "type": "alias", "declaration": { "name": { - "originalName": "Key", + "originalName": "UserId", "camelCase": { - "unsafeName": "key", - "safeName": "key" + "unsafeName": "userID", + "safeName": "userID" }, "snakeCase": { - "unsafeName": "key", - "safeName": "key" + "unsafeName": "user_id", + "safeName": "user_id" }, "screamingSnakeCase": { - "unsafeName": "KEY", - "safeName": "KEY" + "unsafeName": "USER_ID", + "safeName": "USER_ID" }, "pascalCase": { - "unsafeName": "Key", - "safeName": "Key" + "unsafeName": "UserID", + "safeName": "UserID" } }, "fernFilepath": { @@ -6021,40 +8085,31 @@ } } }, - "types": [ - { - "type": "named", - "value": "type_union:KeyType" - }, - { - "type": "literal", - "value": { - "type": "string", - "value": "default" - } - } - ] + "typeReference": { + "type": "primitive", + "value": "STRING" + } }, - "type_union:KeyType": { - "type": "enum", + "type_union:Name": { + "type": "alias", "declaration": { "name": { - "originalName": "KeyType", + "originalName": "Name", "camelCase": { - "unsafeName": "keyType", - "safeName": "keyType" + "unsafeName": "name", + "safeName": "name" }, "snakeCase": { - "unsafeName": "key_type", - "safeName": "key_type" + "unsafeName": "name", + "safeName": "name" }, "screamingSnakeCase": { - "unsafeName": "KEY_TYPE", - "safeName": "KEY_TYPE" + "unsafeName": "NAME", + "safeName": "NAME" }, "pascalCase": { - "unsafeName": "KeyType", - "safeName": "KeyType" + "unsafeName": "Name", + "safeName": "Name" } }, "fernFilepath": { @@ -6101,73 +8156,31 @@ } } }, - "values": [ - { - "wireValue": "name", - "name": { - "originalName": "name", - "camelCase": { - "unsafeName": "name", - "safeName": "name" - }, - "snakeCase": { - "unsafeName": "name", - "safeName": "name" - }, - "screamingSnakeCase": { - "unsafeName": "NAME", - "safeName": "NAME" - }, - "pascalCase": { - "unsafeName": "Name", - "safeName": "Name" - } - } - }, - { - "wireValue": "value", - "name": { - "originalName": "value", - "camelCase": { - "unsafeName": "value", - "safeName": "value" - }, - "snakeCase": { - "unsafeName": "value", - "safeName": "value" - }, - "screamingSnakeCase": { - "unsafeName": "VALUE", - "safeName": "VALUE" - }, - "pascalCase": { - "unsafeName": "Value", - "safeName": "Value" - } - } - } - ] + "typeReference": { + "type": "primitive", + "value": "STRING" + } }, - "type_union:UnionWithBaseProperties": { + "type_union:UnionWithTypeAliases": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "UnionWithBaseProperties", + "originalName": "UnionWithTypeAliases", "camelCase": { - "unsafeName": "unionWithBaseProperties", - "safeName": "unionWithBaseProperties" + "unsafeName": "unionWithTypeAliases", + "safeName": "unionWithTypeAliases" }, "snakeCase": { - "unsafeName": "union_with_base_properties", - "safeName": "union_with_base_properties" + "unsafeName": "union_with_type_aliases", + "safeName": "union_with_type_aliases" }, "screamingSnakeCase": { - "unsafeName": "UNION_WITH_BASE_PROPERTIES", - "safeName": "UNION_WITH_BASE_PROPERTIES" + "unsafeName": "UNION_WITH_TYPE_ALIASES", + "safeName": "UNION_WITH_TYPE_ALIASES" }, "pascalCase": { - "unsafeName": "UnionWithBaseProperties", - "safeName": "UnionWithBaseProperties" + "unsafeName": "UnionWithTypeAliases", + "safeName": "UnionWithTypeAliases" } }, "fernFilepath": { @@ -6215,36 +8228,40 @@ } }, "types": [ + { + "type": "primitive", + "value": "STRING" + }, { "type": "named", - "value": "type_union:NamedMetadata" + "value": "type_union:UserId" }, { "type": "named", - "value": "type_union:OptionalMetadata" + "value": "type_union:Name" } ] }, - "type_union:UnionWithIdenticalStrings": { - "type": "undiscriminatedUnion", + "type_union:LeafTypeA": { + "type": "object", "declaration": { "name": { - "originalName": "UnionWithIdenticalStrings", + "originalName": "LeafTypeA", "camelCase": { - "unsafeName": "unionWithIdenticalStrings", - "safeName": "unionWithIdenticalStrings" + "unsafeName": "leafTypeA", + "safeName": "leafTypeA" }, "snakeCase": { - "unsafeName": "union_with_identical_strings", - "safeName": "union_with_identical_strings" + "unsafeName": "leaf_type_a", + "safeName": "leaf_type_a" }, "screamingSnakeCase": { - "unsafeName": "UNION_WITH_IDENTICAL_STRINGS", - "safeName": "UNION_WITH_IDENTICAL_STRINGS" + "unsafeName": "LEAF_TYPE_A", + "safeName": "LEAF_TYPE_A" }, "pascalCase": { - "unsafeName": "UnionWithIdenticalStrings", - "safeName": "UnionWithIdenticalStrings" + "unsafeName": "LeafTypeA", + "safeName": "LeafTypeA" } }, "fernFilepath": { @@ -6291,33 +8308,91 @@ } } }, - "types": [ + "properties": [ { - "type": "primitive", - "value": "STRING" + "name": { + "wireValue": "alpha", + "name": { + "originalName": "alpha", + "camelCase": { + "unsafeName": "alpha", + "safeName": "alpha" + }, + "snakeCase": { + "unsafeName": "alpha", + "safeName": "alpha" + }, + "screamingSnakeCase": { + "unsafeName": "ALPHA", + "safeName": "ALPHA" + }, + "pascalCase": { + "unsafeName": "Alpha", + "safeName": "Alpha" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "beta", + "name": { + "originalName": "beta", + "camelCase": { + "unsafeName": "beta", + "safeName": "beta" + }, + "snakeCase": { + "unsafeName": "beta", + "safeName": "beta" + }, + "screamingSnakeCase": { + "unsafeName": "BETA", + "safeName": "BETA" + }, + "pascalCase": { + "unsafeName": "Beta", + "safeName": "Beta" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "INTEGER" + }, + "propertyAccess": null, + "variable": null } - ] + ], + "extends": null, + "additionalProperties": false }, - "type_union:UnionWithIdenticalPrimitives": { - "type": "undiscriminatedUnion", + "type_union:LeafTypeB": { + "type": "object", "declaration": { "name": { - "originalName": "UnionWithIdenticalPrimitives", + "originalName": "LeafTypeB", "camelCase": { - "unsafeName": "unionWithIdenticalPrimitives", - "safeName": "unionWithIdenticalPrimitives" + "unsafeName": "leafTypeB", + "safeName": "leafTypeB" }, "snakeCase": { - "unsafeName": "union_with_identical_primitives", - "safeName": "union_with_identical_primitives" + "unsafeName": "leaf_type_b", + "safeName": "leaf_type_b" }, "screamingSnakeCase": { - "unsafeName": "UNION_WITH_IDENTICAL_PRIMITIVES", - "safeName": "UNION_WITH_IDENTICAL_PRIMITIVES" + "unsafeName": "LEAF_TYPE_B", + "safeName": "LEAF_TYPE_B" }, "pascalCase": { - "unsafeName": "UnionWithIdenticalPrimitives", - "safeName": "UnionWithIdenticalPrimitives" + "unsafeName": "LeafTypeB", + "safeName": "LeafTypeB" } }, "fernFilepath": { @@ -6364,41 +8439,61 @@ } } }, - "types": [ - { - "type": "primitive", - "value": "INTEGER" - }, - { - "type": "primitive", - "value": "DOUBLE" - }, + "properties": [ { - "type": "primitive", - "value": "STRING" + "name": { + "wireValue": "gamma", + "name": { + "originalName": "gamma", + "camelCase": { + "unsafeName": "gamma", + "safeName": "gamma" + }, + "snakeCase": { + "unsafeName": "gamma", + "safeName": "gamma" + }, + "screamingSnakeCase": { + "unsafeName": "GAMMA", + "safeName": "GAMMA" + }, + "pascalCase": { + "unsafeName": "Gamma", + "safeName": "Gamma" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null } - ] + ], + "extends": null, + "additionalProperties": false }, - "type_union:PaymentMethodUnion": { + "type_union:NestedObjectUnion": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "PaymentMethodUnion", + "originalName": "NestedObjectUnion", "camelCase": { - "unsafeName": "paymentMethodUnion", - "safeName": "paymentMethodUnion" + "unsafeName": "nestedObjectUnion", + "safeName": "nestedObjectUnion" }, "snakeCase": { - "unsafeName": "payment_method_union", - "safeName": "payment_method_union" + "unsafeName": "nested_object_union", + "safeName": "nested_object_union" }, "screamingSnakeCase": { - "unsafeName": "PAYMENT_METHOD_UNION", - "safeName": "PAYMENT_METHOD_UNION" + "unsafeName": "NESTED_OBJECT_UNION", + "safeName": "NESTED_OBJECT_UNION" }, "pascalCase": { - "unsafeName": "PaymentMethodUnion", - "safeName": "PaymentMethodUnion" + "unsafeName": "NestedObjectUnion", + "safeName": "NestedObjectUnion" } }, "fernFilepath": { @@ -6448,34 +8543,34 @@ "types": [ { "type": "named", - "value": "type_union:TokenizeCard" + "value": "type_union:LeafTypeA" }, { "type": "named", - "value": "type_union:ConvertToken" + "value": "type_union:LeafTypeB" } ] }, - "type_union:TokenizeCard": { + "type_union:WrapperObject": { "type": "object", "declaration": { "name": { - "originalName": "TokenizeCard", + "originalName": "WrapperObject", "camelCase": { - "unsafeName": "tokenizeCard", - "safeName": "tokenizeCard" + "unsafeName": "wrapperObject", + "safeName": "wrapperObject" }, "snakeCase": { - "unsafeName": "tokenize_card", - "safeName": "tokenize_card" + "unsafeName": "wrapper_object", + "safeName": "wrapper_object" }, "screamingSnakeCase": { - "unsafeName": "TOKENIZE_CARD", - "safeName": "TOKENIZE_CARD" + "unsafeName": "WRAPPER_OBJECT", + "safeName": "WRAPPER_OBJECT" }, "pascalCase": { - "unsafeName": "TokenizeCard", - "safeName": "TokenizeCard" + "unsafeName": "WrapperObject", + "safeName": "WrapperObject" } }, "fernFilepath": { @@ -6525,54 +8620,54 @@ "properties": [ { "name": { - "wireValue": "method", + "wireValue": "inner", "name": { - "originalName": "method", + "originalName": "inner", "camelCase": { - "unsafeName": "method", - "safeName": "method" + "unsafeName": "inner", + "safeName": "inner" }, "snakeCase": { - "unsafeName": "method", - "safeName": "method" + "unsafeName": "inner", + "safeName": "inner" }, "screamingSnakeCase": { - "unsafeName": "METHOD", - "safeName": "METHOD" + "unsafeName": "INNER", + "safeName": "INNER" }, "pascalCase": { - "unsafeName": "Method", - "safeName": "Method" + "unsafeName": "Inner", + "safeName": "Inner" } } }, "typeReference": { - "type": "primitive", - "value": "STRING" + "type": "named", + "value": "type_union:NestedObjectUnion" }, "propertyAccess": null, "variable": null }, { "name": { - "wireValue": "cardNumber", + "wireValue": "label", "name": { - "originalName": "cardNumber", + "originalName": "label", "camelCase": { - "unsafeName": "cardNumber", - "safeName": "cardNumber" + "unsafeName": "label", + "safeName": "label" }, "snakeCase": { - "unsafeName": "card_number", - "safeName": "card_number" + "unsafeName": "label", + "safeName": "label" }, "screamingSnakeCase": { - "unsafeName": "CARD_NUMBER", - "safeName": "CARD_NUMBER" + "unsafeName": "LABEL", + "safeName": "LABEL" }, "pascalCase": { - "unsafeName": "CardNumber", - "safeName": "CardNumber" + "unsafeName": "Label", + "safeName": "Label" } } }, @@ -6587,26 +8682,26 @@ "extends": null, "additionalProperties": false }, - "type_union:ConvertToken": { - "type": "object", + "type_union:OuterNestedUnion": { + "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "ConvertToken", + "originalName": "OuterNestedUnion", "camelCase": { - "unsafeName": "convertToken", - "safeName": "convertToken" + "unsafeName": "outerNestedUnion", + "safeName": "outerNestedUnion" }, "snakeCase": { - "unsafeName": "convert_token", - "safeName": "convert_token" + "unsafeName": "outer_nested_union", + "safeName": "outer_nested_union" }, "screamingSnakeCase": { - "unsafeName": "CONVERT_TOKEN", - "safeName": "CONVERT_TOKEN" + "unsafeName": "OUTER_NESTED_UNION", + "safeName": "OUTER_NESTED_UNION" }, "pascalCase": { - "unsafeName": "ConvertToken", - "safeName": "ConvertToken" + "unsafeName": "OuterNestedUnion", + "safeName": "OuterNestedUnion" } }, "fernFilepath": { @@ -6653,91 +8748,179 @@ } } }, - "properties": [ + "types": [ { - "name": { - "wireValue": "method", - "name": { - "originalName": "method", + "type": "primitive", + "value": "STRING" + }, + { + "type": "named", + "value": "type_union:WrapperObject" + } + ] + }, + "type_union:AliasedLeafA": { + "type": "alias", + "declaration": { + "name": { + "originalName": "AliasedLeafA", + "camelCase": { + "unsafeName": "aliasedLeafA", + "safeName": "aliasedLeafA" + }, + "snakeCase": { + "unsafeName": "aliased_leaf_a", + "safeName": "aliased_leaf_a" + }, + "screamingSnakeCase": { + "unsafeName": "ALIASED_LEAF_A", + "safeName": "ALIASED_LEAF_A" + }, + "pascalCase": { + "unsafeName": "AliasedLeafA", + "safeName": "AliasedLeafA" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", "camelCase": { - "unsafeName": "method", - "safeName": "method" + "unsafeName": "union", + "safeName": "union" }, "snakeCase": { - "unsafeName": "method", - "safeName": "method" + "unsafeName": "union", + "safeName": "union" }, "screamingSnakeCase": { - "unsafeName": "METHOD", - "safeName": "METHOD" + "unsafeName": "UNION", + "safeName": "UNION" }, "pascalCase": { - "unsafeName": "Method", - "safeName": "Method" + "unsafeName": "Union", + "safeName": "Union" } } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "typeReference": { + "type": "named", + "value": "type_union:LeafObjectA" + } + }, + "type_union:AliasedLeafB": { + "type": "alias", + "declaration": { + "name": { + "originalName": "AliasedLeafB", + "camelCase": { + "unsafeName": "aliasedLeafB", + "safeName": "aliasedLeafB" }, - "typeReference": { - "type": "primitive", - "value": "STRING" + "snakeCase": { + "unsafeName": "aliased_leaf_b", + "safeName": "aliased_leaf_b" }, - "propertyAccess": null, - "variable": null + "screamingSnakeCase": { + "unsafeName": "ALIASED_LEAF_B", + "safeName": "ALIASED_LEAF_B" + }, + "pascalCase": { + "unsafeName": "AliasedLeafB", + "safeName": "AliasedLeafB" + } }, - { - "name": { - "wireValue": "tokenId", - "name": { - "originalName": "tokenId", + "fernFilepath": { + "allParts": [ + { + "originalName": "union", "camelCase": { - "unsafeName": "tokenID", - "safeName": "tokenID" + "unsafeName": "union", + "safeName": "union" }, "snakeCase": { - "unsafeName": "token_id", - "safeName": "token_id" + "unsafeName": "union", + "safeName": "union" }, "screamingSnakeCase": { - "unsafeName": "TOKEN_ID", - "safeName": "TOKEN_ID" + "unsafeName": "UNION", + "safeName": "UNION" }, "pascalCase": { - "unsafeName": "TokenID", - "safeName": "TokenID" + "unsafeName": "Union", + "safeName": "Union" } } - }, - "typeReference": { - "type": "primitive", - "value": "STRING" - }, - "propertyAccess": null, - "variable": null + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } } - ], - "extends": null, - "additionalProperties": false + }, + "typeReference": { + "type": "named", + "value": "type_union:AliasToLeafB" + } }, - "type_union:UnionWithReservedNames": { - "type": "undiscriminatedUnion", + "type_union:AliasToLeafB": { + "type": "alias", "declaration": { "name": { - "originalName": "UnionWithReservedNames", + "originalName": "AliasToLeafB", "camelCase": { - "unsafeName": "unionWithReservedNames", - "safeName": "unionWithReservedNames" + "unsafeName": "aliasToLeafB", + "safeName": "aliasToLeafB" }, "snakeCase": { - "unsafeName": "union_with_reserved_names", - "safeName": "union_with_reserved_names" + "unsafeName": "alias_to_leaf_b", + "safeName": "alias_to_leaf_b" }, "screamingSnakeCase": { - "unsafeName": "UNION_WITH_RESERVED_NAMES", - "safeName": "UNION_WITH_RESERVED_NAMES" + "unsafeName": "ALIAS_TO_LEAF_B", + "safeName": "ALIAS_TO_LEAF_B" }, "pascalCase": { - "unsafeName": "UnionWithReservedNames", - "safeName": "UnionWithReservedNames" + "unsafeName": "AliasToLeafB", + "safeName": "AliasToLeafB" } }, "fernFilepath": { @@ -6784,47 +8967,31 @@ } } }, - "types": [ - { - "type": "literal", - "value": { - "type": "string", - "value": "type" - } - }, - { - "type": "literal", - "value": { - "type": "string", - "value": "value" - } - }, - { - "type": "primitive", - "value": "STRING" - } - ] + "typeReference": { + "type": "named", + "value": "type_union:LeafObjectB" + } }, - "type_union:UserId": { - "type": "alias", + "type_union:LeafObjectA": { + "type": "object", "declaration": { "name": { - "originalName": "UserId", + "originalName": "LeafObjectA", "camelCase": { - "unsafeName": "userID", - "safeName": "userID" + "unsafeName": "leafObjectA", + "safeName": "leafObjectA" }, "snakeCase": { - "unsafeName": "user_id", - "safeName": "user_id" + "unsafeName": "leaf_object_a", + "safeName": "leaf_object_a" }, "screamingSnakeCase": { - "unsafeName": "USER_ID", - "safeName": "USER_ID" + "unsafeName": "LEAF_OBJECT_A", + "safeName": "LEAF_OBJECT_A" }, "pascalCase": { - "unsafeName": "UserID", - "safeName": "UserID" + "unsafeName": "LeafObjectA", + "safeName": "LeafObjectA" } }, "fernFilepath": { @@ -6871,31 +9038,91 @@ } } }, - "typeReference": { - "type": "primitive", - "value": "STRING" - } + "properties": [ + { + "name": { + "wireValue": "onlyInA", + "name": { + "originalName": "onlyInA", + "camelCase": { + "unsafeName": "onlyInA", + "safeName": "onlyInA" + }, + "snakeCase": { + "unsafeName": "only_in_a", + "safeName": "only_in_a" + }, + "screamingSnakeCase": { + "unsafeName": "ONLY_IN_A", + "safeName": "ONLY_IN_A" + }, + "pascalCase": { + "unsafeName": "OnlyInA", + "safeName": "OnlyInA" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + }, + { + "name": { + "wireValue": "sharedNumber", + "name": { + "originalName": "sharedNumber", + "camelCase": { + "unsafeName": "sharedNumber", + "safeName": "sharedNumber" + }, + "snakeCase": { + "unsafeName": "shared_number", + "safeName": "shared_number" + }, + "screamingSnakeCase": { + "unsafeName": "SHARED_NUMBER", + "safeName": "SHARED_NUMBER" + }, + "pascalCase": { + "unsafeName": "SharedNumber", + "safeName": "SharedNumber" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "INTEGER" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false }, - "type_union:Name": { - "type": "alias", + "type_union:LeafObjectB": { + "type": "object", "declaration": { "name": { - "originalName": "Name", + "originalName": "LeafObjectB", "camelCase": { - "unsafeName": "name", - "safeName": "name" + "unsafeName": "leafObjectB", + "safeName": "leafObjectB" }, "snakeCase": { - "unsafeName": "name", - "safeName": "name" + "unsafeName": "leaf_object_b", + "safeName": "leaf_object_b" }, "screamingSnakeCase": { - "unsafeName": "NAME", - "safeName": "NAME" + "unsafeName": "LEAF_OBJECT_B", + "safeName": "LEAF_OBJECT_B" }, "pascalCase": { - "unsafeName": "Name", - "safeName": "Name" + "unsafeName": "LeafObjectB", + "safeName": "LeafObjectB" } }, "fernFilepath": { @@ -6942,31 +9169,61 @@ } } }, - "typeReference": { - "type": "primitive", - "value": "STRING" - } + "properties": [ + { + "name": { + "wireValue": "onlyInB", + "name": { + "originalName": "onlyInB", + "camelCase": { + "unsafeName": "onlyInB", + "safeName": "onlyInB" + }, + "snakeCase": { + "unsafeName": "only_in_b", + "safeName": "only_in_b" + }, + "screamingSnakeCase": { + "unsafeName": "ONLY_IN_B", + "safeName": "ONLY_IN_B" + }, + "pascalCase": { + "unsafeName": "OnlyInB", + "safeName": "OnlyInB" + } + } + }, + "typeReference": { + "type": "primitive", + "value": "STRING" + }, + "propertyAccess": null, + "variable": null + } + ], + "extends": null, + "additionalProperties": false }, - "type_union:UnionWithTypeAliases": { + "type_union:AliasedObjectUnion": { "type": "undiscriminatedUnion", "declaration": { "name": { - "originalName": "UnionWithTypeAliases", + "originalName": "AliasedObjectUnion", "camelCase": { - "unsafeName": "unionWithTypeAliases", - "safeName": "unionWithTypeAliases" + "unsafeName": "aliasedObjectUnion", + "safeName": "aliasedObjectUnion" }, "snakeCase": { - "unsafeName": "union_with_type_aliases", - "safeName": "union_with_type_aliases" + "unsafeName": "aliased_object_union", + "safeName": "aliased_object_union" }, "screamingSnakeCase": { - "unsafeName": "UNION_WITH_TYPE_ALIASES", - "safeName": "UNION_WITH_TYPE_ALIASES" + "unsafeName": "ALIASED_OBJECT_UNION", + "safeName": "ALIASED_OBJECT_UNION" }, "pascalCase": { - "unsafeName": "UnionWithTypeAliases", - "safeName": "UnionWithTypeAliases" + "unsafeName": "AliasedObjectUnion", + "safeName": "AliasedObjectUnion" } }, "fernFilepath": { @@ -7014,17 +9271,13 @@ } }, "types": [ - { - "type": "primitive", - "value": "STRING" - }, { "type": "named", - "value": "type_union:UserId" + "value": "type_union:AliasedLeafA" }, { "type": "named", - "value": "type_union:Name" + "value": "type_union:AliasedLeafB" } ] } @@ -7541,6 +9794,178 @@ }, "examples": null }, + "endpoint_union.nestedObjectUnions": { + "auth": null, + "declaration": { + "name": { + "originalName": "nestedObjectUnions", + "camelCase": { + "unsafeName": "nestedObjectUnions", + "safeName": "nestedObjectUnions" + }, + "snakeCase": { + "unsafeName": "nested_object_unions", + "safeName": "nested_object_unions" + }, + "screamingSnakeCase": { + "unsafeName": "NESTED_OBJECT_UNIONS", + "safeName": "NESTED_OBJECT_UNIONS" + }, + "pascalCase": { + "unsafeName": "NestedObjectUnions", + "safeName": "NestedObjectUnions" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "location": { + "method": "POST", + "path": "/nested-objects" + }, + "request": { + "type": "body", + "pathParameters": [], + "body": { + "type": "typeReference", + "value": { + "type": "named", + "value": "type_union:OuterNestedUnion" + } + } + }, + "response": { + "type": "json" + }, + "examples": null + }, + "endpoint_union.aliasedObjectUnion": { + "auth": null, + "declaration": { + "name": { + "originalName": "aliasedObjectUnion", + "camelCase": { + "unsafeName": "aliasedObjectUnion", + "safeName": "aliasedObjectUnion" + }, + "snakeCase": { + "unsafeName": "aliased_object_union", + "safeName": "aliased_object_union" + }, + "screamingSnakeCase": { + "unsafeName": "ALIASED_OBJECT_UNION", + "safeName": "ALIASED_OBJECT_UNION" + }, + "pascalCase": { + "unsafeName": "AliasedObjectUnion", + "safeName": "AliasedObjectUnion" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + ], + "packagePath": [], + "file": { + "originalName": "union", + "camelCase": { + "unsafeName": "union", + "safeName": "union" + }, + "snakeCase": { + "unsafeName": "union", + "safeName": "union" + }, + "screamingSnakeCase": { + "unsafeName": "UNION", + "safeName": "UNION" + }, + "pascalCase": { + "unsafeName": "Union", + "safeName": "Union" + } + } + } + }, + "location": { + "method": "POST", + "path": "/aliased-object" + }, + "request": { + "type": "body", + "pathParameters": [], + "body": { + "type": "typeReference", + "value": { + "type": "named", + "value": "type_union:AliasedObjectUnion" + } + } + }, + "response": { + "type": "json" + }, + "examples": null + }, "endpoint_union.getWithBaseProperties": { "auth": null, "declaration": { @@ -7860,7 +10285,18 @@ "type_union:UnionWithReservedNames", "type_union:UserId", "type_union:Name", - "type_union:UnionWithTypeAliases" + "type_union:UnionWithTypeAliases", + "type_union:LeafTypeA", + "type_union:LeafTypeB", + "type_union:NestedObjectUnion", + "type_union:WrapperObject", + "type_union:OuterNestedUnion", + "type_union:AliasedLeafA", + "type_union:AliasedLeafB", + "type_union:AliasToLeafB", + "type_union:LeafObjectA", + "type_union:LeafObjectB", + "type_union:AliasedObjectUnion" ], "errors": [], "subpackages": [], diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-bearer-auth.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-bearer-auth.json index fb6b8f49f7e9..06fcd682b518 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-bearer-auth.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-bearer-auth.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "apiKey", "tokenEnvVar": "SEED_API_KEY", + "tokenPlaceholder": null, "key": "Bearer", "docs": null } diff --git a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-multi-url.json b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-multi-url.json index ea0ffa7c4a1a..cc96565f0058 100644 --- a/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-multi-url.json +++ b/packages/cli/generation/ir-generator-tests/src/ir/__test__/test-definitions/websocket-multi-url.json @@ -12,6 +12,7 @@ "_type": "bearer", "token": "token", "tokenEnvVar": null, + "tokenPlaceholder": null, "key": "bearer", "docs": null } diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json index 68b3f27d5e1f..3e6c3e99eb4f 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/package.json +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/package.json @@ -42,7 +42,7 @@ "@fern-api/core-utils": "workspace:*", "@fern-api/docs-resolver": "workspace:*", "@fern-api/fai-sdk": "catalog:", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/ir-generator": "workspace:*", "@fern-api/ir-migrations": "workspace:*", diff --git a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts index c06f7057c3b8..4eac62a16117 100644 --- a/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts +++ b/packages/cli/generation/remote-generation/remote-workspace-runner/src/publishDocs.ts @@ -3,7 +3,14 @@ import { SourceResolverImpl } from "@fern-api/cli-source-resolver"; import { docsYml, generatorsYml } from "@fern-api/configuration"; import { createFdrService } from "@fern-api/core"; import { MediaType, replaceEnvVariables } from "@fern-api/core-utils"; -import { DocsDefinitionResolver, UploadedFile, wrapWithHttps } from "@fern-api/docs-resolver"; +import { + applyTranslatedFrontmatterToNavTree, + DocsDefinitionResolver, + replaceImagePathsAndUrls, + stripMdxComments, + UploadedFile, + wrapWithHttps +} from "@fern-api/docs-resolver"; import { APIV1Write, FdrAPI as CjsFdrSdk, DocsV1Write, DocsV2Write, FdrClient } from "@fern-api/fdr-sdk"; type DynamicIr = APIV1Write.DynamicIr; @@ -620,6 +627,121 @@ export async function publishDocs({ const publishTime = performance.now() - publishStart; context.logger.debug(`Docs published to FDR in ${publishTime.toFixed(0)}ms`); + // Register translated page content for each configured locale. + // Skip translation registration in preview mode to avoid overwriting production translations. + const translationPages = resolver.getTranslationPages(); + if (!preview && translationPages != null && Object.keys(translationPages).length > 0) { + context.logger.info(`Registering translations for ${Object.keys(translationPages).length} locale(s)...`); + await Promise.all( + Object.entries(translationPages).map(async ([locale, localePages]) => { + try { + // Build a translated DocsDefinition by taking the base definition, + // overriding translated pages, and updating the nav tree to reflect + // any sidebar-title / slug frontmatter in the translated pages. + // + // For each translated page, we apply the same transformations as default locale pages: + // 1. Strip MDX comments to prevent leakage + // 2. Replace relative image paths with file IDs (using base page path for resolution) + // 3. Preserve editThisPageUrl/editThisPageLaunch from the base page + // + // TODO(translations-alpha): Translated pages still need: + // - replaceReferencedMarkdown/Code for and + // - transformAtPrefixImports for @/... and @components/... imports + const collectedFileIds = resolver.getCollectedFileIds(); + const docsWorkspacePath = resolver.getDocsWorkspacePath(); + + const translatedPages = { + ...docsDefinition.pages, + ...Object.fromEntries( + Object.entries(localePages).map(([path, rawMarkdown]) => { + const basePage = docsDefinition.pages[path as DocsV1Write.PageId]; + // Strip MDX comments first + let processedMarkdown = stripMdxComments(rawMarkdown); + // Replace image paths using the base page's location for resolution + // (translated pages reference the same images as the default locale) + const absolutePathToMarkdownFile = resolve( + docsWorkspacePath, + RelativeFilePath.of(path) + ); + processedMarkdown = replaceImagePathsAndUrls( + processedMarkdown, + collectedFileIds, + {}, // markdownFilesToPathName not needed for translations + { + absolutePathToMarkdownFile, + absolutePathToFernFolder: docsWorkspacePath + }, + context + ); + // Rewrite editThisPageUrl to point to the translated file + // URL format: .../fern/${path}?plain=1 -> .../fern/translations/${locale}/${path}?plain=1 + let editThisPageUrl = basePage?.editThisPageUrl; + if (editThisPageUrl != null) { + // Replace /fern/${path} with /fern/translations/${locale}/${path} + const fernPathPattern = `/fern/${path}`; + const translatedPath = `/fern/translations/${locale}/${path}`; + editThisPageUrl = editThisPageUrl.replace( + fernPathPattern, + translatedPath + ) as typeof editThisPageUrl; + } + return [ + path, + { + markdown: processedMarkdown, + rawMarkdown: processedMarkdown, + editThisPageUrl, + editThisPageLaunch: basePage?.editThisPageLaunch + } + ]; + }) + ) + }; + const updatedRoot = applyTranslatedFrontmatterToNavTree( + docsDefinition.config.root, + // localePages is Record (path -> raw markdown) + localePages as Record, + context + ); + const translatedDefinition: DocsDefinition = { + ...docsDefinition, + pages: translatedPages, + config: { + ...docsDefinition.config, + root: updatedRoot + } + }; + context.logger.info( + `Sending translation for locale "${locale}": pages=${JSON.stringify(Object.keys(localePages))}` + ); + // Use a raw fetch instead of the oRPC client to send `docsDefinition` + // (the live server expects that field; the published fdr-sdk still uses `content`). + const translationResponse = await fetch(`${fdrOrigin}/v2/registry/docs/translations/register`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token.value}`, + ...headers // Include telemetry headers (X-CLI-Version, X-CI-Source, etc.) + }, + body: JSON.stringify({ + domain, + orgId: organization, + locale, + docsDefinition: translatedDefinition + }) + }); + if (!translationResponse.ok) { + const body = await translationResponse.text(); + throw new Error(`HTTP ${translationResponse.status}: ${body}`); + } + context.logger.debug(`Registered translations for locale "${locale}"`); + } catch (error) { + context.logger.warn(`Failed to register translations for locale "${locale}": ${String(error)}`); + } + }) + ); + } + const url = wrapWithHttps(urlToOutput); await updateAiChatFromDocsDefinition({ docsDefinition, diff --git a/packages/cli/register/package.json b/packages/cli/register/package.json index 3d28c14590d4..97d5aa43cdc5 100644 --- a/packages/cli/register/package.json +++ b/packages/cli/register/package.json @@ -38,7 +38,7 @@ "@fern-api/configuration": "workspace:*", "@fern-api/core": "workspace:*", "@fern-api/core-utils": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fs-utils": "workspace:*", "@fern-api/ir-generator": "workspace:*", "@fern-api/ir-sdk": "workspace:*", diff --git a/packages/cli/workspace/browser-compatible-fern-workspace/package.json b/packages/cli/workspace/browser-compatible-fern-workspace/package.json index a4226bc53a25..59d1f150f86c 100644 --- a/packages/cli/workspace/browser-compatible-fern-workspace/package.json +++ b/packages/cli/workspace/browser-compatible-fern-workspace/package.json @@ -37,7 +37,7 @@ "@fern-api/asyncapi-to-ir": "workspace:*", "@fern-api/configuration": "workspace:*", "@fern-api/core-utils": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/ir-sdk": "workspace:*", "@fern-api/openapi-ir": "workspace:*", "@fern-api/openapi-ir-parser": "workspace:*", diff --git a/packages/cli/workspace/lazy-fern-workspace/package.json b/packages/cli/workspace/lazy-fern-workspace/package.json index 94468b728d4e..7ca6b1372ba8 100644 --- a/packages/cli/workspace/lazy-fern-workspace/package.json +++ b/packages/cli/workspace/lazy-fern-workspace/package.json @@ -41,7 +41,7 @@ "@fern-api/conjure-to-fern": "workspace:*", "@fern-api/core": "workspace:*", "@fern-api/core-utils": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fern-definition-schema": "workspace:*", "@fern-api/fs-utils": "workspace:*", "@fern-api/graphql-to-fdr": "workspace:*", diff --git a/packages/cli/workspace/loader/src/docs-yml.schema.json b/packages/cli/workspace/loader/src/docs-yml.schema.json index 71f6196be064..61b49185dc54 100644 --- a/packages/cli/workspace/loader/src/docs-yml.schema.json +++ b/packages/cli/workspace/loader/src/docs-yml.schema.json @@ -198,6 +198,19 @@ } ] }, + "translations": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/definitions/docs.TranslationConfig" + } + }, + { + "type": "null" + } + ] + }, "ai-chat": { "oneOf": [ { @@ -4265,6 +4278,28 @@ "tr" ] }, + "docs.TranslationConfig": { + "type": "object", + "properties": { + "lang": { + "$ref": "#/definitions/docs.Language" + }, + "default": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "lang" + ], + "additionalProperties": false + }, "docs.AIChatModel": { "type": "string", "enum": [ diff --git a/packages/cli/yaml/docs-validator/package.json b/packages/cli/yaml/docs-validator/package.json index 73fe84c2bc9b..a80cbc09de07 100644 --- a/packages/cli/yaml/docs-validator/package.json +++ b/packages/cli/yaml/docs-validator/package.json @@ -39,7 +39,7 @@ "@fern-api/core-utils": "workspace:*", "@fern-api/docs-markdown-utils": "workspace:*", "@fern-api/docs-resolver": "workspace:*", - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/fern-definition-schema": "workspace:*", "@fern-api/fs-utils": "workspace:*", "@fern-api/ir-generator": "workspace:*", diff --git a/packages/cli/yaml/docs-validator/src/docsAst/visitDocsConfigFileYamlAst.ts b/packages/cli/yaml/docs-validator/src/docsAst/visitDocsConfigFileYamlAst.ts index 32462a548842..530210ec9b0d 100644 --- a/packages/cli/yaml/docs-validator/src/docsAst/visitDocsConfigFileYamlAst.ts +++ b/packages/cli/yaml/docs-validator/src/docsAst/visitDocsConfigFileYamlAst.ts @@ -399,6 +399,7 @@ export async function visitDocsConfigFileYamlAst({ }, roles: noop, languages: noop, + translations: noop, theme: noop, globalTheme: noop, libraries: noop diff --git a/packages/commons/mock-utils/package.json b/packages/commons/mock-utils/package.json index b9816706b2ac..f100eaeebad1 100644 --- a/packages/commons/mock-utils/package.json +++ b/packages/commons/mock-utils/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "@fern-api/ir-utils": "workspace:*", - "@fern-fern/ir-sdk": "^66.0.0" + "@fern-fern/ir-sdk": "66.0.0" }, "devDependencies": { "@fern-api/configs": "workspace:*", diff --git a/packages/core/package.json b/packages/core/package.json index 237ba2380f8c..b2919e73a674 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -32,7 +32,7 @@ "test:update": "vitest --passWithNoTests --run -u" }, "dependencies": { - "@fern-api/fdr-sdk": "catalog:", + "@fern-api/fdr-sdk": "1.1.23-d25ead8e05", "@fern-api/venus-api-sdk": "catalog:", "@fern-fern/fdr-test-sdk": "catalog:", "@fern-fern/fiddle-sdk": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89c08ac43094..c2073f21565f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -591,7 +591,7 @@ overrides: minimatch: '>=10.2.3' qs: 6.15.0 url-join: ^4.0.1 - '@fern-api/fdr-sdk': 1.1.13-c1ad12a2b8 + '@fern-api/fdr-sdk': 1.1.23-d25ead8e05 form-data: ^4.0.4 '@fern-api/ui-core-utils': 0.145.12-b50d999d1 vite: ^7.3.2 @@ -661,10 +661,10 @@ importers: version: 0.0.1(stylelint@14.16.1) stylelint-config-standard-scss: specifier: 'catalog:' - version: 5.0.0(postcss@8.5.9)(stylelint@14.16.1) + version: 5.0.0(postcss@8.5.10)(stylelint@14.16.1) tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) tsx: specifier: 'catalog:' version: 4.21.0 @@ -1066,8 +1066,8 @@ importers: specifier: 'catalog:' version: 0.0.1167 '@fern-fern/ir-sdk': - specifier: 66.0.0 - version: 66.0.0 + specifier: 66.3.0 + version: 66.3.0 '@types/node': specifier: 'catalog:' version: 22.19.17 @@ -1157,8 +1157,8 @@ importers: specifier: workspace:* version: link:../base '@fern-fern/ir-sdk': - specifier: 66.0.0 - version: 66.0.0 + specifier: 66.3.0 + version: 66.3.0 '@types/node': specifier: 'catalog:' version: 22.19.17 @@ -1208,8 +1208,8 @@ importers: specifier: 'catalog:' version: 0.0.1167 '@fern-fern/ir-sdk': - specifier: 66.0.0 - version: 66.0.0 + specifier: 66.3.0 + version: 66.3.0 '@types/node': specifier: 'catalog:' version: 22.19.17 @@ -3841,8 +3841,8 @@ importers: packages/cli/api-importers/graphql: dependencies: '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../../commons/fs-utils @@ -4332,8 +4332,8 @@ importers: specifier: workspace:* version: link:../yaml/docs-validator '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fern-definition-formatter': specifier: workspace:* version: link:../fern-definition/formatter @@ -4447,7 +4447,7 @@ importers: version: 2.58.5 '@sentry/node': specifier: ^10.45.0 - version: 10.47.0 + version: 10.49.0 '@types/cli-progress': specifier: 'catalog:' version: 3.11.6 @@ -4540,7 +4540,7 @@ importers: version: 3.0.3 tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 'catalog:' version: 5.9.3 @@ -4708,7 +4708,7 @@ importers: version: link:../../configs '@sentry/node': specifier: ^10.45.0 - version: 10.47.0 + version: 10.49.0 '@types/node': specifier: 'catalog:' version: 22.19.17 @@ -4859,7 +4859,7 @@ importers: version: 0.114.0-5745f9e74 '@sentry/node': specifier: ^10.45.0 - version: 10.47.0 + version: 10.49.0 '@types/inquirer': specifier: 'catalog:' version: 9.0.9 @@ -4922,7 +4922,7 @@ importers: version: 7.7.4 tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 'catalog:' version: 5.9.3 @@ -4966,8 +4966,8 @@ importers: specifier: workspace:* version: link:../../commons/core-utils '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fern-definition-schema': specifier: workspace:* version: link:../fern-definition/schema @@ -5003,8 +5003,8 @@ importers: specifier: workspace:* version: link:../../commons/core-utils '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../commons/fs-utils @@ -5082,8 +5082,8 @@ importers: specifier: workspace:* version: link:../../configuration '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../../commons/fs-utils @@ -5122,8 +5122,8 @@ importers: specifier: workspace:* version: link:../commons '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../../commons/fs-utils @@ -5162,8 +5162,8 @@ importers: specifier: workspace:* version: link:../commons '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../../commons/fs-utils @@ -5229,8 +5229,8 @@ importers: packages/cli/docs-markdown-utils: dependencies: '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../commons/fs-utils @@ -5317,8 +5317,8 @@ importers: specifier: workspace:* version: link:../docs-resolver '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../commons/fs-utils @@ -5432,8 +5432,8 @@ importers: specifier: workspace:* version: link:../docs-markdown-utils '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../commons/fs-utils @@ -5535,8 +5535,8 @@ importers: specifier: workspace:* version: link:../configuration '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../commons/fs-utils @@ -6234,8 +6234,8 @@ importers: specifier: 'catalog:' version: 0.0.6-2ee1b7e28 '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../../../commons/fs-utils @@ -6447,8 +6447,8 @@ importers: packages/cli/library-docs-generator: dependencies: '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/task-context': specifier: workspace:* version: link:../task-context @@ -6681,8 +6681,8 @@ importers: specifier: workspace:* version: link:../../commons/core-utils '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fs-utils': specifier: workspace:* version: link:../../commons/fs-utils @@ -6877,8 +6877,8 @@ importers: specifier: workspace:* version: link:../../../commons/core-utils '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/ir-sdk': specifier: workspace:* version: link:../../../ir-sdk @@ -6924,7 +6924,7 @@ importers: version: 0.27.7 tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 'catalog:' version: 5.9.3 @@ -6962,8 +6962,8 @@ importers: specifier: workspace:* version: link:../../../commons/core-utils '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fern-definition-schema': specifier: workspace:* version: link:../../fern-definition/schema @@ -7199,8 +7199,8 @@ importers: specifier: workspace:* version: link:../../docs-resolver '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/fern-definition-schema': specifier: workspace:* version: link:../../fern-definition/schema @@ -7738,7 +7738,7 @@ importers: specifier: workspace:* version: link:../ir-utils '@fern-fern/ir-sdk': - specifier: ^66.0.0 + specifier: 66.0.0 version: 66.0.0 devDependencies: '@fern-api/configs': @@ -7824,7 +7824,7 @@ importers: version: 0.3.0(esbuild@0.27.7) tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) vitest: specifier: 'catalog:' version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(@vitest/coverage-v8@4.1.4)(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -7832,8 +7832,8 @@ importers: packages/core: dependencies: '@fern-api/fdr-sdk': - specifier: 1.1.13-c1ad12a2b8 - version: 1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3) + specifier: 1.1.23-d25ead8e05 + version: 1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3) '@fern-api/venus-api-sdk': specifier: 'catalog:' version: 0.22.34 @@ -7922,7 +7922,7 @@ importers: version: 9.6.1 tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 'catalog:' version: 5.9.3 @@ -8140,7 +8140,7 @@ importers: version: 3.0.3 tsup: specifier: 'catalog:' - version: 8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: 'catalog:' version: 5.9.3 @@ -9393,8 +9393,8 @@ packages: resolution: {integrity: sha512-3qhAAuc4ZJWLaFtyZzaYXfF9OQ5iviNrvLDXtjKScKUNS134fR3v3c3xedCidTq5KedapuBECziUaOmmd6KXVA==} engines: {node: '>=18.0.0'} - '@fern-api/fdr-sdk@1.1.13-c1ad12a2b8': - resolution: {integrity: sha512-5qGDcejIPq/jTLBj2IpN+0wpKsZMbpNiW/Isw3SsUJBjMKujU7ecdro0P+LISVjmCSktvYQf3g6f8nr5MJSJZw==} + '@fern-api/fdr-sdk@1.1.23-d25ead8e05': + resolution: {integrity: sha512-fkcBIQSCI8Pj8k+sLf7p/rfwVCIdNjB3Na5XpsAc/af30JTgVlCmcAip7TgxxFeGjfpBprD7k6XDN162E0ppXQ==} '@fern-api/generator-cli@0.9.11': resolution: {integrity: sha512-pEaz2APvTjddQ8ohuXuxBvyzfk1QhvSRkDT50GzWZcApPZN0bq8pj+7GRwapjF9K9sM5REo5sTC8XIENWT7EvA==} @@ -9923,12 +9923,6 @@ packages: resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/context-async-hooks@2.6.1': - resolution: {integrity: sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.6.1': resolution: {integrity: sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==} engines: {node: ^18.19.0 || >=20.6.0} @@ -9953,12 +9947,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-express@0.62.0': - resolution: {integrity: sha512-Tvx+vgAZKEQxU3Rx+xWLiR0mLxHwmk69/8ya04+VsV9WYh8w6Lhx5hm5yAMvo1wy0KqWgFKBLwSeo3sHCwdOww==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-fs@0.33.0': resolution: {integrity: sha512-sCZWXGalQ01wr3tAhSR9ucqFJ0phidpAle6/17HVjD6gN8FLmZMK/8sKxdXYHy3PbnlV1P4zeiSVFNKpbFMNLA==} engines: {node: ^18.19.0 || >=20.6.0} @@ -10477,141 +10465,141 @@ packages: '@rolldown/pluginutils@1.0.0-rc.12': resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} - '@rollup/rollup-android-arm-eabi@4.60.1': - resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} + '@rollup/rollup-android-arm-eabi@4.60.2': + resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.1': - resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} + '@rollup/rollup-android-arm64@4.60.2': + resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.1': - resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} + '@rollup/rollup-darwin-arm64@4.60.2': + resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.1': - resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} + '@rollup/rollup-darwin-x64@4.60.2': + resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.1': - resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} + '@rollup/rollup-freebsd-arm64@4.60.2': + resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.1': - resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} + '@rollup/rollup-freebsd-x64@4.60.2': + resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.1': - resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.1': - resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.1': - resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} + '@rollup/rollup-linux-arm64-gnu@4.60.2': + resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.1': - resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} + '@rollup/rollup-linux-arm64-musl@4.60.2': + resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.1': - resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} + '@rollup/rollup-linux-loong64-gnu@4.60.2': + resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.1': - resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} + '@rollup/rollup-linux-loong64-musl@4.60.2': + resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.1': - resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.1': - resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} + '@rollup/rollup-linux-ppc64-musl@4.60.2': + resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.1': - resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.1': - resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} + '@rollup/rollup-linux-riscv64-musl@4.60.2': + resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.1': - resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} + '@rollup/rollup-linux-s390x-gnu@4.60.2': + resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.1': - resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} + '@rollup/rollup-linux-x64-gnu@4.60.2': + resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.1': - resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} + '@rollup/rollup-linux-x64-musl@4.60.2': + resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.1': - resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} + '@rollup/rollup-openbsd-x64@4.60.2': + resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.1': - resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} + '@rollup/rollup-openharmony-arm64@4.60.2': + resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.1': - resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} + '@rollup/rollup-win32-arm64-msvc@4.60.2': + resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.1': - resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} + '@rollup/rollup-win32-ia32-msvc@4.60.2': + resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.1': - resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} + '@rollup/rollup-win32-x64-gnu@4.60.2': + resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.1': - resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} + '@rollup/rollup-win32-x64-msvc@4.60.2': + resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} cpu: [x64] os: [win32] @@ -10673,44 +10661,10 @@ packages: engines: {node: '>= 10'} hasBin: true - '@sentry/core@10.47.0': - resolution: {integrity: sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==} - engines: {node: '>=18'} - '@sentry/core@10.49.0': resolution: {integrity: sha512-UaFeum3LUM1mB0d67jvKnqId1yWQjyqmaDV6kWngG03x+jqXb08tJdGpSoxjXZe13jFBbiBL/wKDDYIK7rCK4g==} engines: {node: '>=18'} - '@sentry/node-core@10.47.0': - resolution: {integrity: sha512-qv6LsqHbkQmd0aQEUox/svRSz26J+l4gGjFOUNEay2armZu9XLD+Ct89jpFgZD5oIPNAj2jraodTRqydXiwS5w==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' - '@opentelemetry/instrumentation': '>=0.57.1 <1' - '@opentelemetry/resources': ^1.30.1 || ^2.1.0 - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.39.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@opentelemetry/context-async-hooks': - optional: true - '@opentelemetry/core': - optional: true - '@opentelemetry/exporter-trace-otlp-http': - optional: true - '@opentelemetry/instrumentation': - optional: true - '@opentelemetry/resources': - optional: true - '@opentelemetry/sdk-trace-base': - optional: true - '@opentelemetry/semantic-conventions': - optional: true - '@sentry/node-core@10.49.0': resolution: {integrity: sha512-7WO0KuCDPSq3G54TVUSI1CKFJwB67LasG+n/gDMBqbrarzs/Yh/s34OOMU5gfVQpncxQAmQsy4nEboQms8iNqA==} engines: {node: '>=18'} @@ -10735,24 +10689,10 @@ packages: '@opentelemetry/semantic-conventions': optional: true - '@sentry/node@10.47.0': - resolution: {integrity: sha512-R+btqPepv88o635G6HtVewLjqCLUedBg5HBs7Nq1qbbKvyti01uArUF2f+3DsLenk5B9LUNiRlE+frZA44Ahmw==} - engines: {node: '>=18'} - '@sentry/node@10.49.0': resolution: {integrity: sha512-xr+HXABCiO5mgAJRQxsXRdNOLO0+Ee6CvXAAIqovL2A1GlhxNWc5ooPWeIrrLDJ/KGyT8zI91O5scpVXdXs0uQ==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.47.0': - resolution: {integrity: sha512-f6Hw2lrpCjlOksiosP0Z2jK/+l+21SIdoNglVeG/sttMyx8C8ywONKh0Ha50sFsvB1VaB8n94RKzzf3hkh9V3g==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.39.0 - '@sentry/opentelemetry@10.49.0': resolution: {integrity: sha512-XNLm4dXmtegXQf+EEE2Cs84Ymlo/f5wMx+lg2S2XS4qLbXaPN/HttjhwKftd8D+8iUNfmH+xNMCSshx4s1B/1w==} engines: {node: '>=18'} @@ -13835,8 +13775,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.9: - resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -14158,8 +14098,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.1: - resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} + rollup@4.60.2: + resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -14596,8 +14536,8 @@ packages: resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} tinyrainbow@3.1.0: @@ -15989,7 +15929,7 @@ snapshots: '@blueprintjs/stylelint-plugin@4.1.18(stylelint@14.16.1)': dependencies: '@blueprintjs/colors': 5.1.16 - postcss: 8.5.9 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 stylelint: 14.16.1 @@ -16464,7 +16404,7 @@ snapshots: '@fern-api/fai-sdk@0.0.6-2ee1b7e28': {} - '@fern-api/fdr-sdk@1.1.13-c1ad12a2b8(@opentelemetry/api@1.9.1)(typescript@5.9.3)': + '@fern-api/fdr-sdk@1.1.23-d25ead8e05(@opentelemetry/api@1.9.1)(typescript@5.9.3)': dependencies: '@fern-api/ui-core-utils': 0.145.12-b50d999d1 '@orpc/client': 1.13.9(@opentelemetry/api@1.9.1) @@ -17100,10 +17040,6 @@ snapshots: '@opentelemetry/api@1.9.1': {} - '@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -17135,15 +17071,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-express@0.62.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - '@opentelemetry/instrumentation-fs@0.33.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -17635,79 +17562,79 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.12': {} - '@rollup/rollup-android-arm-eabi@4.60.1': + '@rollup/rollup-android-arm-eabi@4.60.2': optional: true - '@rollup/rollup-android-arm64@4.60.1': + '@rollup/rollup-android-arm64@4.60.2': optional: true - '@rollup/rollup-darwin-arm64@4.60.1': + '@rollup/rollup-darwin-arm64@4.60.2': optional: true - '@rollup/rollup-darwin-x64@4.60.1': + '@rollup/rollup-darwin-x64@4.60.2': optional: true - '@rollup/rollup-freebsd-arm64@4.60.1': + '@rollup/rollup-freebsd-arm64@4.60.2': optional: true - '@rollup/rollup-freebsd-x64@4.60.1': + '@rollup/rollup-freebsd-x64@4.60.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.1': + '@rollup/rollup-linux-arm-musleabihf@4.60.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.1': + '@rollup/rollup-linux-arm64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.1': + '@rollup/rollup-linux-arm64-musl@4.60.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.1': + '@rollup/rollup-linux-loong64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.1': + '@rollup/rollup-linux-loong64-musl@4.60.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.1': + '@rollup/rollup-linux-ppc64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.1': + '@rollup/rollup-linux-ppc64-musl@4.60.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.1': + '@rollup/rollup-linux-riscv64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.1': + '@rollup/rollup-linux-riscv64-musl@4.60.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.1': + '@rollup/rollup-linux-s390x-gnu@4.60.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.1': + '@rollup/rollup-linux-x64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-x64-musl@4.60.1': + '@rollup/rollup-linux-x64-musl@4.60.2': optional: true - '@rollup/rollup-openbsd-x64@4.60.1': + '@rollup/rollup-openbsd-x64@4.60.2': optional: true - '@rollup/rollup-openharmony-arm64@4.60.1': + '@rollup/rollup-openharmony-arm64@4.60.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.1': + '@rollup/rollup-win32-arm64-msvc@4.60.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.1': + '@rollup/rollup-win32-ia32-msvc@4.60.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.1': + '@rollup/rollup-win32-x64-gnu@4.60.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.1': + '@rollup/rollup-win32-x64-msvc@4.60.2': optional: true '@scarf/scarf@1.4.0': {} @@ -17758,24 +17685,8 @@ snapshots: - encoding - supports-color - '@sentry/core@10.47.0': {} - '@sentry/core@10.49.0': {} - '@sentry/node-core@10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': - dependencies: - '@sentry/core': 10.47.0 - '@sentry/opentelemetry': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.1 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node-core@10.49.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: '@sentry/core': 10.49.0 @@ -17788,47 +17699,6 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node@10.47.0': - dependencies: - '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) - '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-amqplib': 0.61.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-connect': 0.57.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-dataloader': 0.31.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-express': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-fs': 0.33.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-generic-pool': 0.57.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-graphql': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-hapi': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-ioredis': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-kafkajs': 0.23.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-knex': 0.58.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-koa': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-lru-memoizer': 0.58.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mongodb': 0.67.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mongoose': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mysql': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mysql2': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-pg': 0.66.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-redis': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-tedious': 0.33.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-undici': 0.24.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) - '@sentry/core': 10.47.0 - '@sentry/node-core': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/opentelemetry': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.1 - transitivePeerDependencies: - - '@opentelemetry/exporter-trace-otlp-http' - - supports-color - '@sentry/node@10.49.0': dependencies: '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) @@ -17867,15 +17737,6 @@ snapshots: - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/opentelemetry@10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/core': 10.47.0 - '@sentry/opentelemetry@10.49.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: '@opentelemetry/api': 1.9.1 @@ -17911,7 +17772,7 @@ snapshots: dependencies: minimatch: 10.2.5 path-browserify: 1.0.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 '@turbo/darwin-64@2.9.5': optional: true @@ -18236,7 +18097,7 @@ snapshots: debug: 4.4.3 minimatch: 10.2.5 semver: 7.7.4 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -18939,7 +18800,7 @@ snapshots: fast-json-stable-stringify: 2.1.0 flatted: 3.4.2 semver: 7.7.4 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 css-functions-list@3.3.3: {} @@ -19565,7 +19426,7 @@ snapshots: dependencies: magic-string: 0.30.21 mlly: 1.8.2 - rollup: 4.60.1 + rollup: 4.60.2 flat-cache@3.2.0: dependencies: @@ -21408,12 +21269,12 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(yaml@2.8.3): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 - postcss: 8.5.9 + postcss: 8.5.10 tsx: 4.21.0 yaml: 2.8.3 @@ -21421,17 +21282,17 @@ snapshots: postcss-resolve-nested-selector@0.1.6: {} - postcss-safe-parser@6.0.0(postcss@8.5.9): + postcss-safe-parser@6.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 - postcss-safe-parser@7.0.1(postcss@8.5.9): + postcss-safe-parser@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 - postcss-scss@4.0.9(postcss@8.5.9): + postcss-scss@4.0.9(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 postcss-selector-parser@6.1.2: dependencies: @@ -21445,7 +21306,7 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.5.9: + postcss@8.5.10: dependencies: nanoid: 3.3.8 picocolors: 1.1.1 @@ -21886,35 +21747,35 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - rollup@4.60.1: + rollup@4.60.2: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.1 - '@rollup/rollup-android-arm64': 4.60.1 - '@rollup/rollup-darwin-arm64': 4.60.1 - '@rollup/rollup-darwin-x64': 4.60.1 - '@rollup/rollup-freebsd-arm64': 4.60.1 - '@rollup/rollup-freebsd-x64': 4.60.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 - '@rollup/rollup-linux-arm-musleabihf': 4.60.1 - '@rollup/rollup-linux-arm64-gnu': 4.60.1 - '@rollup/rollup-linux-arm64-musl': 4.60.1 - '@rollup/rollup-linux-loong64-gnu': 4.60.1 - '@rollup/rollup-linux-loong64-musl': 4.60.1 - '@rollup/rollup-linux-ppc64-gnu': 4.60.1 - '@rollup/rollup-linux-ppc64-musl': 4.60.1 - '@rollup/rollup-linux-riscv64-gnu': 4.60.1 - '@rollup/rollup-linux-riscv64-musl': 4.60.1 - '@rollup/rollup-linux-s390x-gnu': 4.60.1 - '@rollup/rollup-linux-x64-gnu': 4.60.1 - '@rollup/rollup-linux-x64-musl': 4.60.1 - '@rollup/rollup-openbsd-x64': 4.60.1 - '@rollup/rollup-openharmony-arm64': 4.60.1 - '@rollup/rollup-win32-arm64-msvc': 4.60.1 - '@rollup/rollup-win32-ia32-msvc': 4.60.1 - '@rollup/rollup-win32-x64-gnu': 4.60.1 - '@rollup/rollup-win32-x64-msvc': 4.60.1 + '@rollup/rollup-android-arm-eabi': 4.60.2 + '@rollup/rollup-android-arm64': 4.60.2 + '@rollup/rollup-darwin-arm64': 4.60.2 + '@rollup/rollup-darwin-x64': 4.60.2 + '@rollup/rollup-freebsd-arm64': 4.60.2 + '@rollup/rollup-freebsd-x64': 4.60.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 + '@rollup/rollup-linux-arm-musleabihf': 4.60.2 + '@rollup/rollup-linux-arm64-gnu': 4.60.2 + '@rollup/rollup-linux-arm64-musl': 4.60.2 + '@rollup/rollup-linux-loong64-gnu': 4.60.2 + '@rollup/rollup-linux-loong64-musl': 4.60.2 + '@rollup/rollup-linux-ppc64-gnu': 4.60.2 + '@rollup/rollup-linux-ppc64-musl': 4.60.2 + '@rollup/rollup-linux-riscv64-gnu': 4.60.2 + '@rollup/rollup-linux-riscv64-musl': 4.60.2 + '@rollup/rollup-linux-s390x-gnu': 4.60.2 + '@rollup/rollup-linux-x64-gnu': 4.60.2 + '@rollup/rollup-linux-x64-musl': 4.60.2 + '@rollup/rollup-openbsd-x64': 4.60.2 + '@rollup/rollup-openharmony-arm64': 4.60.2 + '@rollup/rollup-win32-arm64-msvc': 4.60.2 + '@rollup/rollup-win32-ia32-msvc': 4.60.2 + '@rollup/rollup-win32-x64-gnu': 4.60.2 + '@rollup/rollup-win32-x64-msvc': 4.60.2 fsevents: 2.3.3 run-async@3.0.0: {} @@ -22105,7 +21966,7 @@ snapshots: is-plain-obj: 4.1.0 semver: 7.7.4 sort-object-keys: 2.1.0 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 source-map-js@1.2.1: {} @@ -22253,9 +22114,9 @@ snapshots: dependencies: stylelint: 14.16.1 - stylelint-config-recommended-scss@7.0.0(postcss@8.5.9)(stylelint@14.16.1): + stylelint-config-recommended-scss@7.0.0(postcss@8.5.10)(stylelint@14.16.1): dependencies: - postcss-scss: 4.0.9(postcss@8.5.9) + postcss-scss: 4.0.9(postcss@8.5.10) stylelint: 14.16.1 stylelint-config-recommended: 8.0.0(stylelint@14.16.1) stylelint-scss: 4.7.0(stylelint@14.16.1) @@ -22266,10 +22127,10 @@ snapshots: dependencies: stylelint: 14.16.1 - stylelint-config-standard-scss@5.0.0(postcss@8.5.9)(stylelint@14.16.1): + stylelint-config-standard-scss@5.0.0(postcss@8.5.10)(stylelint@14.16.1): dependencies: stylelint: 14.16.1 - stylelint-config-recommended-scss: 7.0.0(postcss@8.5.9)(stylelint@14.16.1) + stylelint-config-recommended-scss: 7.0.0(postcss@8.5.10)(stylelint@14.16.1) stylelint-config-standard: 26.0.0(stylelint@14.16.1) transitivePeerDependencies: - postcss @@ -22312,10 +22173,10 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.9 + postcss: 8.5.10 postcss-media-query-parser: 0.2.3 postcss-resolve-nested-selector: 0.1.6 - postcss-safe-parser: 6.0.0(postcss@8.5.9) + postcss-safe-parser: 6.0.0(postcss@8.5.10) postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 @@ -22360,9 +22221,9 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.9 + postcss: 8.5.10 postcss-resolve-nested-selector: 0.1.6 - postcss-safe-parser: 7.0.1(postcss@8.5.9) + postcss-safe-parser: 7.0.1(postcss@8.5.10) postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 @@ -22382,7 +22243,7 @@ snapshots: lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.7 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 ts-interface-checker: 0.1.13 supports-color@4.5.0: @@ -22514,7 +22375,7 @@ snapshots: tinyexec@1.1.1: {} - tinyglobby@0.2.15: + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -22603,7 +22464,7 @@ snapshots: rolldown-plugin-dts: 0.21.9(oxc-resolver@11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2))(rolldown@1.0.0-rc.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2))(typescript@5.9.3) semver: 7.7.4 tinyexec: 1.1.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 tree-kill: 1.2.2 unconfig-core: 7.5.0 unrun: 0.2.34(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) @@ -22622,7 +22483,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 @@ -22633,16 +22494,16 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.9)(tsx@4.21.0)(yaml@2.8.3) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.10)(tsx@4.21.0)(yaml@2.8.3) resolve-from: 5.0.0 - rollup: 4.60.1 + rollup: 4.60.2 source-map: 0.7.6 sucrase: 3.35.1 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.5.9 + postcss: 8.5.10 typescript: 5.9.3 transitivePeerDependencies: - jiti @@ -22858,9 +22719,9 @@ snapshots: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.9 - rollup: 4.60.1 - tinyglobby: 0.2.15 + postcss: 8.5.10 + rollup: 4.60.2 + tinyglobby: 0.2.16 optionalDependencies: '@types/node': 22.19.17 fsevents: 2.3.3 @@ -22886,7 +22747,7 @@ snapshots: std-env: 4.0.0 tinybench: 2.9.0 tinyexec: 1.1.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 tinyrainbow: 3.1.0 vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7f35d6e2745b..80f3b684e43d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -58,7 +58,7 @@ catalog: "@bufbuild/protobuf": ^2.2.5 "@bufbuild/protoplugin": 2.2.5 "@fern-api/fai-sdk": 0.0.6-2ee1b7e28 - "@fern-api/fdr-sdk": 1.1.13-c1ad12a2b8 + "@fern-api/fdr-sdk": 1.1.23-d25ead8e05 "@fern-api/generator-cli": 0.9.11 "@fern-api/ui-core-utils": 0.129.4-b6c699ad2 "@fern-api/venus-api-sdk": 0.22.34 diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example10.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example10.cs index d1f52216ce91..fc0eacc7b664 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example10.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example10.cs @@ -9,12 +9,10 @@ public async Task Example10() { } ); - await client.Union.TestCamelCasePropertiesAsync( - new PaymentRequest { - PaymentMethod = new TokenizeCard { - Method = "card", - CardNumber = "1234567890123456" - } + await client.Union.AliasedObjectUnionAsync( + new LeafObjectA { + OnlyInA = "onlyInA", + SharedNumber = 1 } ); } diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example11.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example11.cs index d7fb4d6043f5..a03f3add5644 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example11.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example11.cs @@ -9,12 +9,17 @@ public async Task Example11() { } ); - await client.Union.TestCamelCasePropertiesAsync( - new PaymentRequest { - PaymentMethod = new TokenizeCard { - Method = "method", - CardNumber = "cardNumber" + await client.Union.GetWithBasePropertiesAsync( + new NamedMetadata { + Name = "name", + Value = new Dictionary(){ + ["value"] = new Dictionary() + { + ["key"] = "value", + } + , } + } ); } diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example12.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example12.cs new file mode 100644 index 000000000000..3bd00fcc47b7 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example12.cs @@ -0,0 +1,22 @@ +using SeedUndiscriminatedUnions; + +public partial class Examples +{ + public async Task Example12() { + var client = new SeedUndiscriminatedUnionsClient( + clientOptions: new ClientOptions { + BaseUrl = "https://api.fern.com" + } + ); + + await client.Union.TestCamelCasePropertiesAsync( + new PaymentRequest { + PaymentMethod = new TokenizeCard { + Method = "card", + CardNumber = "1234567890123456" + } + } + ); + } + +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example13.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example13.cs new file mode 100644 index 000000000000..c9c980d4a9cd --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example13.cs @@ -0,0 +1,22 @@ +using SeedUndiscriminatedUnions; + +public partial class Examples +{ + public async Task Example13() { + var client = new SeedUndiscriminatedUnionsClient( + clientOptions: new ClientOptions { + BaseUrl = "https://api.fern.com" + } + ); + + await client.Union.TestCamelCasePropertiesAsync( + new PaymentRequest { + PaymentMethod = new TokenizeCard { + Method = "method", + CardNumber = "cardNumber" + } + } + ); + } + +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example9.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example9.cs index 2b8c814df1c4..fb894666b954 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example9.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/Snippets/Example9.cs @@ -9,18 +9,8 @@ public async Task Example9() { } ); - await client.Union.GetWithBasePropertiesAsync( - new NamedMetadata { - Name = "name", - Value = new Dictionary(){ - ["value"] = new Dictionary() - { - ["key"] = "value", - } - , - } - - } + await client.Union.NestedObjectUnionsAsync( + "string" ); } diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/reference.md b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/reference.md index 8865bcce0b0c..5e77b1765a02 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/reference.md +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/reference.md @@ -240,6 +240,88 @@ await client.Union.NestedUnionsAsync("string"); + + + + +
client.Union.NestedObjectUnionsAsync(OneOf<string, WrapperObject> { ... }) -> WithRawResponseTask<string> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Union.NestedObjectUnionsAsync("string"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `OneOf` + +
+
+
+
+ + +
+
+
+ +
client.Union.AliasedObjectUnionAsync(OneOf<LeafObjectA, LeafObjectB> { ... }) -> WithRawResponseTask<string> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Union.AliasedObjectUnionAsync( + new LeafObjectA { OnlyInA = "onlyInA", SharedNumber = 1 } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `OneOf` + +
+
+
+
+ +
diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/snippet.json b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/snippet.json index bf19dd198e86..0f7b254c6468 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/snippet.json +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/snippet.json @@ -73,6 +73,30 @@ "client": "using SeedUndiscriminatedUnions;\n\nvar client = new SeedUndiscriminatedUnionsClient();\nawait client.Union.NestedUnionsAsync(\"string\");\n" } }, + { + "example_identifier": null, + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "csharp", + "client": "using SeedUndiscriminatedUnions;\n\nvar client = new SeedUndiscriminatedUnionsClient();\nawait client.Union.NestedObjectUnionsAsync(\"string\");\n" + } + }, + { + "example_identifier": null, + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "csharp", + "client": "using SeedUndiscriminatedUnions;\n\nvar client = new SeedUndiscriminatedUnionsClient();\nawait client.Union.AliasedObjectUnionAsync(\n new LeafObjectA { OnlyInA = \"onlyInA\", SharedNumber = 1 }\n);\n" + } + }, { "example_identifier": null, "id": { diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/AliasedObjectUnionTest.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/AliasedObjectUnionTest.cs new file mode 100644 index 000000000000..20deadeaf920 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/AliasedObjectUnionTest.cs @@ -0,0 +1,46 @@ +using NUnit.Framework; +using SeedUndiscriminatedUnions; +using SeedUndiscriminatedUnions.Test.Unit.MockServer; +using SeedUndiscriminatedUnions.Test.Utils; + +namespace SeedUndiscriminatedUnions.Test.Unit.MockServer.Union; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class AliasedObjectUnionTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest() + { + const string requestJson = """ + { + "onlyInA": "onlyInA", + "sharedNumber": 1 + } + """; + + const string mockResponse = """ + "string" + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/aliased-object") + .UsingPost() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Union.AliasedObjectUnionAsync( + new LeafObjectA { OnlyInA = "onlyInA", SharedNumber = 1 } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/NestedObjectUnionsTest.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/NestedObjectUnionsTest.cs new file mode 100644 index 000000000000..fe124e2526ca --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/NestedObjectUnionsTest.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using SeedUndiscriminatedUnions.Test.Unit.MockServer; +using SeedUndiscriminatedUnions.Test.Utils; + +namespace SeedUndiscriminatedUnions.Test.Unit.MockServer.Union; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class NestedObjectUnionsTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest() + { + const string requestJson = """ + "string" + """; + + const string mockResponse = """ + "string" + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/nested-objects") + .UsingPost() + .WithBody(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Union.NestedObjectUnionsAsync("string"); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs index 4b9aacfee572..a69a750aae26 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs @@ -66,6 +66,18 @@ WithRawResponseTask NestedUnionsAsync( CancellationToken cancellationToken = default ); + WithRawResponseTask NestedObjectUnionsAsync( + OneOf request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + WithRawResponseTask AliasedObjectUnionAsync( + OneOf request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + WithRawResponseTask< OneOf?> > GetWithBasePropertiesAsync( diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectA.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectA.cs new file mode 100644 index 000000000000..d2dc9b100f4d --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectA.cs @@ -0,0 +1,31 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafObjectA : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("onlyInA")] + public required string OnlyInA { get; set; } + + [JsonPropertyName("sharedNumber")] + public required int SharedNumber { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectB.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectB.cs new file mode 100644 index 000000000000..9f3fe6992b70 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectB.cs @@ -0,0 +1,28 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafObjectB : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("onlyInB")] + public required string OnlyInB { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeA.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeA.cs new file mode 100644 index 000000000000..e7e05fc0bac6 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeA.cs @@ -0,0 +1,31 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafTypeA : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("alpha")] + public required string Alpha { get; set; } + + [JsonPropertyName("beta")] + public required int Beta { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeB.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeB.cs new file mode 100644 index 000000000000..a1d0ffc18097 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeB.cs @@ -0,0 +1,28 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafTypeB : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("gamma")] + public required string Gamma { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/WrapperObject.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/WrapperObject.cs new file mode 100644 index 000000000000..227b66042468 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/Types/WrapperObject.cs @@ -0,0 +1,32 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using OneOf; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record WrapperObject : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("inner")] + public required OneOf Inner { get; set; } + + [JsonPropertyName("label")] + public required string Label { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/UnionClient.cs b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/UnionClient.cs index aff7b5cdbd28..e0f467966efd 100644 --- a/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/UnionClient.cs +++ b/seed/csharp-sdk/undiscriminated-unions/no-custom-config/src/SeedUndiscriminatedUnions/Union/UnionClient.cs @@ -462,6 +462,138 @@ private async Task> NestedUnionsAsyncCore( } } + private async Task> NestedObjectUnionsAsyncCore( + OneOf request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _headers = await new SeedUndiscriminatedUnions.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Post, + Path = "/nested-objects", + Body = request, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new SeedUndiscriminatedUnionsApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + throw new SeedUndiscriminatedUnionsApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody + ); + } + } + + private async Task> AliasedObjectUnionAsyncCore( + OneOf request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _headers = await new SeedUndiscriminatedUnions.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Post, + Path = "/aliased-object", + Body = request, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new SeedUndiscriminatedUnionsApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + throw new SeedUndiscriminatedUnionsApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody + ); + } + } + private async Task< WithRawResponse?>> > GetWithBasePropertiesAsyncCore( @@ -732,6 +864,36 @@ public WithRawResponseTask NestedUnionsAsync( ); } + /// + /// await client.Union.NestedObjectUnionsAsync("string"); + /// + public WithRawResponseTask NestedObjectUnionsAsync( + OneOf request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + NestedObjectUnionsAsyncCore(request, options, cancellationToken) + ); + } + + /// + /// await client.Union.AliasedObjectUnionAsync( + /// new LeafObjectA { OnlyInA = "onlyInA", SharedNumber = 1 } + /// ); + /// + public WithRawResponseTask AliasedObjectUnionAsync( + OneOf request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + AliasedObjectUnionAsyncCore(request, options, cancellationToken) + ); + } + /// /// await client.Union.GetWithBasePropertiesAsync( /// new NamedMetadata diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example10.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example10.cs index d1f52216ce91..fc0eacc7b664 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example10.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example10.cs @@ -9,12 +9,10 @@ public async Task Example10() { } ); - await client.Union.TestCamelCasePropertiesAsync( - new PaymentRequest { - PaymentMethod = new TokenizeCard { - Method = "card", - CardNumber = "1234567890123456" - } + await client.Union.AliasedObjectUnionAsync( + new LeafObjectA { + OnlyInA = "onlyInA", + SharedNumber = 1 } ); } diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example11.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example11.cs index d7fb4d6043f5..a03f3add5644 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example11.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example11.cs @@ -9,12 +9,17 @@ public async Task Example11() { } ); - await client.Union.TestCamelCasePropertiesAsync( - new PaymentRequest { - PaymentMethod = new TokenizeCard { - Method = "method", - CardNumber = "cardNumber" + await client.Union.GetWithBasePropertiesAsync( + new NamedMetadata { + Name = "name", + Value = new Dictionary(){ + ["value"] = new Dictionary() + { + ["key"] = "value", + } + , } + } ); } diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example12.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example12.cs new file mode 100644 index 000000000000..3bd00fcc47b7 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example12.cs @@ -0,0 +1,22 @@ +using SeedUndiscriminatedUnions; + +public partial class Examples +{ + public async Task Example12() { + var client = new SeedUndiscriminatedUnionsClient( + clientOptions: new ClientOptions { + BaseUrl = "https://api.fern.com" + } + ); + + await client.Union.TestCamelCasePropertiesAsync( + new PaymentRequest { + PaymentMethod = new TokenizeCard { + Method = "card", + CardNumber = "1234567890123456" + } + } + ); + } + +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example13.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example13.cs new file mode 100644 index 000000000000..c9c980d4a9cd --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example13.cs @@ -0,0 +1,22 @@ +using SeedUndiscriminatedUnions; + +public partial class Examples +{ + public async Task Example13() { + var client = new SeedUndiscriminatedUnionsClient( + clientOptions: new ClientOptions { + BaseUrl = "https://api.fern.com" + } + ); + + await client.Union.TestCamelCasePropertiesAsync( + new PaymentRequest { + PaymentMethod = new TokenizeCard { + Method = "method", + CardNumber = "cardNumber" + } + } + ); + } + +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example9.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example9.cs index 2b8c814df1c4..fb894666b954 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example9.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/Snippets/Example9.cs @@ -9,18 +9,8 @@ public async Task Example9() { } ); - await client.Union.GetWithBasePropertiesAsync( - new NamedMetadata { - Name = "name", - Value = new Dictionary(){ - ["value"] = new Dictionary() - { - ["key"] = "value", - } - , - } - - } + await client.Union.NestedObjectUnionsAsync( + "string" ); } diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/reference.md b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/reference.md index 677efd321228..b2055050a8cd 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/reference.md +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/reference.md @@ -240,6 +240,88 @@ await client.Union.NestedUnionsAsync("string"); + + + + +
client.Union.NestedObjectUnionsAsync(OuterNestedUnion { ... }) -> WithRawResponseTask<string> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Union.NestedObjectUnionsAsync("string"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `OuterNestedUnion` + +
+
+
+
+ + +
+
+
+ +
client.Union.AliasedObjectUnionAsync(AliasedObjectUnion { ... }) -> WithRawResponseTask<string> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Union.AliasedObjectUnionAsync( + new LeafObjectA { OnlyInA = "onlyInA", SharedNumber = 1 } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `AliasedObjectUnion` + +
+
+
+
+ +
diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/snippet.json b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/snippet.json index bf19dd198e86..0f7b254c6468 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/snippet.json +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/snippet.json @@ -73,6 +73,30 @@ "client": "using SeedUndiscriminatedUnions;\n\nvar client = new SeedUndiscriminatedUnionsClient();\nawait client.Union.NestedUnionsAsync(\"string\");\n" } }, + { + "example_identifier": null, + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "csharp", + "client": "using SeedUndiscriminatedUnions;\n\nvar client = new SeedUndiscriminatedUnionsClient();\nawait client.Union.NestedObjectUnionsAsync(\"string\");\n" + } + }, + { + "example_identifier": null, + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "csharp", + "client": "using SeedUndiscriminatedUnions;\n\nvar client = new SeedUndiscriminatedUnionsClient();\nawait client.Union.AliasedObjectUnionAsync(\n new LeafObjectA { OnlyInA = \"onlyInA\", SharedNumber = 1 }\n);\n" + } + }, { "example_identifier": null, "id": { diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/AliasedObjectUnionTest.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/AliasedObjectUnionTest.cs new file mode 100644 index 000000000000..20deadeaf920 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/AliasedObjectUnionTest.cs @@ -0,0 +1,46 @@ +using NUnit.Framework; +using SeedUndiscriminatedUnions; +using SeedUndiscriminatedUnions.Test.Unit.MockServer; +using SeedUndiscriminatedUnions.Test.Utils; + +namespace SeedUndiscriminatedUnions.Test.Unit.MockServer.Union; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class AliasedObjectUnionTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest() + { + const string requestJson = """ + { + "onlyInA": "onlyInA", + "sharedNumber": 1 + } + """; + + const string mockResponse = """ + "string" + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/aliased-object") + .UsingPost() + .WithBodyAsJson(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Union.AliasedObjectUnionAsync( + new LeafObjectA { OnlyInA = "onlyInA", SharedNumber = 1 } + ); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/NestedObjectUnionsTest.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/NestedObjectUnionsTest.cs new file mode 100644 index 000000000000..fe124e2526ca --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions.Test/Unit/MockServer/Union/NestedObjectUnionsTest.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using SeedUndiscriminatedUnions.Test.Unit.MockServer; +using SeedUndiscriminatedUnions.Test.Utils; + +namespace SeedUndiscriminatedUnions.Test.Unit.MockServer.Union; + +[TestFixture] +[Parallelizable(ParallelScope.Self)] +public class NestedObjectUnionsTest : BaseMockServerTest +{ + [NUnit.Framework.Test] + public async Task MockServerTest() + { + const string requestJson = """ + "string" + """; + + const string mockResponse = """ + "string" + """; + + Server + .Given( + WireMock + .RequestBuilders.Request.Create() + .WithPath("/nested-objects") + .UsingPost() + .WithBody(requestJson) + ) + .RespondWith( + WireMock + .ResponseBuilders.Response.Create() + .WithStatusCode(200) + .WithBody(mockResponse) + ); + + var response = await Client.Union.NestedObjectUnionsAsync("string"); + JsonAssert.AreEqual(response, mockResponse); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs index ef07b594c703..e694ec53a1bc 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/IUnionClient.cs @@ -37,6 +37,18 @@ WithRawResponseTask NestedUnionsAsync( CancellationToken cancellationToken = default ); + WithRawResponseTask NestedObjectUnionsAsync( + OuterNestedUnion request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + + WithRawResponseTask AliasedObjectUnionAsync( + AliasedObjectUnion request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ); + WithRawResponseTask GetWithBasePropertiesAsync( UnionWithBaseProperties request, RequestOptions? options = null, diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs new file mode 100644 index 000000000000..dc9ed4ee5716 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/AliasedObjectUnion.cs @@ -0,0 +1,256 @@ +// ReSharper disable NullableWarningSuppressionIsUsed +// ReSharper disable InconsistentNaming + +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +/// +/// Undiscriminated union whose members are named aliases of object types +/// (including an alias-of-alias). Required keys are disjoint, so a correct +/// deserializer must emit containsKey() guards for each alias variant. +/// +[JsonConverter(typeof(AliasedObjectUnion.JsonConverter))] +[Serializable] +public class AliasedObjectUnion +{ + private AliasedObjectUnion(string type, object? value) + { + Type = type; + Value = value; + } + + /// + /// Type discriminator + /// + [JsonIgnore] + public string Type { get; internal set; } + + /// + /// Union value + /// + [JsonIgnore] + public object? Value { get; internal set; } + + /// + /// Factory method to create a union from a LeafObjectA value. + /// + public static AliasedObjectUnion FromAliasedLeafA(LeafObjectA value) => + new("aliasedLeafA", value); + + /// + /// Factory method to create a union from a LeafObjectB value. + /// + public static AliasedObjectUnion FromAliasedLeafB(LeafObjectB value) => + new("aliasedLeafB", value); + + /// + /// Returns true if is "aliasedLeafA" + /// + public bool IsAliasedLeafA() => Type == "aliasedLeafA"; + + /// + /// Returns true if is "aliasedLeafB" + /// + public bool IsAliasedLeafB() => Type == "aliasedLeafB"; + + /// + /// Returns the value as a if is 'aliasedLeafA', otherwise throws an exception. + /// + /// Thrown when is not 'aliasedLeafA'. + public LeafObjectA AsAliasedLeafA() => + IsAliasedLeafA() + ? (LeafObjectA)Value! + : throw new SeedUndiscriminatedUnionsException("Union type is not 'aliasedLeafA'"); + + /// + /// Returns the value as a if is 'aliasedLeafB', otherwise throws an exception. + /// + /// Thrown when is not 'aliasedLeafB'. + public LeafObjectB AsAliasedLeafB() => + IsAliasedLeafB() + ? (LeafObjectB)Value! + : throw new SeedUndiscriminatedUnionsException("Union type is not 'aliasedLeafB'"); + + /// + /// Attempts to cast the value to a and returns true if successful. + /// + public bool TryGetAliasedLeafA(out LeafObjectA? value) + { + if (Type == "aliasedLeafA") + { + value = (LeafObjectA)Value!; + return true; + } + value = null; + return false; + } + + /// + /// Attempts to cast the value to a and returns true if successful. + /// + public bool TryGetAliasedLeafB(out LeafObjectB? value) + { + if (Type == "aliasedLeafB") + { + value = (LeafObjectB)Value!; + return true; + } + value = null; + return false; + } + + public T Match(Func onAliasedLeafA, Func onAliasedLeafB) + { + return Type switch + { + "aliasedLeafA" => onAliasedLeafA(AsAliasedLeafA()), + "aliasedLeafB" => onAliasedLeafB(AsAliasedLeafB()), + _ => throw new SeedUndiscriminatedUnionsException($"Unknown union type: {Type}"), + }; + } + + public void Visit(Action onAliasedLeafA, Action onAliasedLeafB) + { + switch (Type) + { + case "aliasedLeafA": + onAliasedLeafA(AsAliasedLeafA()); + break; + case "aliasedLeafB": + onAliasedLeafB(AsAliasedLeafB()); + break; + default: + throw new SeedUndiscriminatedUnionsException($"Unknown union type: {Type}"); + } + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Type.GetHashCode(); + if (Value != null) + { + hashCode = (hashCode * 397) ^ Value.GetHashCode(); + } + return hashCode; + } + } + + public override bool Equals(object? obj) + { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj is not AliasedObjectUnion other) + return false; + + // Compare type discriminators + if (Type != other.Type) + return false; + + // Compare values using EqualityComparer for deep comparison + return System.Collections.Generic.EqualityComparer.Default.Equals( + Value, + other.Value + ); + } + + public override string ToString() => JsonUtils.Serialize(this); + + public static implicit operator AliasedObjectUnion(LeafObjectA value) => + new("aliasedLeafA", value); + + public static implicit operator AliasedObjectUnion(LeafObjectB value) => + new("aliasedLeafB", value); + + [Serializable] + internal sealed class JsonConverter : JsonConverter + { + public override AliasedObjectUnion? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + if (reader.TokenType == JsonTokenType.StartObject) + { + var document = JsonDocument.ParseValue(ref reader); + + var types = new (string Key, System.Type Type)[] + { + ("aliasedLeafA", typeof(LeafObjectA)), + ("aliasedLeafB", typeof(LeafObjectB)), + }; + + foreach (var (key, type) in types) + { + try + { + var value = document.Deserialize(type, options); + if (value != null) + { + AliasedObjectUnion result = new(key, value); + return result; + } + } + catch (JsonException) + { + // Try next type; + } + } + } + + throw new JsonException( + $"Cannot deserialize JSON token {reader.TokenType} into AliasedObjectUnion" + ); + } + + public override void Write( + Utf8JsonWriter writer, + AliasedObjectUnion value, + JsonSerializerOptions options + ) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + + value.Visit( + obj => JsonSerializer.Serialize(writer, obj, options), + obj => JsonSerializer.Serialize(writer, obj, options) + ); + } + + public override AliasedObjectUnion ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = reader.GetString()!; + AliasedObjectUnion result = new("string", stringValue); + return result; + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + AliasedObjectUnion value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.Value?.ToString() ?? "null"); + } + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectA.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectA.cs new file mode 100644 index 000000000000..d2dc9b100f4d --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectA.cs @@ -0,0 +1,31 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafObjectA : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("onlyInA")] + public required string OnlyInA { get; set; } + + [JsonPropertyName("sharedNumber")] + public required int SharedNumber { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectB.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectB.cs new file mode 100644 index 000000000000..9f3fe6992b70 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafObjectB.cs @@ -0,0 +1,28 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafObjectB : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("onlyInB")] + public required string OnlyInB { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeA.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeA.cs new file mode 100644 index 000000000000..e7e05fc0bac6 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeA.cs @@ -0,0 +1,31 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafTypeA : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("alpha")] + public required string Alpha { get; set; } + + [JsonPropertyName("beta")] + public required int Beta { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeB.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeB.cs new file mode 100644 index 000000000000..a1d0ffc18097 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/LeafTypeB.cs @@ -0,0 +1,28 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record LeafTypeB : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("gamma")] + public required string Gamma { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs new file mode 100644 index 000000000000..fb772f0c4e56 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/NestedObjectUnion.cs @@ -0,0 +1,261 @@ +// ReSharper disable NullableWarningSuppressionIsUsed +// ReSharper disable InconsistentNaming + +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +/// +/// Inner union with two object variants that have disjoint required keys. +/// Tests that required-key guards work correctly inside nested union contexts. +/// +[JsonConverter(typeof(NestedObjectUnion.JsonConverter))] +[Serializable] +public class NestedObjectUnion +{ + private NestedObjectUnion(string type, object? value) + { + Type = type; + Value = value; + } + + /// + /// Type discriminator + /// + [JsonIgnore] + public string Type { get; internal set; } + + /// + /// Union value + /// + [JsonIgnore] + public object? Value { get; internal set; } + + /// + /// Factory method to create a union from a SeedUndiscriminatedUnions.LeafTypeA value. + /// + public static NestedObjectUnion FromLeafTypeA(SeedUndiscriminatedUnions.LeafTypeA value) => + new("leafTypeA", value); + + /// + /// Factory method to create a union from a SeedUndiscriminatedUnions.LeafTypeB value. + /// + public static NestedObjectUnion FromLeafTypeB(SeedUndiscriminatedUnions.LeafTypeB value) => + new("leafTypeB", value); + + /// + /// Returns true if is "leafTypeA" + /// + public bool IsLeafTypeA() => Type == "leafTypeA"; + + /// + /// Returns true if is "leafTypeB" + /// + public bool IsLeafTypeB() => Type == "leafTypeB"; + + /// + /// Returns the value as a if is 'leafTypeA', otherwise throws an exception. + /// + /// Thrown when is not 'leafTypeA'. + public SeedUndiscriminatedUnions.LeafTypeA AsLeafTypeA() => + IsLeafTypeA() + ? (SeedUndiscriminatedUnions.LeafTypeA)Value! + : throw new SeedUndiscriminatedUnionsException("Union type is not 'leafTypeA'"); + + /// + /// Returns the value as a if is 'leafTypeB', otherwise throws an exception. + /// + /// Thrown when is not 'leafTypeB'. + public SeedUndiscriminatedUnions.LeafTypeB AsLeafTypeB() => + IsLeafTypeB() + ? (SeedUndiscriminatedUnions.LeafTypeB)Value! + : throw new SeedUndiscriminatedUnionsException("Union type is not 'leafTypeB'"); + + /// + /// Attempts to cast the value to a and returns true if successful. + /// + public bool TryGetLeafTypeA(out SeedUndiscriminatedUnions.LeafTypeA? value) + { + if (Type == "leafTypeA") + { + value = (SeedUndiscriminatedUnions.LeafTypeA)Value!; + return true; + } + value = null; + return false; + } + + /// + /// Attempts to cast the value to a and returns true if successful. + /// + public bool TryGetLeafTypeB(out SeedUndiscriminatedUnions.LeafTypeB? value) + { + if (Type == "leafTypeB") + { + value = (SeedUndiscriminatedUnions.LeafTypeB)Value!; + return true; + } + value = null; + return false; + } + + public T Match( + Func onLeafTypeA, + Func onLeafTypeB + ) + { + return Type switch + { + "leafTypeA" => onLeafTypeA(AsLeafTypeA()), + "leafTypeB" => onLeafTypeB(AsLeafTypeB()), + _ => throw new SeedUndiscriminatedUnionsException($"Unknown union type: {Type}"), + }; + } + + public void Visit( + Action onLeafTypeA, + Action onLeafTypeB + ) + { + switch (Type) + { + case "leafTypeA": + onLeafTypeA(AsLeafTypeA()); + break; + case "leafTypeB": + onLeafTypeB(AsLeafTypeB()); + break; + default: + throw new SeedUndiscriminatedUnionsException($"Unknown union type: {Type}"); + } + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Type.GetHashCode(); + if (Value != null) + { + hashCode = (hashCode * 397) ^ Value.GetHashCode(); + } + return hashCode; + } + } + + public override bool Equals(object? obj) + { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj is not NestedObjectUnion other) + return false; + + // Compare type discriminators + if (Type != other.Type) + return false; + + // Compare values using EqualityComparer for deep comparison + return System.Collections.Generic.EqualityComparer.Default.Equals( + Value, + other.Value + ); + } + + public override string ToString() => JsonUtils.Serialize(this); + + public static implicit operator NestedObjectUnion(SeedUndiscriminatedUnions.LeafTypeA value) => + new("leafTypeA", value); + + public static implicit operator NestedObjectUnion(SeedUndiscriminatedUnions.LeafTypeB value) => + new("leafTypeB", value); + + [Serializable] + internal sealed class JsonConverter : JsonConverter + { + public override NestedObjectUnion? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + if (reader.TokenType == JsonTokenType.StartObject) + { + var document = JsonDocument.ParseValue(ref reader); + + var types = new (string Key, System.Type Type)[] + { + ("leafTypeA", typeof(SeedUndiscriminatedUnions.LeafTypeA)), + ("leafTypeB", typeof(SeedUndiscriminatedUnions.LeafTypeB)), + }; + + foreach (var (key, type) in types) + { + try + { + var value = document.Deserialize(type, options); + if (value != null) + { + NestedObjectUnion result = new(key, value); + return result; + } + } + catch (JsonException) + { + // Try next type; + } + } + } + + throw new JsonException( + $"Cannot deserialize JSON token {reader.TokenType} into NestedObjectUnion" + ); + } + + public override void Write( + Utf8JsonWriter writer, + NestedObjectUnion value, + JsonSerializerOptions options + ) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + + value.Visit( + obj => JsonSerializer.Serialize(writer, obj, options), + obj => JsonSerializer.Serialize(writer, obj, options) + ); + } + + public override NestedObjectUnion ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = reader.GetString()!; + NestedObjectUnion result = new("string", stringValue); + return result; + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + NestedObjectUnion value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.Value?.ToString() ?? "null"); + } + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs new file mode 100644 index 000000000000..83c1b45681f8 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/OuterNestedUnion.cs @@ -0,0 +1,268 @@ +// ReSharper disable NullableWarningSuppressionIsUsed +// ReSharper disable InconsistentNaming + +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +/// +/// Outer union where one variant is an object containing a nested union field. +/// Tests that the deserializer correctly handles transitive union deserialization. +/// +[JsonConverter(typeof(OuterNestedUnion.JsonConverter))] +[Serializable] +public class OuterNestedUnion +{ + private OuterNestedUnion(string type, object? value) + { + Type = type; + Value = value; + } + + /// + /// Type discriminator + /// + [JsonIgnore] + public string Type { get; internal set; } + + /// + /// Union value + /// + [JsonIgnore] + public object? Value { get; internal set; } + + /// + /// Factory method to create a union from a string value. + /// + public static OuterNestedUnion FromString(string value) => new("string", value); + + /// + /// Factory method to create a union from a SeedUndiscriminatedUnions.WrapperObject value. + /// + public static OuterNestedUnion FromWrapperObject( + SeedUndiscriminatedUnions.WrapperObject value + ) => new("wrapperObject", value); + + /// + /// Returns true if is "string" + /// + public bool IsString() => Type == "string"; + + /// + /// Returns true if is "wrapperObject" + /// + public bool IsWrapperObject() => Type == "wrapperObject"; + + /// + /// Returns the value as a if is 'string', otherwise throws an exception. + /// + /// Thrown when is not 'string'. + public string AsString() => + IsString() + ? (string)Value! + : throw new SeedUndiscriminatedUnionsException("Union type is not 'string'"); + + /// + /// Returns the value as a if is 'wrapperObject', otherwise throws an exception. + /// + /// Thrown when is not 'wrapperObject'. + public SeedUndiscriminatedUnions.WrapperObject AsWrapperObject() => + IsWrapperObject() + ? (SeedUndiscriminatedUnions.WrapperObject)Value! + : throw new SeedUndiscriminatedUnionsException("Union type is not 'wrapperObject'"); + + /// + /// Attempts to cast the value to a and returns true if successful. + /// + public bool TryGetString(out string? value) + { + if (Type == "string") + { + value = (string)Value!; + return true; + } + value = null; + return false; + } + + /// + /// Attempts to cast the value to a and returns true if successful. + /// + public bool TryGetWrapperObject(out SeedUndiscriminatedUnions.WrapperObject? value) + { + if (Type == "wrapperObject") + { + value = (SeedUndiscriminatedUnions.WrapperObject)Value!; + return true; + } + value = null; + return false; + } + + public T Match( + Func onString, + Func onWrapperObject + ) + { + return Type switch + { + "string" => onString(AsString()), + "wrapperObject" => onWrapperObject(AsWrapperObject()), + _ => throw new SeedUndiscriminatedUnionsException($"Unknown union type: {Type}"), + }; + } + + public void Visit( + Action onString, + Action onWrapperObject + ) + { + switch (Type) + { + case "string": + onString(AsString()); + break; + case "wrapperObject": + onWrapperObject(AsWrapperObject()); + break; + default: + throw new SeedUndiscriminatedUnionsException($"Unknown union type: {Type}"); + } + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Type.GetHashCode(); + if (Value != null) + { + hashCode = (hashCode * 397) ^ Value.GetHashCode(); + } + return hashCode; + } + } + + public override bool Equals(object? obj) + { + if (obj is null) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj is not OuterNestedUnion other) + return false; + + // Compare type discriminators + if (Type != other.Type) + return false; + + // Compare values using EqualityComparer for deep comparison + return System.Collections.Generic.EqualityComparer.Default.Equals( + Value, + other.Value + ); + } + + public override string ToString() => JsonUtils.Serialize(this); + + public static implicit operator OuterNestedUnion(string value) => new("string", value); + + public static implicit operator OuterNestedUnion( + SeedUndiscriminatedUnions.WrapperObject value + ) => new("wrapperObject", value); + + [Serializable] + internal sealed class JsonConverter : JsonConverter + { + public override OuterNestedUnion? Read( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + if (reader.TokenType == JsonTokenType.String) + { + var stringValue = reader.GetString()!; + + OuterNestedUnion stringResult = new("string", stringValue); + return stringResult; + } + + if (reader.TokenType == JsonTokenType.StartObject) + { + var document = JsonDocument.ParseValue(ref reader); + + var types = new (string Key, System.Type Type)[] + { + ("wrapperObject", typeof(SeedUndiscriminatedUnions.WrapperObject)), + }; + + foreach (var (key, type) in types) + { + try + { + var value = document.Deserialize(type, options); + if (value != null) + { + OuterNestedUnion result = new(key, value); + return result; + } + } + catch (JsonException) + { + // Try next type; + } + } + } + + throw new JsonException( + $"Cannot deserialize JSON token {reader.TokenType} into OuterNestedUnion" + ); + } + + public override void Write( + Utf8JsonWriter writer, + OuterNestedUnion value, + JsonSerializerOptions options + ) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + + value.Visit( + str => writer.WriteStringValue(str), + obj => JsonSerializer.Serialize(writer, obj, options) + ); + } + + public override OuterNestedUnion ReadAsPropertyName( + ref Utf8JsonReader reader, + global::System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = reader.GetString()!; + OuterNestedUnion result = new("string", stringValue); + return result; + } + + public override void WriteAsPropertyName( + Utf8JsonWriter writer, + OuterNestedUnion value, + JsonSerializerOptions options + ) + { + writer.WritePropertyName(value.Value?.ToString() ?? "null"); + } + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/WrapperObject.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/WrapperObject.cs new file mode 100644 index 000000000000..b7f179852349 --- /dev/null +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/Types/WrapperObject.cs @@ -0,0 +1,31 @@ +using global::System.Text.Json; +using global::System.Text.Json.Serialization; +using SeedUndiscriminatedUnions.Core; + +namespace SeedUndiscriminatedUnions; + +[Serializable] +public record WrapperObject : IJsonOnDeserialized +{ + [JsonExtensionData] + private readonly IDictionary _extensionData = + new Dictionary(); + + [JsonPropertyName("inner")] + public required NestedObjectUnion Inner { get; set; } + + [JsonPropertyName("label")] + public required string Label { get; set; } + + [JsonIgnore] + public ReadOnlyAdditionalProperties AdditionalProperties { get; private set; } = new(); + + void IJsonOnDeserialized.OnDeserialized() => + AdditionalProperties.CopyFromExtensionData(_extensionData); + + /// + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/UnionClient.cs b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/UnionClient.cs index e623ca1c70d8..db428f9602bd 100644 --- a/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/UnionClient.cs +++ b/seed/csharp-sdk/undiscriminated-unions/with-undiscriminated-unions/src/SeedUndiscriminatedUnions/Union/UnionClient.cs @@ -406,6 +406,138 @@ private async Task> NestedUnionsAsyncCore( } } + private async Task> NestedObjectUnionsAsyncCore( + OuterNestedUnion request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _headers = await new SeedUndiscriminatedUnions.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Post, + Path = "/nested-objects", + Body = request, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new SeedUndiscriminatedUnionsApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + throw new SeedUndiscriminatedUnionsApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody + ); + } + } + + private async Task> AliasedObjectUnionAsyncCore( + AliasedObjectUnion request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var _headers = await new SeedUndiscriminatedUnions.Core.HeadersBuilder.Builder() + .Add(_client.Options.Headers) + .Add(_client.Options.AdditionalHeaders) + .Add(options?.AdditionalHeaders) + .BuildAsync() + .ConfigureAwait(false); + var response = await _client + .SendRequestAsync( + new JsonRequest + { + Method = HttpMethod.Post, + Path = "/aliased-object", + Body = request, + Headers = _headers, + Options = options, + }, + cancellationToken + ) + .ConfigureAwait(false); + if (response.StatusCode is >= 200 and < 400) + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + try + { + var responseData = JsonUtils.Deserialize(responseBody)!; + return new WithRawResponse() + { + Data = responseData, + RawResponse = new RawResponse() + { + StatusCode = response.Raw.StatusCode, + Url = response.Raw.RequestMessage?.RequestUri ?? new Uri("about:blank"), + Headers = ResponseHeaders.FromHttpResponseMessage(response.Raw), + }, + }; + } + catch (JsonException e) + { + throw new SeedUndiscriminatedUnionsApiException( + "Failed to deserialize response", + response.StatusCode, + responseBody, + e + ); + } + } + { + var responseBody = await response + .Raw.Content.ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + throw new SeedUndiscriminatedUnionsApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody + ); + } + } + private async Task> GetWithBasePropertiesAsyncCore( UnionWithBaseProperties request, RequestOptions? options = null, @@ -636,6 +768,36 @@ public WithRawResponseTask NestedUnionsAsync( ); } + /// + /// await client.Union.NestedObjectUnionsAsync("string"); + /// + public WithRawResponseTask NestedObjectUnionsAsync( + OuterNestedUnion request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + NestedObjectUnionsAsyncCore(request, options, cancellationToken) + ); + } + + /// + /// await client.Union.AliasedObjectUnionAsync( + /// new LeafObjectA { OnlyInA = "onlyInA", SharedNumber = 1 } + /// ); + /// + public WithRawResponseTask AliasedObjectUnionAsync( + AliasedObjectUnion request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + return new WithRawResponseTask( + AliasedObjectUnionAsyncCore(request, options, cancellationToken) + ); + } + /// /// await client.Union.GetWithBasePropertiesAsync( /// new NamedMetadata diff --git a/seed/go-sdk/accept-header/.fern/metadata.json b/seed/go-sdk/accept-header/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/accept-header/.fern/metadata.json +++ b/seed/go-sdk/accept-header/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/alias/.fern/metadata.json b/seed/go-sdk/alias/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/alias/.fern/metadata.json +++ b/seed/go-sdk/alias/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/allof-inline/.fern/metadata.json b/seed/go-sdk/allof-inline/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/allof-inline/.fern/metadata.json +++ b/seed/go-sdk/allof-inline/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/allof/.fern/metadata.json b/seed/go-sdk/allof/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/allof/.fern/metadata.json +++ b/seed/go-sdk/allof/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/any-auth/.fern/metadata.json b/seed/go-sdk/any-auth/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/any-auth/.fern/metadata.json +++ b/seed/go-sdk/any-auth/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/api-wide-base-path/.fern/metadata.json b/seed/go-sdk/api-wide-base-path/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/api-wide-base-path/.fern/metadata.json +++ b/seed/go-sdk/api-wide-base-path/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/audiences/.fern/metadata.json b/seed/go-sdk/audiences/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/audiences/.fern/metadata.json +++ b/seed/go-sdk/audiences/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/basic-auth-environment-variables/.fern/metadata.json b/seed/go-sdk/basic-auth-environment-variables/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/basic-auth-environment-variables/.fern/metadata.json +++ b/seed/go-sdk/basic-auth-environment-variables/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/basic-auth-pw-omitted/wire-tests/.fern/metadata.json b/seed/go-sdk/basic-auth-pw-omitted/wire-tests/.fern/metadata.json index 87f59d207d24..0162fff7b46e 100644 --- a/seed/go-sdk/basic-auth-pw-omitted/wire-tests/.fern/metadata.json +++ b/seed/go-sdk/basic-auth-pw-omitted/wire-tests/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/basic-auth/.fern/metadata.json b/seed/go-sdk/basic-auth/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/basic-auth/.fern/metadata.json +++ b/seed/go-sdk/basic-auth/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/bearer-token-environment-variable/.fern/metadata.json b/seed/go-sdk/bearer-token-environment-variable/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/bearer-token-environment-variable/.fern/metadata.json +++ b/seed/go-sdk/bearer-token-environment-variable/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/bytes-upload/.fern/metadata.json b/seed/go-sdk/bytes-upload/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/bytes-upload/.fern/metadata.json +++ b/seed/go-sdk/bytes-upload/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/circular-references-advanced/.fern/metadata.json b/seed/go-sdk/circular-references-advanced/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/circular-references-advanced/.fern/metadata.json +++ b/seed/go-sdk/circular-references-advanced/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/circular-references-extends/.fern/metadata.json b/seed/go-sdk/circular-references-extends/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/circular-references-extends/.fern/metadata.json +++ b/seed/go-sdk/circular-references-extends/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/circular-references/.fern/metadata.json b/seed/go-sdk/circular-references/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/circular-references/.fern/metadata.json +++ b/seed/go-sdk/circular-references/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/client-side-params/.fern/metadata.json b/seed/go-sdk/client-side-params/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/client-side-params/.fern/metadata.json +++ b/seed/go-sdk/client-side-params/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/content-type/.fern/metadata.json b/seed/go-sdk/content-type/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/content-type/.fern/metadata.json +++ b/seed/go-sdk/content-type/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/cross-package-type-names/.fern/metadata.json b/seed/go-sdk/cross-package-type-names/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/cross-package-type-names/.fern/metadata.json +++ b/seed/go-sdk/cross-package-type-names/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/dollar-string-examples/.fern/metadata.json b/seed/go-sdk/dollar-string-examples/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/dollar-string-examples/.fern/metadata.json +++ b/seed/go-sdk/dollar-string-examples/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/empty-clients/.fern/metadata.json b/seed/go-sdk/empty-clients/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/empty-clients/.fern/metadata.json +++ b/seed/go-sdk/empty-clients/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/endpoint-security-auth/.fern/metadata.json b/seed/go-sdk/endpoint-security-auth/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/endpoint-security-auth/.fern/metadata.json +++ b/seed/go-sdk/endpoint-security-auth/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/enum/.fern/metadata.json b/seed/go-sdk/enum/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/enum/.fern/metadata.json +++ b/seed/go-sdk/enum/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/error-property/.fern/metadata.json b/seed/go-sdk/error-property/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/error-property/.fern/metadata.json +++ b/seed/go-sdk/error-property/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/errors/.fern/metadata.json b/seed/go-sdk/errors/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/errors/.fern/metadata.json +++ b/seed/go-sdk/errors/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/always-send-required-properties/.fern/metadata.json b/seed/go-sdk/examples/always-send-required-properties/.fern/metadata.json index df9761433cc0..0f31f50414f2 100644 --- a/seed/go-sdk/examples/always-send-required-properties/.fern/metadata.json +++ b/seed/go-sdk/examples/always-send-required-properties/.fern/metadata.json @@ -7,7 +7,6 @@ "alwaysSendRequiredProperties": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/client-name-with-custom-constructor-name/.fern/metadata.json b/seed/go-sdk/examples/client-name-with-custom-constructor-name/.fern/metadata.json index c2a1bce7d167..774218fc7182 100644 --- a/seed/go-sdk/examples/client-name-with-custom-constructor-name/.fern/metadata.json +++ b/seed/go-sdk/examples/client-name-with-custom-constructor-name/.fern/metadata.json @@ -8,7 +8,6 @@ "clientConstructorName": "New" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/client-name/.fern/metadata.json b/seed/go-sdk/examples/client-name/.fern/metadata.json index 0e62c2ef87e9..cd4affc19d75 100644 --- a/seed/go-sdk/examples/client-name/.fern/metadata.json +++ b/seed/go-sdk/examples/client-name/.fern/metadata.json @@ -7,7 +7,6 @@ "clientName": "Acme" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/export-all-requests-at-root/.fern/metadata.json b/seed/go-sdk/examples/export-all-requests-at-root/.fern/metadata.json index 362cf01732e0..d1d84ecb2ed1 100644 --- a/seed/go-sdk/examples/export-all-requests-at-root/.fern/metadata.json +++ b/seed/go-sdk/examples/export-all-requests-at-root/.fern/metadata.json @@ -7,7 +7,6 @@ "exportAllRequestsAtRoot": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/exported-client-name/.fern/metadata.json b/seed/go-sdk/examples/exported-client-name/.fern/metadata.json index 40f0740488c6..891def590a4f 100644 --- a/seed/go-sdk/examples/exported-client-name/.fern/metadata.json +++ b/seed/go-sdk/examples/exported-client-name/.fern/metadata.json @@ -7,7 +7,6 @@ "exportedClientName": "AcmeClient" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/getters-pass-by-value/.fern/metadata.json b/seed/go-sdk/examples/getters-pass-by-value/.fern/metadata.json index c7c09a5e2828..3d47f53259a2 100644 --- a/seed/go-sdk/examples/getters-pass-by-value/.fern/metadata.json +++ b/seed/go-sdk/examples/getters-pass-by-value/.fern/metadata.json @@ -7,7 +7,6 @@ "gettersPassByValue": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/no-custom-config/.fern/metadata.json b/seed/go-sdk/examples/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/examples/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/examples/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/package-path/.fern/metadata.json b/seed/go-sdk/examples/package-path/.fern/metadata.json index 2caa8228b7f1..47b3a8c8ff29 100644 --- a/seed/go-sdk/examples/package-path/.fern/metadata.json +++ b/seed/go-sdk/examples/package-path/.fern/metadata.json @@ -7,7 +7,6 @@ "packagePath": "pleaseinhere" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/readme-config/.fern/metadata.json b/seed/go-sdk/examples/readme-config/.fern/metadata.json index 3158f4af781d..bed3f8dddd36 100644 --- a/seed/go-sdk/examples/readme-config/.fern/metadata.json +++ b/seed/go-sdk/examples/readme-config/.fern/metadata.json @@ -18,7 +18,6 @@ ] }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/examples/v0/.fern/metadata.json b/seed/go-sdk/examples/v0/.fern/metadata.json index 1dc7814c35ab..103f72d27c70 100644 --- a/seed/go-sdk/examples/v0/.fern/metadata.json +++ b/seed/go-sdk/examples/v0/.fern/metadata.json @@ -11,7 +11,6 @@ "union": "v0" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/exhaustive/no-custom-config/.fern/metadata.json b/seed/go-sdk/exhaustive/no-custom-config/.fern/metadata.json index 87f59d207d24..0162fff7b46e 100644 --- a/seed/go-sdk/exhaustive/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/exhaustive/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/exhaustive/omit-empty-request-wrappers/.fern/metadata.json b/seed/go-sdk/exhaustive/omit-empty-request-wrappers/.fern/metadata.json index dd6d3c6352bb..eba55cf5da7e 100644 --- a/seed/go-sdk/exhaustive/omit-empty-request-wrappers/.fern/metadata.json +++ b/seed/go-sdk/exhaustive/omit-empty-request-wrappers/.fern/metadata.json @@ -7,7 +7,6 @@ "omitEmptyRequestWrappers": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/extends/.fern/metadata.json b/seed/go-sdk/extends/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/extends/.fern/metadata.json +++ b/seed/go-sdk/extends/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/extra-properties/.fern/metadata.json b/seed/go-sdk/extra-properties/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/extra-properties/.fern/metadata.json +++ b/seed/go-sdk/extra-properties/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/file-download/.fern/metadata.json b/seed/go-sdk/file-download/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/file-download/.fern/metadata.json +++ b/seed/go-sdk/file-download/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/file-upload-openapi/.fern/metadata.json b/seed/go-sdk/file-upload-openapi/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/file-upload-openapi/.fern/metadata.json +++ b/seed/go-sdk/file-upload-openapi/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/file-upload/no-custom-config/.fern/metadata.json b/seed/go-sdk/file-upload/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/file-upload/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/file-upload/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/file-upload/package-name/.fern/metadata.json b/seed/go-sdk/file-upload/package-name/.fern/metadata.json index 16cde5c1cd42..b989726ef04f 100644 --- a/seed/go-sdk/file-upload/package-name/.fern/metadata.json +++ b/seed/go-sdk/file-upload/package-name/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/file-upload/v0/.fern/metadata.json b/seed/go-sdk/file-upload/v0/.fern/metadata.json index 1dc7814c35ab..103f72d27c70 100644 --- a/seed/go-sdk/file-upload/v0/.fern/metadata.json +++ b/seed/go-sdk/file-upload/v0/.fern/metadata.json @@ -11,7 +11,6 @@ "union": "v0" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/folders/.fern/metadata.json b/seed/go-sdk/folders/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/folders/.fern/metadata.json +++ b/seed/go-sdk/folders/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-bytes-request/no-custom-config/.fern/metadata.json b/seed/go-sdk/go-bytes-request/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/go-bytes-request/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/go-bytes-request/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-bytes-request/use-reader-for-bytes-request/.fern/metadata.json b/seed/go-sdk/go-bytes-request/use-reader-for-bytes-request/.fern/metadata.json index 480ca9acaf9d..32bdfe3ad2be 100644 --- a/seed/go-sdk/go-bytes-request/use-reader-for-bytes-request/.fern/metadata.json +++ b/seed/go-sdk/go-bytes-request/use-reader-for-bytes-request/.fern/metadata.json @@ -7,7 +7,6 @@ "useReaderForBytesRequest": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-content-type/.fern/metadata.json b/seed/go-sdk/go-content-type/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/go-content-type/.fern/metadata.json +++ b/seed/go-sdk/go-content-type/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-deterministic-ordering/.fern/metadata.json b/seed/go-sdk/go-deterministic-ordering/.fern/metadata.json index 894ddfc474e4..b5f0075018c2 100644 --- a/seed/go-sdk/go-deterministic-ordering/.fern/metadata.json +++ b/seed/go-sdk/go-deterministic-ordering/.fern/metadata.json @@ -7,7 +7,6 @@ "exportAllRequestsAtRoot": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-nested-cross-package/.fern/metadata.json b/seed/go-sdk/go-nested-cross-package/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/go-nested-cross-package/.fern/metadata.json +++ b/seed/go-sdk/go-nested-cross-package/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-optional-literal-alias/.fern/metadata.json b/seed/go-sdk/go-optional-literal-alias/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/go-optional-literal-alias/.fern/metadata.json +++ b/seed/go-sdk/go-optional-literal-alias/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-subpackage-collision/.fern/metadata.json b/seed/go-sdk/go-subpackage-collision/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/go-subpackage-collision/.fern/metadata.json +++ b/seed/go-sdk/go-subpackage-collision/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/go-undiscriminated-union-wire-tests/.fern/metadata.json b/seed/go-sdk/go-undiscriminated-union-wire-tests/.fern/metadata.json index fcd5f4be0448..eefbac3a2aa3 100644 --- a/seed/go-sdk/go-undiscriminated-union-wire-tests/.fern/metadata.json +++ b/seed/go-sdk/go-undiscriminated-union-wire-tests/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/header-auth-environment-variable/.fern/metadata.json b/seed/go-sdk/header-auth-environment-variable/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/header-auth-environment-variable/.fern/metadata.json +++ b/seed/go-sdk/header-auth-environment-variable/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/header-auth/.fern/metadata.json b/seed/go-sdk/header-auth/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/header-auth/.fern/metadata.json +++ b/seed/go-sdk/header-auth/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/http-head/.fern/metadata.json b/seed/go-sdk/http-head/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/http-head/.fern/metadata.json +++ b/seed/go-sdk/http-head/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/idempotency-headers/.fern/metadata.json b/seed/go-sdk/idempotency-headers/.fern/metadata.json index 280a5e51c132..5563646cca6d 100644 --- a/seed/go-sdk/idempotency-headers/.fern/metadata.json +++ b/seed/go-sdk/idempotency-headers/.fern/metadata.json @@ -11,7 +11,6 @@ "includeLegacyClientOptions": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/imdb/deep-package-path/.fern/metadata.json b/seed/go-sdk/imdb/deep-package-path/.fern/metadata.json index 350fd51ea798..427355f75acf 100644 --- a/seed/go-sdk/imdb/deep-package-path/.fern/metadata.json +++ b/seed/go-sdk/imdb/deep-package-path/.fern/metadata.json @@ -7,7 +7,6 @@ "packagePath": "all/the/way/in/here/please" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/imdb/no-custom-config/.fern/metadata.json b/seed/go-sdk/imdb/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/imdb/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/imdb/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/imdb/omit-fern-headers/.fern/metadata.json b/seed/go-sdk/imdb/omit-fern-headers/.fern/metadata.json index d6609a2a8b11..426a74635252 100644 --- a/seed/go-sdk/imdb/omit-fern-headers/.fern/metadata.json +++ b/seed/go-sdk/imdb/omit-fern-headers/.fern/metadata.json @@ -8,7 +8,6 @@ "maxRetries": 5 }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/imdb/package-path/.fern/metadata.json b/seed/go-sdk/imdb/package-path/.fern/metadata.json index 62d2f8ac843c..60a5ba92a0fd 100644 --- a/seed/go-sdk/imdb/package-path/.fern/metadata.json +++ b/seed/go-sdk/imdb/package-path/.fern/metadata.json @@ -7,7 +7,6 @@ "packagePath": "inhereplease" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/imdb/with-wiremock-tests/.fern/metadata.json b/seed/go-sdk/imdb/with-wiremock-tests/.fern/metadata.json index 14601fe7744d..7529afbf8fd6 100644 --- a/seed/go-sdk/imdb/with-wiremock-tests/.fern/metadata.json +++ b/seed/go-sdk/imdb/with-wiremock-tests/.fern/metadata.json @@ -9,7 +9,6 @@ "clientConstructorName": "NewIMDBClient" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/inferred-auth-explicit/.fern/metadata.json b/seed/go-sdk/inferred-auth-explicit/.fern/metadata.json index 87f59d207d24..0162fff7b46e 100644 --- a/seed/go-sdk/inferred-auth-explicit/.fern/metadata.json +++ b/seed/go-sdk/inferred-auth-explicit/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/inferred-auth-implicit-api-key/.fern/metadata.json b/seed/go-sdk/inferred-auth-implicit-api-key/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/inferred-auth-implicit-api-key/.fern/metadata.json +++ b/seed/go-sdk/inferred-auth-implicit-api-key/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/inferred-auth-implicit-no-expiry/.fern/metadata.json b/seed/go-sdk/inferred-auth-implicit-no-expiry/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/inferred-auth-implicit-no-expiry/.fern/metadata.json +++ b/seed/go-sdk/inferred-auth-implicit-no-expiry/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/inferred-auth-implicit-reference/.fern/metadata.json b/seed/go-sdk/inferred-auth-implicit-reference/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/inferred-auth-implicit-reference/.fern/metadata.json +++ b/seed/go-sdk/inferred-auth-implicit-reference/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/inferred-auth-implicit/.fern/metadata.json b/seed/go-sdk/inferred-auth-implicit/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/inferred-auth-implicit/.fern/metadata.json +++ b/seed/go-sdk/inferred-auth-implicit/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/license/.fern/metadata.json b/seed/go-sdk/license/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/license/.fern/metadata.json +++ b/seed/go-sdk/license/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/literal/.fern/metadata.json b/seed/go-sdk/literal/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/literal/.fern/metadata.json +++ b/seed/go-sdk/literal/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/literals-unions/no-custom-config/.fern/metadata.json b/seed/go-sdk/literals-unions/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/literals-unions/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/literals-unions/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/mixed-case/default-values/.fern/metadata.json b/seed/go-sdk/mixed-case/default-values/.fern/metadata.json index 042dc51b7417..392af1b1a5dc 100644 --- a/seed/go-sdk/mixed-case/default-values/.fern/metadata.json +++ b/seed/go-sdk/mixed-case/default-values/.fern/metadata.json @@ -7,7 +7,6 @@ "useDefaultRequestParameterValues": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/mixed-case/no-custom-config/.fern/metadata.json b/seed/go-sdk/mixed-case/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/mixed-case/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/mixed-case/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/mixed-file-directory/.fern/metadata.json b/seed/go-sdk/mixed-file-directory/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/mixed-file-directory/.fern/metadata.json +++ b/seed/go-sdk/mixed-file-directory/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/multi-line-docs/.fern/metadata.json b/seed/go-sdk/multi-line-docs/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/multi-line-docs/.fern/metadata.json +++ b/seed/go-sdk/multi-line-docs/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/multi-url-environment-no-default/.fern/metadata.json b/seed/go-sdk/multi-url-environment-no-default/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/multi-url-environment-no-default/.fern/metadata.json +++ b/seed/go-sdk/multi-url-environment-no-default/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/multi-url-environment-reference/.fern/metadata.json b/seed/go-sdk/multi-url-environment-reference/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/multi-url-environment-reference/.fern/metadata.json +++ b/seed/go-sdk/multi-url-environment-reference/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/multi-url-environment/.fern/metadata.json b/seed/go-sdk/multi-url-environment/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/multi-url-environment/.fern/metadata.json +++ b/seed/go-sdk/multi-url-environment/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/multiple-request-bodies/.fern/metadata.json b/seed/go-sdk/multiple-request-bodies/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/multiple-request-bodies/.fern/metadata.json +++ b/seed/go-sdk/multiple-request-bodies/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/no-content-response/.fern/metadata.json b/seed/go-sdk/no-content-response/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/no-content-response/.fern/metadata.json +++ b/seed/go-sdk/no-content-response/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/no-environment/.fern/metadata.json b/seed/go-sdk/no-environment/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/no-environment/.fern/metadata.json +++ b/seed/go-sdk/no-environment/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/no-retries/.fern/metadata.json b/seed/go-sdk/no-retries/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/no-retries/.fern/metadata.json +++ b/seed/go-sdk/no-retries/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/null-type/.fern/metadata.json b/seed/go-sdk/null-type/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/null-type/.fern/metadata.json +++ b/seed/go-sdk/null-type/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/nullable-allof-extends/.fern/metadata.json b/seed/go-sdk/nullable-allof-extends/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/nullable-allof-extends/.fern/metadata.json +++ b/seed/go-sdk/nullable-allof-extends/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/nullable-optional/.fern/metadata.json b/seed/go-sdk/nullable-optional/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/nullable-optional/.fern/metadata.json +++ b/seed/go-sdk/nullable-optional/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/.fern/metadata.json b/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/.fern/metadata.json +++ b/seed/go-sdk/nullable-request-body/dynamic-snippets-disabled/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/nullable/.fern/metadata.json b/seed/go-sdk/nullable/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/nullable/.fern/metadata.json +++ b/seed/go-sdk/nullable/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-custom/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-custom/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-custom/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-custom/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-default/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-default/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-default/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-default/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-environment-variables/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-environment-variables/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-environment-variables/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-environment-variables/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-mandatory-auth/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-nested-root/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-nested-root/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-nested-root/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-nested-root/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-openapi/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-openapi/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-openapi/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-openapi/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-reference/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-reference/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-reference/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-reference/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials-with-variables/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials-with-variables/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/oauth-client-credentials-with-variables/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials-with-variables/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/oauth-client-credentials/.fern/metadata.json b/seed/go-sdk/oauth-client-credentials/.fern/metadata.json index 87f59d207d24..0162fff7b46e 100644 --- a/seed/go-sdk/oauth-client-credentials/.fern/metadata.json +++ b/seed/go-sdk/oauth-client-credentials/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/object/.fern/metadata.json b/seed/go-sdk/object/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/object/.fern/metadata.json +++ b/seed/go-sdk/object/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/objects-with-imports/.fern/metadata.json b/seed/go-sdk/objects-with-imports/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/objects-with-imports/.fern/metadata.json +++ b/seed/go-sdk/objects-with-imports/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/optional/.fern/metadata.json b/seed/go-sdk/optional/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/optional/.fern/metadata.json +++ b/seed/go-sdk/optional/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/package-yml/no-custom-config/.fern/metadata.json b/seed/go-sdk/package-yml/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/package-yml/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/package-yml/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/pagination-custom/.fern/metadata.json b/seed/go-sdk/pagination-custom/.fern/metadata.json index 1cfda47f694f..8280fd05a74c 100644 --- a/seed/go-sdk/pagination-custom/.fern/metadata.json +++ b/seed/go-sdk/pagination-custom/.fern/metadata.json @@ -7,7 +7,6 @@ "customPagerName": "PayrocPager" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/path-parameters/no-custom-config/.fern/metadata.json b/seed/go-sdk/path-parameters/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/path-parameters/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/path-parameters/package-name/.fern/metadata.json b/seed/go-sdk/path-parameters/package-name/.fern/metadata.json index c239d1be4cb9..48fcac40f4b2 100644 --- a/seed/go-sdk/path-parameters/package-name/.fern/metadata.json +++ b/seed/go-sdk/path-parameters/package-name/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/path-parameters/v0/.fern/metadata.json b/seed/go-sdk/path-parameters/v0/.fern/metadata.json index 1dc7814c35ab..103f72d27c70 100644 --- a/seed/go-sdk/path-parameters/v0/.fern/metadata.json +++ b/seed/go-sdk/path-parameters/v0/.fern/metadata.json @@ -11,7 +11,6 @@ "union": "v0" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/plain-text/.fern/metadata.json b/seed/go-sdk/plain-text/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/plain-text/.fern/metadata.json +++ b/seed/go-sdk/plain-text/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/property-access/.fern/metadata.json b/seed/go-sdk/property-access/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/property-access/.fern/metadata.json +++ b/seed/go-sdk/property-access/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/public-object/.fern/metadata.json b/seed/go-sdk/public-object/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/public-object/.fern/metadata.json +++ b/seed/go-sdk/public-object/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/query-param-name-conflict/.fern/metadata.json b/seed/go-sdk/query-param-name-conflict/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/query-param-name-conflict/.fern/metadata.json +++ b/seed/go-sdk/query-param-name-conflict/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/query-parameters-openapi-as-objects/.fern/metadata.json b/seed/go-sdk/query-parameters-openapi-as-objects/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/query-parameters-openapi-as-objects/.fern/metadata.json +++ b/seed/go-sdk/query-parameters-openapi-as-objects/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/query-parameters-openapi/.fern/metadata.json b/seed/go-sdk/query-parameters-openapi/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/query-parameters-openapi/.fern/metadata.json +++ b/seed/go-sdk/query-parameters-openapi/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/query-parameters/.fern/metadata.json b/seed/go-sdk/query-parameters/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/query-parameters/.fern/metadata.json +++ b/seed/go-sdk/query-parameters/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/required-nullable/.fern/metadata.json b/seed/go-sdk/required-nullable/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/required-nullable/.fern/metadata.json +++ b/seed/go-sdk/required-nullable/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/reserved-keywords/.fern/metadata.json b/seed/go-sdk/reserved-keywords/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/reserved-keywords/.fern/metadata.json +++ b/seed/go-sdk/reserved-keywords/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/response-property/.fern/metadata.json b/seed/go-sdk/response-property/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/response-property/.fern/metadata.json +++ b/seed/go-sdk/response-property/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/schemaless-request-body-examples/.fern/metadata.json b/seed/go-sdk/schemaless-request-body-examples/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/schemaless-request-body-examples/.fern/metadata.json +++ b/seed/go-sdk/schemaless-request-body-examples/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/server-sent-event-examples/with-wire-tests/.fern/metadata.json b/seed/go-sdk/server-sent-event-examples/with-wire-tests/.fern/metadata.json index 05bc475963e9..bc116718d930 100644 --- a/seed/go-sdk/server-sent-event-examples/with-wire-tests/.fern/metadata.json +++ b/seed/go-sdk/server-sent-event-examples/with-wire-tests/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/server-sent-events-openapi/with-wire-tests/.fern/metadata.json b/seed/go-sdk/server-sent-events-openapi/with-wire-tests/.fern/metadata.json index 87f59d207d24..0162fff7b46e 100644 --- a/seed/go-sdk/server-sent-events-openapi/with-wire-tests/.fern/metadata.json +++ b/seed/go-sdk/server-sent-events-openapi/with-wire-tests/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": true }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/server-sent-events/with-wire-tests/.fern/metadata.json b/seed/go-sdk/server-sent-events/with-wire-tests/.fern/metadata.json index fc9cd91ac780..75c5f30ca21a 100644 --- a/seed/go-sdk/server-sent-events/with-wire-tests/.fern/metadata.json +++ b/seed/go-sdk/server-sent-events/with-wire-tests/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/server-url-templating/.fern/metadata.json b/seed/go-sdk/server-url-templating/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/server-url-templating/.fern/metadata.json +++ b/seed/go-sdk/server-url-templating/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/simple-api/.fern/metadata.json b/seed/go-sdk/simple-api/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/simple-api/.fern/metadata.json +++ b/seed/go-sdk/simple-api/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/simple-fhir/.fern/metadata.json b/seed/go-sdk/simple-fhir/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/simple-fhir/.fern/metadata.json +++ b/seed/go-sdk/simple-fhir/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/single-url-environment-default/.fern/metadata.json b/seed/go-sdk/single-url-environment-default/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/single-url-environment-default/.fern/metadata.json +++ b/seed/go-sdk/single-url-environment-default/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/single-url-environment-no-default/.fern/metadata.json b/seed/go-sdk/single-url-environment-no-default/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/single-url-environment-no-default/.fern/metadata.json +++ b/seed/go-sdk/single-url-environment-no-default/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/streaming/.fern/metadata.json b/seed/go-sdk/streaming/.fern/metadata.json index 08da5b0cf0f6..6fe0bd4f7b28 100644 --- a/seed/go-sdk/streaming/.fern/metadata.json +++ b/seed/go-sdk/streaming/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "v2.0.0", "ciProvider": "github", diff --git a/seed/go-sdk/undiscriminated-union-with-response-property/.fern/metadata.json b/seed/go-sdk/undiscriminated-union-with-response-property/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/undiscriminated-union-with-response-property/.fern/metadata.json +++ b/seed/go-sdk/undiscriminated-union-with-response-property/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/.fern/metadata.json b/seed/go-sdk/undiscriminated-unions/no-custom-config/.fern/metadata.json index ef85fe740b61..7b6927b31dd9 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example10/snippet.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example10/snippet.go index 663df9988ed5..7aa6ded6979a 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example10/snippet.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example10/snippet.go @@ -14,15 +14,13 @@ func do() { "https://api.fern.com", ), ) - request := &undiscriminated.PaymentRequest{ - PaymentMethod: &undiscriminated.PaymentMethodUnion{ - TokenizeCard: &undiscriminated.TokenizeCard{ - Method: "card", - CardNumber: "1234567890123456", - }, + request := &undiscriminated.AliasedObjectUnion{ + AliasedLeafA: &undiscriminated.LeafObjectA{ + OnlyInA: "onlyInA", + SharedNumber: 1, }, } - client.Union.TestCamelCaseProperties( + client.Union.AliasedObjectUnion( context.TODO(), request, ) diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example11/snippet.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example11/snippet.go index 91c1f9321850..f96db190593c 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example11/snippet.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example11/snippet.go @@ -14,15 +14,17 @@ func do() { "https://api.fern.com", ), ) - request := &undiscriminated.PaymentRequest{ - PaymentMethod: &undiscriminated.PaymentMethodUnion{ - TokenizeCard: &undiscriminated.TokenizeCard{ - Method: "method", - CardNumber: "cardNumber", + request := &undiscriminated.UnionWithBaseProperties{ + NamedMetadata: &undiscriminated.NamedMetadata{ + Name: "name", + Value: map[string]any{ + "value": map[string]any{ + "key": "value", + }, }, }, } - client.Union.TestCamelCaseProperties( + client.Union.GetWithBaseProperties( context.TODO(), request, ) diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example12/snippet.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example12/snippet.go new file mode 100644 index 000000000000..663df9988ed5 --- /dev/null +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example12/snippet.go @@ -0,0 +1,29 @@ +package example + +import ( + context "context" + + undiscriminated "github.com/fern-api/undiscriminated-go" + client "github.com/fern-api/undiscriminated-go/client" + option "github.com/fern-api/undiscriminated-go/option" +) + +func do() { + client := client.NewClient( + option.WithBaseURL( + "https://api.fern.com", + ), + ) + request := &undiscriminated.PaymentRequest{ + PaymentMethod: &undiscriminated.PaymentMethodUnion{ + TokenizeCard: &undiscriminated.TokenizeCard{ + Method: "card", + CardNumber: "1234567890123456", + }, + }, + } + client.Union.TestCamelCaseProperties( + context.TODO(), + request, + ) +} diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example13/snippet.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example13/snippet.go new file mode 100644 index 000000000000..91c1f9321850 --- /dev/null +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example13/snippet.go @@ -0,0 +1,29 @@ +package example + +import ( + context "context" + + undiscriminated "github.com/fern-api/undiscriminated-go" + client "github.com/fern-api/undiscriminated-go/client" + option "github.com/fern-api/undiscriminated-go/option" +) + +func do() { + client := client.NewClient( + option.WithBaseURL( + "https://api.fern.com", + ), + ) + request := &undiscriminated.PaymentRequest{ + PaymentMethod: &undiscriminated.PaymentMethodUnion{ + TokenizeCard: &undiscriminated.TokenizeCard{ + Method: "method", + CardNumber: "cardNumber", + }, + }, + } + client.Union.TestCamelCaseProperties( + context.TODO(), + request, + ) +} diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example9/snippet.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example9/snippet.go index f96db190593c..7d1c914966be 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example9/snippet.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/dynamic-snippets/example9/snippet.go @@ -14,17 +14,10 @@ func do() { "https://api.fern.com", ), ) - request := &undiscriminated.UnionWithBaseProperties{ - NamedMetadata: &undiscriminated.NamedMetadata{ - Name: "name", - Value: map[string]any{ - "value": map[string]any{ - "key": "value", - }, - }, - }, + request := &undiscriminated.OuterNestedUnion{ + String: "string", } - client.Union.GetWithBaseProperties( + client.Union.NestedObjectUnions( context.TODO(), request, ) diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/reference.md b/seed/go-sdk/undiscriminated-unions/no-custom-config/reference.md index aa052d14bd5f..92886021ec64 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/reference.md +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/reference.md @@ -269,6 +269,103 @@ client.Union.NestedUnions( + + + + +
client.Union.NestedObjectUnions(request) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```go +request := &undiscriminated.OuterNestedUnion{ + String: "string", + } +client.Union.NestedObjectUnions( + context.TODO(), + request, + ) +} +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `*undiscriminated.OuterNestedUnion` + +
+
+
+
+ + +
+
+
+ +
client.Union.AliasedObjectUnion(request) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```go +request := &undiscriminated.AliasedObjectUnion{ + AliasedLeafA: &undiscriminated.LeafObjectA{ + OnlyInA: "onlyInA", + SharedNumber: 1, + }, + } +client.Union.AliasedObjectUnion( + context.TODO(), + request, + ) +} +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `*undiscriminated.AliasedObjectUnion` + +
+
+
+
+ +
diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/snippet.json b/seed/go-sdk/undiscriminated-unions/no-custom-config/snippet.json index ba3de9f5871e..1f1f6e2f5722 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/snippet.json +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/snippet.json @@ -11,6 +11,17 @@ "client": "import (\n\tcontext \"context\"\n\tundiscriminatedgo \"github.com/fern-api/undiscriminated-go\"\n\tundiscriminatedgoclient \"github.com/fern-api/undiscriminated-go/client\"\n)\n\nclient := undiscriminatedgoclient.NewClient()\nresponse, err := client.Union.Get(\n\tcontext.TODO(),\n\t\u0026undiscriminatedgo.MyUnion{\n\t\tString: \"string\",\n\t},\n)\n" } }, + { + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "go", + "client": "import (\n\tcontext \"context\"\n\tundiscriminatedgo \"github.com/fern-api/undiscriminated-go\"\n\tundiscriminatedgoclient \"github.com/fern-api/undiscriminated-go/client\"\n)\n\nclient := undiscriminatedgoclient.NewClient()\nresponse, err := client.Union.AliasedObjectUnion(\n\tcontext.TODO(),\n\t\u0026undiscriminatedgo.AliasedObjectUnion{\n\t\tAliasedLeafA: \u0026undiscriminatedgo.LeafObjectA{\n\t\t\tOnlyInA: \"onlyInA\",\n\t\t\tSharedNumber: 1,\n\t\t},\n\t},\n)\n" + } + }, { "id": { "path": "/call", @@ -66,6 +77,17 @@ "client": "import (\n\tcontext \"context\"\n\tundiscriminatedgo \"github.com/fern-api/undiscriminated-go\"\n\tundiscriminatedgoclient \"github.com/fern-api/undiscriminated-go/client\"\n)\n\nclient := undiscriminatedgoclient.NewClient()\nresponse, err := client.Union.UpdateMetadata(\n\tcontext.TODO(),\n\t\u0026undiscriminatedgo.MetadataUnion{\n\t\tOptionalMetadata: map[string]any{\n\t\t\t\"string\": map[string]interface{}{\n\t\t\t\t\"key\": \"value\",\n\t\t\t},\n\t\t},\n\t},\n)\n" } }, + { + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "go", + "client": "import (\n\tcontext \"context\"\n\tundiscriminatedgo \"github.com/fern-api/undiscriminated-go\"\n\tundiscriminatedgoclient \"github.com/fern-api/undiscriminated-go/client\"\n)\n\nclient := undiscriminatedgoclient.NewClient()\nresponse, err := client.Union.NestedObjectUnions(\n\tcontext.TODO(),\n\t\u0026undiscriminatedgo.OuterNestedUnion{\n\t\tString: \"string\",\n\t},\n)\n" + } + }, { "id": { "path": "/nested", diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/union.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/union.go index 6ea8ce4fa349..6120f990b63d 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/union.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/union.go @@ -55,6 +55,79 @@ func (p *PaymentRequest) MarshalJSON() ([]byte, error) { return json.Marshal(explicitMarshaler) } +type AliasToLeafB = *LeafObjectB + +// An alias around LeafObjectA. +type AliasedLeafA = *LeafObjectA + +// An alias around an alias around LeafObjectB, to exercise the alias-walk loop. +type AliasedLeafB = AliasToLeafB + +// Undiscriminated union whose members are named aliases of object types +// (including an alias-of-alias). Required keys are disjoint, so a correct +// deserializer must emit containsKey() guards for each alias variant. +type AliasedObjectUnion struct { + AliasedLeafA AliasedLeafA + AliasedLeafB AliasedLeafB + + typ string +} + +func (a *AliasedObjectUnion) GetAliasedLeafA() AliasedLeafA { + if a == nil { + return nil + } + return a.AliasedLeafA +} + +func (a *AliasedObjectUnion) GetAliasedLeafB() AliasedLeafB { + if a == nil { + return nil + } + return a.AliasedLeafB +} + +func (a *AliasedObjectUnion) UnmarshalJSON(data []byte) error { + var valueAliasedLeafA AliasedLeafA + if err := json.Unmarshal(data, &valueAliasedLeafA); err == nil { + a.typ = "AliasedLeafA" + a.AliasedLeafA = valueAliasedLeafA + return nil + } + var valueAliasedLeafB AliasedLeafB + if err := json.Unmarshal(data, &valueAliasedLeafB); err == nil { + a.typ = "AliasedLeafB" + a.AliasedLeafB = valueAliasedLeafB + return nil + } + return fmt.Errorf("%s cannot be deserialized as a %T", data, a) +} + +func (a AliasedObjectUnion) MarshalJSON() ([]byte, error) { + if a.typ == "AliasedLeafA" || a.AliasedLeafA != nil { + return json.Marshal(a.AliasedLeafA) + } + if a.typ == "AliasedLeafB" || a.AliasedLeafB != nil { + return json.Marshal(a.AliasedLeafB) + } + return nil, fmt.Errorf("type %T does not include a non-empty union type", a) +} + +type AliasedObjectUnionVisitor interface { + VisitAliasedLeafA(AliasedLeafA) error + VisitAliasedLeafB(AliasedLeafB) error +} + +func (a *AliasedObjectUnion) Accept(visitor AliasedObjectUnionVisitor) error { + if a.typ == "AliasedLeafA" || a.AliasedLeafA != nil { + return visitor.VisitAliasedLeafA(a.AliasedLeafA) + } + if a.typ == "AliasedLeafB" || a.AliasedLeafB != nil { + return visitor.VisitAliasedLeafB(a.AliasedLeafB) + } + return fmt.Errorf("type %T does not include a non-empty union type", a) +} + var ( convertTokenFieldMethod = big.NewInt(1 << 0) convertTokenFieldTokenID = big.NewInt(1 << 1) @@ -239,6 +312,374 @@ func (k KeyType) Ptr() *KeyType { return &k } +var ( + leafObjectAFieldOnlyInA = big.NewInt(1 << 0) + leafObjectAFieldSharedNumber = big.NewInt(1 << 1) +) + +type LeafObjectA struct { + OnlyInA string `json:"onlyInA" url:"onlyInA"` + SharedNumber int `json:"sharedNumber" url:"sharedNumber"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafObjectA) GetOnlyInA() string { + if l == nil { + return "" + } + return l.OnlyInA +} + +func (l *LeafObjectA) GetSharedNumber() int { + if l == nil { + return 0 + } + return l.SharedNumber +} + +func (l *LeafObjectA) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafObjectA) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetOnlyInA sets the OnlyInA field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafObjectA) SetOnlyInA(onlyInA string) { + l.OnlyInA = onlyInA + l.require(leafObjectAFieldOnlyInA) +} + +// SetSharedNumber sets the SharedNumber field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafObjectA) SetSharedNumber(sharedNumber int) { + l.SharedNumber = sharedNumber + l.require(leafObjectAFieldSharedNumber) +} + +func (l *LeafObjectA) UnmarshalJSON(data []byte) error { + type unmarshaler LeafObjectA + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafObjectA(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafObjectA) MarshalJSON() ([]byte, error) { + type embed LeafObjectA + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafObjectA) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + +var ( + leafObjectBFieldOnlyInB = big.NewInt(1 << 0) +) + +type LeafObjectB struct { + OnlyInB string `json:"onlyInB" url:"onlyInB"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafObjectB) GetOnlyInB() string { + if l == nil { + return "" + } + return l.OnlyInB +} + +func (l *LeafObjectB) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafObjectB) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetOnlyInB sets the OnlyInB field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafObjectB) SetOnlyInB(onlyInB string) { + l.OnlyInB = onlyInB + l.require(leafObjectBFieldOnlyInB) +} + +func (l *LeafObjectB) UnmarshalJSON(data []byte) error { + type unmarshaler LeafObjectB + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafObjectB(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafObjectB) MarshalJSON() ([]byte, error) { + type embed LeafObjectB + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafObjectB) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + +var ( + leafTypeAFieldAlpha = big.NewInt(1 << 0) + leafTypeAFieldBeta = big.NewInt(1 << 1) +) + +type LeafTypeA struct { + Alpha string `json:"alpha" url:"alpha"` + Beta int `json:"beta" url:"beta"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafTypeA) GetAlpha() string { + if l == nil { + return "" + } + return l.Alpha +} + +func (l *LeafTypeA) GetBeta() int { + if l == nil { + return 0 + } + return l.Beta +} + +func (l *LeafTypeA) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafTypeA) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetAlpha sets the Alpha field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafTypeA) SetAlpha(alpha string) { + l.Alpha = alpha + l.require(leafTypeAFieldAlpha) +} + +// SetBeta sets the Beta field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafTypeA) SetBeta(beta int) { + l.Beta = beta + l.require(leafTypeAFieldBeta) +} + +func (l *LeafTypeA) UnmarshalJSON(data []byte) error { + type unmarshaler LeafTypeA + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafTypeA(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafTypeA) MarshalJSON() ([]byte, error) { + type embed LeafTypeA + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafTypeA) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + +var ( + leafTypeBFieldGamma = big.NewInt(1 << 0) +) + +type LeafTypeB struct { + Gamma string `json:"gamma" url:"gamma"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafTypeB) GetGamma() string { + if l == nil { + return "" + } + return l.Gamma +} + +func (l *LeafTypeB) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafTypeB) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetGamma sets the Gamma field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafTypeB) SetGamma(gamma string) { + l.Gamma = gamma + l.require(leafTypeBFieldGamma) +} + +func (l *LeafTypeB) UnmarshalJSON(data []byte) error { + type unmarshaler LeafTypeB + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafTypeB(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafTypeB) MarshalJSON() ([]byte, error) { + type embed LeafTypeB + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafTypeB) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + // Undiscriminated unions can act as a map key // as long as all of their values are valid keys // (i.e. do they have a valid string representation). @@ -556,6 +997,70 @@ func (n *NamedMetadata) String() string { return fmt.Sprintf("%#v", n) } +// Inner union with two object variants that have disjoint required keys. +// Tests that required-key guards work correctly inside nested union contexts. +type NestedObjectUnion struct { + LeafTypeA *LeafTypeA + LeafTypeB *LeafTypeB + + typ string +} + +func (n *NestedObjectUnion) GetLeafTypeA() *LeafTypeA { + if n == nil { + return nil + } + return n.LeafTypeA +} + +func (n *NestedObjectUnion) GetLeafTypeB() *LeafTypeB { + if n == nil { + return nil + } + return n.LeafTypeB +} + +func (n *NestedObjectUnion) UnmarshalJSON(data []byte) error { + valueLeafTypeA := new(LeafTypeA) + if err := json.Unmarshal(data, &valueLeafTypeA); err == nil { + n.typ = "LeafTypeA" + n.LeafTypeA = valueLeafTypeA + return nil + } + valueLeafTypeB := new(LeafTypeB) + if err := json.Unmarshal(data, &valueLeafTypeB); err == nil { + n.typ = "LeafTypeB" + n.LeafTypeB = valueLeafTypeB + return nil + } + return fmt.Errorf("%s cannot be deserialized as a %T", data, n) +} + +func (n NestedObjectUnion) MarshalJSON() ([]byte, error) { + if n.typ == "LeafTypeA" || n.LeafTypeA != nil { + return json.Marshal(n.LeafTypeA) + } + if n.typ == "LeafTypeB" || n.LeafTypeB != nil { + return json.Marshal(n.LeafTypeB) + } + return nil, fmt.Errorf("type %T does not include a non-empty union type", n) +} + +type NestedObjectUnionVisitor interface { + VisitLeafTypeA(*LeafTypeA) error + VisitLeafTypeB(*LeafTypeB) error +} + +func (n *NestedObjectUnion) Accept(visitor NestedObjectUnionVisitor) error { + if n.typ == "LeafTypeA" || n.LeafTypeA != nil { + return visitor.VisitLeafTypeA(n.LeafTypeA) + } + if n.typ == "LeafTypeB" || n.LeafTypeB != nil { + return visitor.VisitLeafTypeB(n.LeafTypeB) + } + return fmt.Errorf("type %T does not include a non-empty union type", n) +} + // Nested layer 1. type NestedUnionL1 struct { Integer int @@ -831,6 +1336,70 @@ func (n *NestedUnionRoot) Accept(visitor NestedUnionRootVisitor) error { type OptionalMetadata = map[string]any +// Outer union where one variant is an object containing a nested union field. +// Tests that the deserializer correctly handles transitive union deserialization. +type OuterNestedUnion struct { + String string + WrapperObject *WrapperObject + + typ string +} + +func (o *OuterNestedUnion) GetString() string { + if o == nil { + return "" + } + return o.String +} + +func (o *OuterNestedUnion) GetWrapperObject() *WrapperObject { + if o == nil { + return nil + } + return o.WrapperObject +} + +func (o *OuterNestedUnion) UnmarshalJSON(data []byte) error { + var valueString string + if err := json.Unmarshal(data, &valueString); err == nil { + o.typ = "String" + o.String = valueString + return nil + } + valueWrapperObject := new(WrapperObject) + if err := json.Unmarshal(data, &valueWrapperObject); err == nil { + o.typ = "WrapperObject" + o.WrapperObject = valueWrapperObject + return nil + } + return fmt.Errorf("%s cannot be deserialized as a %T", data, o) +} + +func (o OuterNestedUnion) MarshalJSON() ([]byte, error) { + if o.typ == "String" || o.String != "" { + return json.Marshal(o.String) + } + if o.typ == "WrapperObject" || o.WrapperObject != nil { + return json.Marshal(o.WrapperObject) + } + return nil, fmt.Errorf("type %T does not include a non-empty union type", o) +} + +type OuterNestedUnionVisitor interface { + VisitString(string) error + VisitWrapperObject(*WrapperObject) error +} + +func (o *OuterNestedUnion) Accept(visitor OuterNestedUnionVisitor) error { + if o.typ == "String" || o.String != "" { + return visitor.VisitString(o.String) + } + if o.typ == "WrapperObject" || o.WrapperObject != nil { + return visitor.VisitWrapperObject(o.WrapperObject) + } + return fmt.Errorf("type %T does not include a non-empty union type", o) +} + // Tests that nested properties with camelCase wire names are properly // converted from snake_case Ruby keys when passed as Hash values. type PaymentMethodUnion struct { @@ -1636,3 +2205,103 @@ func (u *UnionWithTypeAliases) Accept(visitor UnionWithTypeAliasesVisitor) error // A user identifier (alias for string) type UserID = string + +var ( + wrapperObjectFieldInner = big.NewInt(1 << 0) + wrapperObjectFieldLabel = big.NewInt(1 << 1) +) + +type WrapperObject struct { + Inner *NestedObjectUnion `json:"inner" url:"inner"` + Label string `json:"label" url:"label"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (w *WrapperObject) GetInner() *NestedObjectUnion { + if w == nil { + return nil + } + return w.Inner +} + +func (w *WrapperObject) GetLabel() string { + if w == nil { + return "" + } + return w.Label +} + +func (w *WrapperObject) GetExtraProperties() map[string]interface{} { + if w == nil { + return nil + } + return w.extraProperties +} + +func (w *WrapperObject) require(field *big.Int) { + if w.explicitFields == nil { + w.explicitFields = big.NewInt(0) + } + w.explicitFields.Or(w.explicitFields, field) +} + +// SetInner sets the Inner field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (w *WrapperObject) SetInner(inner *NestedObjectUnion) { + w.Inner = inner + w.require(wrapperObjectFieldInner) +} + +// SetLabel sets the Label field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (w *WrapperObject) SetLabel(label string) { + w.Label = label + w.require(wrapperObjectFieldLabel) +} + +func (w *WrapperObject) UnmarshalJSON(data []byte) error { + type unmarshaler WrapperObject + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *w = WrapperObject(value) + extraProperties, err := internal.ExtractExtraProperties(data, *w) + if err != nil { + return err + } + w.extraProperties = extraProperties + w.rawJSON = json.RawMessage(data) + return nil +} + +func (w *WrapperObject) MarshalJSON() ([]byte, error) { + type embed WrapperObject + var marshaler = struct { + embed + }{ + embed: embed(*w), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, w.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (w *WrapperObject) String() string { + if w == nil { + return "" + } + if len(w.rawJSON) > 0 { + if value, err := internal.StringifyJSON(w.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(w); err == nil { + return value + } + return fmt.Sprintf("%#v", w) +} diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/union/client.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/union/client.go index 03be471cfeaf..306ddc131f67 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/union/client.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/union/client.go @@ -127,6 +127,38 @@ func (c *Client) NestedUnions( return response.Body, nil } +func (c *Client) NestedObjectUnions( + ctx context.Context, + request *undiscriminated.OuterNestedUnion, + opts ...option.RequestOption, +) (string, error) { + response, err := c.WithRawResponse.NestedObjectUnions( + ctx, + request, + opts..., + ) + if err != nil { + return "", err + } + return response.Body, nil +} + +func (c *Client) AliasedObjectUnion( + ctx context.Context, + request *undiscriminated.AliasedObjectUnion, + opts ...option.RequestOption, +) (string, error) { + response, err := c.WithRawResponse.AliasedObjectUnion( + ctx, + request, + opts..., + ) + if err != nil { + return "", err + } + return response.Body, nil +} + func (c *Client) GetWithBaseProperties( ctx context.Context, request *undiscriminated.UnionWithBaseProperties, diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/union/raw_client.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/union/raw_client.go index d74158632c36..32d341df953b 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/union/raw_client.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/union/raw_client.go @@ -275,6 +275,88 @@ func (r *RawClient) NestedUnions( }, nil } +func (r *RawClient) NestedObjectUnions( + ctx context.Context, + request *undiscriminated.OuterNestedUnion, + opts ...option.RequestOption, +) (*core.Response[string], error) { + options := core.NewRequestOptions(opts...) + baseURL := internal.ResolveBaseURL( + options.BaseURL, + r.baseURL, + "", + ) + endpointURL := baseURL + "/nested-objects" + headers := internal.MergeHeaders( + r.options.ToHeader(), + options.ToHeader(), + ) + var response string + raw, err := r.caller.Call( + ctx, + &internal.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + Headers: headers, + MaxAttempts: options.MaxAttempts, + BodyProperties: options.BodyProperties, + QueryParameters: options.QueryParameters, + Client: options.HTTPClient, + Request: request, + Response: &response, + }, + ) + if err != nil { + return nil, err + } + return &core.Response[string]{ + StatusCode: raw.StatusCode, + Header: raw.Header, + Body: response, + }, nil +} + +func (r *RawClient) AliasedObjectUnion( + ctx context.Context, + request *undiscriminated.AliasedObjectUnion, + opts ...option.RequestOption, +) (*core.Response[string], error) { + options := core.NewRequestOptions(opts...) + baseURL := internal.ResolveBaseURL( + options.BaseURL, + r.baseURL, + "", + ) + endpointURL := baseURL + "/aliased-object" + headers := internal.MergeHeaders( + r.options.ToHeader(), + options.ToHeader(), + ) + var response string + raw, err := r.caller.Call( + ctx, + &internal.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + Headers: headers, + MaxAttempts: options.MaxAttempts, + BodyProperties: options.BodyProperties, + QueryParameters: options.QueryParameters, + Client: options.HTTPClient, + Request: request, + Response: &response, + }, + ) + if err != nil { + return nil, err + } + return &core.Response[string]{ + StatusCode: raw.StatusCode, + Header: raw.Header, + Body: response, + }, nil +} + func (r *RawClient) GetWithBaseProperties( ctx context.Context, request *undiscriminated.UnionWithBaseProperties, diff --git a/seed/go-sdk/undiscriminated-unions/no-custom-config/union_test.go b/seed/go-sdk/undiscriminated-unions/no-custom-config/union_test.go index 62445591766c..ef5de53afbd5 100644 --- a/seed/go-sdk/undiscriminated-unions/no-custom-config/union_test.go +++ b/seed/go-sdk/undiscriminated-unions/no-custom-config/union_test.go @@ -54,6 +54,55 @@ func TestSettersMarkExplicitPaymentRequest(t *testing.T) { } +func TestGettersAliasedObjectUnion(t *testing.T) { + t.Run("GetAliasedLeafA", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &AliasedObjectUnion{} + var expected AliasedLeafA + obj.AliasedLeafA = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetAliasedLeafA(), "getter should return the property value") + }) + + t.Run("GetAliasedLeafA_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *AliasedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetAliasedLeafA() // Should return zero value + }) + + t.Run("GetAliasedLeafB", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &AliasedObjectUnion{} + var expected AliasedLeafB + obj.AliasedLeafB = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetAliasedLeafB(), "getter should return the property value") + }) + + t.Run("GetAliasedLeafB_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *AliasedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetAliasedLeafB() // Should return zero value + }) + +} + func TestSettersConvertToken(t *testing.T) { t.Run("SetMethod", func(t *testing.T) { obj := &ConvertToken{} @@ -213,6 +262,414 @@ func TestGettersKey(t *testing.T) { } +func TestSettersLeafObjectA(t *testing.T) { + t.Run("SetOnlyInA", func(t *testing.T) { + obj := &LeafObjectA{} + var fernTestValueOnlyInA string + obj.SetOnlyInA(fernTestValueOnlyInA) + assert.Equal(t, fernTestValueOnlyInA, obj.OnlyInA) + assert.NotNil(t, obj.explicitFields) + }) + + t.Run("SetSharedNumber", func(t *testing.T) { + obj := &LeafObjectA{} + var fernTestValueSharedNumber int + obj.SetSharedNumber(fernTestValueSharedNumber) + assert.Equal(t, fernTestValueSharedNumber, obj.SharedNumber) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafObjectA(t *testing.T) { + t.Run("GetOnlyInA", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var expected string + obj.OnlyInA = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetOnlyInA(), "getter should return the property value") + }) + + t.Run("GetOnlyInA_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetOnlyInA() // Should return zero value + }) + + t.Run("GetSharedNumber", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var expected int + obj.SharedNumber = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetSharedNumber(), "getter should return the property value") + }) + + t.Run("GetSharedNumber_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetSharedNumber() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafObjectA(t *testing.T) { + t.Run("SetOnlyInA_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var fernTestValueOnlyInA string + + // Act + obj.SetOnlyInA(fernTestValueOnlyInA) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + + t.Run("SetSharedNumber_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var fernTestValueSharedNumber int + + // Act + obj.SetSharedNumber(fernTestValueSharedNumber) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestSettersLeafObjectB(t *testing.T) { + t.Run("SetOnlyInB", func(t *testing.T) { + obj := &LeafObjectB{} + var fernTestValueOnlyInB string + obj.SetOnlyInB(fernTestValueOnlyInB) + assert.Equal(t, fernTestValueOnlyInB, obj.OnlyInB) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafObjectB(t *testing.T) { + t.Run("GetOnlyInB", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectB{} + var expected string + obj.OnlyInB = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetOnlyInB(), "getter should return the property value") + }) + + t.Run("GetOnlyInB_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectB + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetOnlyInB() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafObjectB(t *testing.T) { + t.Run("SetOnlyInB_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectB{} + var fernTestValueOnlyInB string + + // Act + obj.SetOnlyInB(fernTestValueOnlyInB) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestSettersLeafTypeA(t *testing.T) { + t.Run("SetAlpha", func(t *testing.T) { + obj := &LeafTypeA{} + var fernTestValueAlpha string + obj.SetAlpha(fernTestValueAlpha) + assert.Equal(t, fernTestValueAlpha, obj.Alpha) + assert.NotNil(t, obj.explicitFields) + }) + + t.Run("SetBeta", func(t *testing.T) { + obj := &LeafTypeA{} + var fernTestValueBeta int + obj.SetBeta(fernTestValueBeta) + assert.Equal(t, fernTestValueBeta, obj.Beta) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafTypeA(t *testing.T) { + t.Run("GetAlpha", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var expected string + obj.Alpha = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetAlpha(), "getter should return the property value") + }) + + t.Run("GetAlpha_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetAlpha() // Should return zero value + }) + + t.Run("GetBeta", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var expected int + obj.Beta = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetBeta(), "getter should return the property value") + }) + + t.Run("GetBeta_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetBeta() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafTypeA(t *testing.T) { + t.Run("SetAlpha_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var fernTestValueAlpha string + + // Act + obj.SetAlpha(fernTestValueAlpha) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + + t.Run("SetBeta_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var fernTestValueBeta int + + // Act + obj.SetBeta(fernTestValueBeta) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestSettersLeafTypeB(t *testing.T) { + t.Run("SetGamma", func(t *testing.T) { + obj := &LeafTypeB{} + var fernTestValueGamma string + obj.SetGamma(fernTestValueGamma) + assert.Equal(t, fernTestValueGamma, obj.Gamma) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafTypeB(t *testing.T) { + t.Run("GetGamma", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeB{} + var expected string + obj.Gamma = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetGamma(), "getter should return the property value") + }) + + t.Run("GetGamma_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeB + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetGamma() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafTypeB(t *testing.T) { + t.Run("SetGamma_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeB{} + var fernTestValueGamma string + + // Act + obj.SetGamma(fernTestValueGamma) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + func TestGettersMetadataUnion(t *testing.T) { t.Run("GetOptionalMetadata", func(t *testing.T) { t.Parallel() @@ -596,6 +1053,75 @@ func TestSettersMarkExplicitNamedMetadata(t *testing.T) { } +func TestGettersNestedObjectUnion(t *testing.T) { + t.Run("GetLeafTypeA", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + var expected *LeafTypeA + obj.LeafTypeA = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetLeafTypeA(), "getter should return the property value") + }) + + t.Run("GetLeafTypeA_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + obj.LeafTypeA = nil + + // Act & Assert + assert.Nil(t, obj.GetLeafTypeA(), "getter should return nil when property is nil") + }) + + t.Run("GetLeafTypeA_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetLeafTypeA() // Should return zero value + }) + + t.Run("GetLeafTypeB", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + var expected *LeafTypeB + obj.LeafTypeB = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetLeafTypeB(), "getter should return the property value") + }) + + t.Run("GetLeafTypeB_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + obj.LeafTypeB = nil + + // Act & Assert + assert.Nil(t, obj.GetLeafTypeB(), "getter should return nil when property is nil") + }) + + t.Run("GetLeafTypeB_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetLeafTypeB() // Should return zero value + }) + +} + func TestGettersNestedUnionL1(t *testing.T) { t.Run("GetInteger", func(t *testing.T) { t.Parallel() @@ -848,59 +1374,118 @@ func TestGettersNestedUnionRoot(t *testing.T) { assert.Equal(t, expected, obj.GetStringList(), "getter should return the property value") }) - t.Run("GetStringList_NilValue", func(t *testing.T) { + t.Run("GetStringList_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedUnionRoot{} + obj.StringList = nil + + // Act & Assert + assert.Nil(t, obj.GetStringList(), "getter should return nil when property is nil") + }) + + t.Run("GetStringList_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedUnionRoot + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetStringList() // Should return zero value + }) + + t.Run("GetNestedUnionL1", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedUnionRoot{} + var expected *NestedUnionL1 + obj.NestedUnionL1 = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetNestedUnionL1(), "getter should return the property value") + }) + + t.Run("GetNestedUnionL1_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedUnionRoot{} + obj.NestedUnionL1 = nil + + // Act & Assert + assert.Nil(t, obj.GetNestedUnionL1(), "getter should return nil when property is nil") + }) + + t.Run("GetNestedUnionL1_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedUnionRoot + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetNestedUnionL1() // Should return zero value + }) + +} + +func TestGettersOuterNestedUnion(t *testing.T) { + t.Run("GetString", func(t *testing.T) { t.Parallel() // Arrange - obj := &NestedUnionRoot{} - obj.StringList = nil + obj := &OuterNestedUnion{} + var expected string + obj.String = expected // Act & Assert - assert.Nil(t, obj.GetStringList(), "getter should return nil when property is nil") + assert.Equal(t, expected, obj.GetString(), "getter should return the property value") }) - t.Run("GetStringList_NilReceiver", func(t *testing.T) { + t.Run("GetString_NilReceiver", func(t *testing.T) { t.Parallel() - var obj *NestedUnionRoot + var obj *OuterNestedUnion // Should not panic - getters should handle nil receiver gracefully defer func() { if r := recover(); r != nil { t.Errorf("Getter panicked on nil receiver: %v", r) } }() - _ = obj.GetStringList() // Should return zero value + _ = obj.GetString() // Should return zero value }) - t.Run("GetNestedUnionL1", func(t *testing.T) { + t.Run("GetWrapperObject", func(t *testing.T) { t.Parallel() // Arrange - obj := &NestedUnionRoot{} - var expected *NestedUnionL1 - obj.NestedUnionL1 = expected + obj := &OuterNestedUnion{} + var expected *WrapperObject + obj.WrapperObject = expected // Act & Assert - assert.Equal(t, expected, obj.GetNestedUnionL1(), "getter should return the property value") + assert.Equal(t, expected, obj.GetWrapperObject(), "getter should return the property value") }) - t.Run("GetNestedUnionL1_NilValue", func(t *testing.T) { + t.Run("GetWrapperObject_NilValue", func(t *testing.T) { t.Parallel() // Arrange - obj := &NestedUnionRoot{} - obj.NestedUnionL1 = nil + obj := &OuterNestedUnion{} + obj.WrapperObject = nil // Act & Assert - assert.Nil(t, obj.GetNestedUnionL1(), "getter should return nil when property is nil") + assert.Nil(t, obj.GetWrapperObject(), "getter should return nil when property is nil") }) - t.Run("GetNestedUnionL1_NilReceiver", func(t *testing.T) { + t.Run("GetWrapperObject_NilReceiver", func(t *testing.T) { t.Parallel() - var obj *NestedUnionRoot + var obj *OuterNestedUnion // Should not panic - getters should handle nil receiver gracefully defer func() { if r := recover(); r != nil { t.Errorf("Getter panicked on nil receiver: %v", r) } }() - _ = obj.GetNestedUnionL1() // Should return zero value + _ = obj.GetWrapperObject() // Should return zero value }) } @@ -1591,59 +2176,334 @@ func TestGettersUnionWithTypeAliases(t *testing.T) { _ = obj.GetString() // Should return zero value }) - t.Run("GetUserID", func(t *testing.T) { + t.Run("GetUserID", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &UnionWithTypeAliases{} + var expected UserID + obj.UserID = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetUserID(), "getter should return the property value") + }) + + t.Run("GetUserID_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *UnionWithTypeAliases + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetUserID() // Should return zero value + }) + + t.Run("GetName", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &UnionWithTypeAliases{} + var expected Name + obj.Name = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetName(), "getter should return the property value") + }) + + t.Run("GetName_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *UnionWithTypeAliases + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetName() // Should return zero value + }) + +} + +func TestSettersWrapperObject(t *testing.T) { + t.Run("SetInner", func(t *testing.T) { + obj := &WrapperObject{} + var fernTestValueInner *NestedObjectUnion + obj.SetInner(fernTestValueInner) + assert.Equal(t, fernTestValueInner, obj.Inner) + assert.NotNil(t, obj.explicitFields) + }) + + t.Run("SetLabel", func(t *testing.T) { + obj := &WrapperObject{} + var fernTestValueLabel string + obj.SetLabel(fernTestValueLabel) + assert.Equal(t, fernTestValueLabel, obj.Label) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersWrapperObject(t *testing.T) { + t.Run("GetInner", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var expected *NestedObjectUnion + obj.Inner = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetInner(), "getter should return the property value") + }) + + t.Run("GetInner_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + obj.Inner = nil + + // Act & Assert + assert.Nil(t, obj.GetInner(), "getter should return nil when property is nil") + }) + + t.Run("GetInner_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetInner() // Should return zero value + }) + + t.Run("GetLabel", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var expected string + obj.Label = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetLabel(), "getter should return the property value") + }) + + t.Run("GetLabel_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetLabel() // Should return zero value + }) + +} + +func TestSettersMarkExplicitWrapperObject(t *testing.T) { + t.Run("SetInner_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var fernTestValueInner *NestedObjectUnion + + // Act + obj.SetInner(fernTestValueInner) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + + t.Run("SetLabel_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var fernTestValueLabel string + + // Act + obj.SetLabel(fernTestValueLabel) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestJSONMarshalingConvertToken(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &ConvertToken{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled ConvertToken + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { + t.Parallel() + var obj ConvertToken + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") + }) + + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj ConvertToken + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) +} + +func TestJSONMarshalingLeafObjectA(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled LeafObjectA + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { + t.Parallel() + var obj LeafObjectA + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") + }) + + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj LeafObjectA + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) +} + +func TestJSONMarshalingLeafObjectB(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectB{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled LeafObjectB + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { t.Parallel() - // Arrange - obj := &UnionWithTypeAliases{} - var expected UserID - obj.UserID = expected - - // Act & Assert - assert.Equal(t, expected, obj.GetUserID(), "getter should return the property value") + var obj LeafObjectB + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") }) - t.Run("GetUserID_NilReceiver", func(t *testing.T) { + t.Run("UnmarshalEmptyObject", func(t *testing.T) { t.Parallel() - var obj *UnionWithTypeAliases - // Should not panic - getters should handle nil receiver gracefully - defer func() { - if r := recover(); r != nil { - t.Errorf("Getter panicked on nil receiver: %v", r) - } - }() - _ = obj.GetUserID() // Should return zero value + var obj LeafObjectB + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") }) +} - t.Run("GetName", func(t *testing.T) { +func TestJSONMarshalingLeafTypeA(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { t.Parallel() // Arrange - obj := &UnionWithTypeAliases{} - var expected Name - obj.Name = expected + obj := &LeafTypeA{} - // Act & Assert - assert.Equal(t, expected, obj.GetName(), "getter should return the property value") + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled LeafTypeA + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") }) - t.Run("GetName_NilReceiver", func(t *testing.T) { + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { t.Parallel() - var obj *UnionWithTypeAliases - // Should not panic - getters should handle nil receiver gracefully - defer func() { - if r := recover(); r != nil { - t.Errorf("Getter panicked on nil receiver: %v", r) - } - }() - _ = obj.GetName() // Should return zero value + var obj LeafTypeA + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") }) + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj LeafTypeA + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) } -func TestJSONMarshalingConvertToken(t *testing.T) { +func TestJSONMarshalingLeafTypeB(t *testing.T) { t.Run("MarshalUnmarshal", func(t *testing.T) { t.Parallel() // Arrange - obj := &ConvertToken{} + obj := &LeafTypeB{} // Act - Marshal to JSON data, err := json.Marshal(obj) @@ -1652,21 +2512,21 @@ func TestJSONMarshalingConvertToken(t *testing.T) { assert.NotEmpty(t, data, "marshaled data should not be empty") // Unmarshal back and verify round-trip - var unmarshaled ConvertToken + var unmarshaled LeafTypeB err = json.Unmarshal(data, &unmarshaled) assert.NoError(t, err, "round-trip unmarshal should succeed") }) t.Run("UnmarshalInvalidJSON", func(t *testing.T) { t.Parallel() - var obj ConvertToken + var obj LeafTypeB err := json.Unmarshal([]byte(`{invalid json}`), &obj) assert.Error(t, err, "unmarshaling invalid JSON should return an error") }) t.Run("UnmarshalEmptyObject", func(t *testing.T) { t.Parallel() - var obj ConvertToken + var obj LeafTypeB err := json.Unmarshal([]byte(`{}`), &obj) assert.NoError(t, err, "unmarshaling empty object should succeed") }) @@ -1804,6 +2664,39 @@ func TestJSONMarshalingTypeWithOptionalUnion(t *testing.T) { }) } +func TestJSONMarshalingWrapperObject(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled WrapperObject + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { + t.Parallel() + var obj WrapperObject + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") + }) + + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj WrapperObject + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) +} + func TestStringConvertToken(t *testing.T) { t.Run("StringMethod", func(t *testing.T) { t.Parallel() @@ -1820,6 +2713,70 @@ func TestStringConvertToken(t *testing.T) { }) } +func TestStringLeafObjectA(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectA{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + +func TestStringLeafObjectB(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectB{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectB + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + +func TestStringLeafTypeA(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeA{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + +func TestStringLeafTypeB(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeB{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeB + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + func TestStringNamedMetadata(t *testing.T) { t.Run("StringMethod", func(t *testing.T) { t.Parallel() @@ -1884,6 +2841,22 @@ func TestStringTypeWithOptionalUnion(t *testing.T) { }) } +func TestStringWrapperObject(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &WrapperObject{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + func TestEnumKeyType(t *testing.T) { t.Run("NewFromString_name", func(t *testing.T) { t.Parallel() @@ -1936,6 +2909,98 @@ func TestExtraPropertiesConvertToken(t *testing.T) { }) } +func TestExtraPropertiesLeafObjectA(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectA{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + +func TestExtraPropertiesLeafObjectB(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectB{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectB + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + +func TestExtraPropertiesLeafTypeA(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeA{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + +func TestExtraPropertiesLeafTypeB(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeB{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeB + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + func TestExtraPropertiesNamedMetadata(t *testing.T) { t.Run("GetExtraProperties", func(t *testing.T) { t.Parallel() @@ -2027,3 +3092,26 @@ func TestExtraPropertiesTypeWithOptionalUnion(t *testing.T) { assert.Nil(t, extraProps, "nil receiver should return nil without panicking") }) } + +func TestExtraPropertiesWrapperObject(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &WrapperObject{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} diff --git a/seed/go-sdk/undiscriminated-unions/v0/.fern/metadata.json b/seed/go-sdk/undiscriminated-unions/v0/.fern/metadata.json index 1dc7814c35ab..103f72d27c70 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/.fern/metadata.json +++ b/seed/go-sdk/undiscriminated-unions/v0/.fern/metadata.json @@ -11,7 +11,6 @@ "union": "v0" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example10/snippet.go b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example10/snippet.go index a1ef97acb1c1..3400b1a550d1 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example10/snippet.go +++ b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example10/snippet.go @@ -14,15 +14,13 @@ func do() { "https://api.fern.com", ), ) - request := &fern.PaymentRequest{ - PaymentMethod: &fern.PaymentMethodUnion{ - TokenizeCard: &fern.TokenizeCard{ - Method: "card", - CardNumber: "1234567890123456", - }, + request := &fern.AliasedObjectUnion{ + AliasedLeafA: &fern.LeafObjectA{ + OnlyInA: "onlyInA", + SharedNumber: 1, }, } - client.Union.TestCamelCaseProperties( + client.Union.AliasedObjectUnion( context.TODO(), request, ) diff --git a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example11/snippet.go b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example11/snippet.go index 0cd0d0ffab37..45f95995dd7b 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example11/snippet.go +++ b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example11/snippet.go @@ -14,15 +14,17 @@ func do() { "https://api.fern.com", ), ) - request := &fern.PaymentRequest{ - PaymentMethod: &fern.PaymentMethodUnion{ - TokenizeCard: &fern.TokenizeCard{ - Method: "method", - CardNumber: "cardNumber", + request := &fern.UnionWithBaseProperties{ + NamedMetadata: &fern.NamedMetadata{ + Name: "name", + Value: map[string]any{ + "value": map[string]any{ + "key": "value", + }, }, }, } - client.Union.TestCamelCaseProperties( + client.Union.GetWithBaseProperties( context.TODO(), request, ) diff --git a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example12/snippet.go b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example12/snippet.go new file mode 100644 index 000000000000..a1ef97acb1c1 --- /dev/null +++ b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example12/snippet.go @@ -0,0 +1,29 @@ +package example + +import ( + context "context" + + fern "github.com/undiscriminated-unions/fern" + client "github.com/undiscriminated-unions/fern/client" + option "github.com/undiscriminated-unions/fern/option" +) + +func do() { + client := client.NewClient( + option.WithBaseURL( + "https://api.fern.com", + ), + ) + request := &fern.PaymentRequest{ + PaymentMethod: &fern.PaymentMethodUnion{ + TokenizeCard: &fern.TokenizeCard{ + Method: "card", + CardNumber: "1234567890123456", + }, + }, + } + client.Union.TestCamelCaseProperties( + context.TODO(), + request, + ) +} diff --git a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example13/snippet.go b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example13/snippet.go new file mode 100644 index 000000000000..0cd0d0ffab37 --- /dev/null +++ b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example13/snippet.go @@ -0,0 +1,29 @@ +package example + +import ( + context "context" + + fern "github.com/undiscriminated-unions/fern" + client "github.com/undiscriminated-unions/fern/client" + option "github.com/undiscriminated-unions/fern/option" +) + +func do() { + client := client.NewClient( + option.WithBaseURL( + "https://api.fern.com", + ), + ) + request := &fern.PaymentRequest{ + PaymentMethod: &fern.PaymentMethodUnion{ + TokenizeCard: &fern.TokenizeCard{ + Method: "method", + CardNumber: "cardNumber", + }, + }, + } + client.Union.TestCamelCaseProperties( + context.TODO(), + request, + ) +} diff --git a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example9/snippet.go b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example9/snippet.go index 45f95995dd7b..870c6135bd68 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example9/snippet.go +++ b/seed/go-sdk/undiscriminated-unions/v0/dynamic-snippets/example9/snippet.go @@ -14,17 +14,10 @@ func do() { "https://api.fern.com", ), ) - request := &fern.UnionWithBaseProperties{ - NamedMetadata: &fern.NamedMetadata{ - Name: "name", - Value: map[string]any{ - "value": map[string]any{ - "key": "value", - }, - }, - }, + request := &fern.OuterNestedUnion{ + String: "string", } - client.Union.GetWithBaseProperties( + client.Union.NestedObjectUnions( context.TODO(), request, ) diff --git a/seed/go-sdk/undiscriminated-unions/v0/reference.md b/seed/go-sdk/undiscriminated-unions/v0/reference.md index 3ad42aa81ee5..aec268a98fc3 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/reference.md +++ b/seed/go-sdk/undiscriminated-unions/v0/reference.md @@ -269,6 +269,103 @@ client.Union.NestedUnions( + + + + +
client.Union.NestedObjectUnions(request) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```go +request := &fern.OuterNestedUnion{ + String: "string", + } +client.Union.NestedObjectUnions( + context.TODO(), + request, + ) +} +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `*fern.OuterNestedUnion` + +
+
+
+
+ + +
+
+
+ +
client.Union.AliasedObjectUnion(request) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```go +request := &fern.AliasedObjectUnion{ + AliasedLeafA: &fern.LeafObjectA{ + OnlyInA: "onlyInA", + SharedNumber: 1, + }, + } +client.Union.AliasedObjectUnion( + context.TODO(), + request, + ) +} +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `*fern.AliasedObjectUnion` + +
+
+
+
+ +
diff --git a/seed/go-sdk/undiscriminated-unions/v0/snippet.json b/seed/go-sdk/undiscriminated-unions/v0/snippet.json index 4e03f0e2b332..52a3d9b55552 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/snippet.json +++ b/seed/go-sdk/undiscriminated-unions/v0/snippet.json @@ -11,6 +11,17 @@ "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/undiscriminated-unions/fern\"\n\tfernclient \"github.com/undiscriminated-unions/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.Union.Get(\n\tcontext.TODO(),\n\tfern.NewMyUnionFromString(\n\t\t\"string\",\n\t),\n)\n" } }, + { + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "go", + "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/undiscriminated-unions/fern\"\n\tfernclient \"github.com/undiscriminated-unions/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.Union.AliasedObjectUnion(\n\tcontext.TODO(),\n\tfern.NewAliasedObjectUnionFromAliasedLeafA(\n\t\t\u0026fern.LeafObjectA{\n\t\t\tOnlyInA: \"onlyInA\",\n\t\t\tSharedNumber: 1,\n\t\t},\n\t),\n)\n" + } + }, { "id": { "path": "/call", @@ -66,6 +77,17 @@ "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/undiscriminated-unions/fern\"\n\tfernclient \"github.com/undiscriminated-unions/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.Union.UpdateMetadata(\n\tcontext.TODO(),\n\tfern.NewMetadataUnionFromOptionalMetadata(\n\t\tmap[string]any{\n\t\t\t\"string\": map[string]interface{}{\n\t\t\t\t\"key\": \"value\",\n\t\t\t},\n\t\t},\n\t),\n)\n" } }, + { + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "go", + "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/undiscriminated-unions/fern\"\n\tfernclient \"github.com/undiscriminated-unions/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.Union.NestedObjectUnions(\n\tcontext.TODO(),\n\tfern.NewOuterNestedUnionFromString(\n\t\t\"string\",\n\t),\n)\n" + } + }, { "id": { "path": "/nested", diff --git a/seed/go-sdk/undiscriminated-unions/v0/union.go b/seed/go-sdk/undiscriminated-unions/v0/union.go index 429a2d034a5f..49b9d78734ff 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/union.go +++ b/seed/go-sdk/undiscriminated-unions/v0/union.go @@ -55,6 +55,87 @@ func (p *PaymentRequest) MarshalJSON() ([]byte, error) { return json.Marshal(explicitMarshaler) } +type AliasToLeafB = *LeafObjectB + +// An alias around LeafObjectA. +type AliasedLeafA = *LeafObjectA + +// An alias around an alias around LeafObjectB, to exercise the alias-walk loop. +type AliasedLeafB = AliasToLeafB + +// Undiscriminated union whose members are named aliases of object types +// (including an alias-of-alias). Required keys are disjoint, so a correct +// deserializer must emit containsKey() guards for each alias variant. +type AliasedObjectUnion struct { + AliasedLeafA AliasedLeafA + AliasedLeafB AliasedLeafB + + typ string +} + +func NewAliasedObjectUnionFromAliasedLeafA(value AliasedLeafA) *AliasedObjectUnion { + return &AliasedObjectUnion{typ: "AliasedLeafA", AliasedLeafA: value} +} + +func NewAliasedObjectUnionFromAliasedLeafB(value AliasedLeafB) *AliasedObjectUnion { + return &AliasedObjectUnion{typ: "AliasedLeafB", AliasedLeafB: value} +} + +func (a *AliasedObjectUnion) GetAliasedLeafA() AliasedLeafA { + if a == nil { + return nil + } + return a.AliasedLeafA +} + +func (a *AliasedObjectUnion) GetAliasedLeafB() AliasedLeafB { + if a == nil { + return nil + } + return a.AliasedLeafB +} + +func (a *AliasedObjectUnion) UnmarshalJSON(data []byte) error { + var valueAliasedLeafA AliasedLeafA + if err := json.Unmarshal(data, &valueAliasedLeafA); err == nil { + a.typ = "AliasedLeafA" + a.AliasedLeafA = valueAliasedLeafA + return nil + } + var valueAliasedLeafB AliasedLeafB + if err := json.Unmarshal(data, &valueAliasedLeafB); err == nil { + a.typ = "AliasedLeafB" + a.AliasedLeafB = valueAliasedLeafB + return nil + } + return fmt.Errorf("%s cannot be deserialized as a %T", data, a) +} + +func (a AliasedObjectUnion) MarshalJSON() ([]byte, error) { + if a.typ == "AliasedLeafA" || a.AliasedLeafA != nil { + return json.Marshal(a.AliasedLeafA) + } + if a.typ == "AliasedLeafB" || a.AliasedLeafB != nil { + return json.Marshal(a.AliasedLeafB) + } + return nil, fmt.Errorf("type %T does not include a non-empty union type", a) +} + +type AliasedObjectUnionVisitor interface { + VisitAliasedLeafA(AliasedLeafA) error + VisitAliasedLeafB(AliasedLeafB) error +} + +func (a *AliasedObjectUnion) Accept(visitor AliasedObjectUnionVisitor) error { + if a.typ == "AliasedLeafA" || a.AliasedLeafA != nil { + return visitor.VisitAliasedLeafA(a.AliasedLeafA) + } + if a.typ == "AliasedLeafB" || a.AliasedLeafB != nil { + return visitor.VisitAliasedLeafB(a.AliasedLeafB) + } + return fmt.Errorf("type %T does not include a non-empty union type", a) +} + var ( convertTokenFieldMethod = big.NewInt(1 << 0) convertTokenFieldTokenID = big.NewInt(1 << 1) @@ -243,6 +324,374 @@ func (k KeyType) Ptr() *KeyType { return &k } +var ( + leafObjectAFieldOnlyInA = big.NewInt(1 << 0) + leafObjectAFieldSharedNumber = big.NewInt(1 << 1) +) + +type LeafObjectA struct { + OnlyInA string `json:"onlyInA" url:"onlyInA"` + SharedNumber int `json:"sharedNumber" url:"sharedNumber"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafObjectA) GetOnlyInA() string { + if l == nil { + return "" + } + return l.OnlyInA +} + +func (l *LeafObjectA) GetSharedNumber() int { + if l == nil { + return 0 + } + return l.SharedNumber +} + +func (l *LeafObjectA) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafObjectA) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetOnlyInA sets the OnlyInA field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafObjectA) SetOnlyInA(onlyInA string) { + l.OnlyInA = onlyInA + l.require(leafObjectAFieldOnlyInA) +} + +// SetSharedNumber sets the SharedNumber field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafObjectA) SetSharedNumber(sharedNumber int) { + l.SharedNumber = sharedNumber + l.require(leafObjectAFieldSharedNumber) +} + +func (l *LeafObjectA) UnmarshalJSON(data []byte) error { + type unmarshaler LeafObjectA + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafObjectA(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafObjectA) MarshalJSON() ([]byte, error) { + type embed LeafObjectA + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafObjectA) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + +var ( + leafObjectBFieldOnlyInB = big.NewInt(1 << 0) +) + +type LeafObjectB struct { + OnlyInB string `json:"onlyInB" url:"onlyInB"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafObjectB) GetOnlyInB() string { + if l == nil { + return "" + } + return l.OnlyInB +} + +func (l *LeafObjectB) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafObjectB) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetOnlyInB sets the OnlyInB field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafObjectB) SetOnlyInB(onlyInB string) { + l.OnlyInB = onlyInB + l.require(leafObjectBFieldOnlyInB) +} + +func (l *LeafObjectB) UnmarshalJSON(data []byte) error { + type unmarshaler LeafObjectB + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafObjectB(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafObjectB) MarshalJSON() ([]byte, error) { + type embed LeafObjectB + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafObjectB) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + +var ( + leafTypeAFieldAlpha = big.NewInt(1 << 0) + leafTypeAFieldBeta = big.NewInt(1 << 1) +) + +type LeafTypeA struct { + Alpha string `json:"alpha" url:"alpha"` + Beta int `json:"beta" url:"beta"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafTypeA) GetAlpha() string { + if l == nil { + return "" + } + return l.Alpha +} + +func (l *LeafTypeA) GetBeta() int { + if l == nil { + return 0 + } + return l.Beta +} + +func (l *LeafTypeA) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafTypeA) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetAlpha sets the Alpha field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafTypeA) SetAlpha(alpha string) { + l.Alpha = alpha + l.require(leafTypeAFieldAlpha) +} + +// SetBeta sets the Beta field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafTypeA) SetBeta(beta int) { + l.Beta = beta + l.require(leafTypeAFieldBeta) +} + +func (l *LeafTypeA) UnmarshalJSON(data []byte) error { + type unmarshaler LeafTypeA + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafTypeA(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafTypeA) MarshalJSON() ([]byte, error) { + type embed LeafTypeA + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafTypeA) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + +var ( + leafTypeBFieldGamma = big.NewInt(1 << 0) +) + +type LeafTypeB struct { + Gamma string `json:"gamma" url:"gamma"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (l *LeafTypeB) GetGamma() string { + if l == nil { + return "" + } + return l.Gamma +} + +func (l *LeafTypeB) GetExtraProperties() map[string]interface{} { + if l == nil { + return nil + } + return l.extraProperties +} + +func (l *LeafTypeB) require(field *big.Int) { + if l.explicitFields == nil { + l.explicitFields = big.NewInt(0) + } + l.explicitFields.Or(l.explicitFields, field) +} + +// SetGamma sets the Gamma field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (l *LeafTypeB) SetGamma(gamma string) { + l.Gamma = gamma + l.require(leafTypeBFieldGamma) +} + +func (l *LeafTypeB) UnmarshalJSON(data []byte) error { + type unmarshaler LeafTypeB + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *l = LeafTypeB(value) + extraProperties, err := internal.ExtractExtraProperties(data, *l) + if err != nil { + return err + } + l.extraProperties = extraProperties + l.rawJSON = json.RawMessage(data) + return nil +} + +func (l *LeafTypeB) MarshalJSON() ([]byte, error) { + type embed LeafTypeB + var marshaler = struct { + embed + }{ + embed: embed(*l), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, l.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (l *LeafTypeB) String() string { + if l == nil { + return "" + } + if len(l.rawJSON) > 0 { + if value, err := internal.StringifyJSON(l.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(l); err == nil { + return value + } + return fmt.Sprintf("%#v", l) +} + // Undiscriminated unions can act as a map key // as long as all of their values are valid keys // (i.e. do they have a valid string representation). @@ -592,6 +1041,78 @@ func (n *NamedMetadata) String() string { return fmt.Sprintf("%#v", n) } +// Inner union with two object variants that have disjoint required keys. +// Tests that required-key guards work correctly inside nested union contexts. +type NestedObjectUnion struct { + LeafTypeA *LeafTypeA + LeafTypeB *LeafTypeB + + typ string +} + +func NewNestedObjectUnionFromLeafTypeA(value *LeafTypeA) *NestedObjectUnion { + return &NestedObjectUnion{typ: "LeafTypeA", LeafTypeA: value} +} + +func NewNestedObjectUnionFromLeafTypeB(value *LeafTypeB) *NestedObjectUnion { + return &NestedObjectUnion{typ: "LeafTypeB", LeafTypeB: value} +} + +func (n *NestedObjectUnion) GetLeafTypeA() *LeafTypeA { + if n == nil { + return nil + } + return n.LeafTypeA +} + +func (n *NestedObjectUnion) GetLeafTypeB() *LeafTypeB { + if n == nil { + return nil + } + return n.LeafTypeB +} + +func (n *NestedObjectUnion) UnmarshalJSON(data []byte) error { + valueLeafTypeA := new(LeafTypeA) + if err := json.Unmarshal(data, &valueLeafTypeA); err == nil { + n.typ = "LeafTypeA" + n.LeafTypeA = valueLeafTypeA + return nil + } + valueLeafTypeB := new(LeafTypeB) + if err := json.Unmarshal(data, &valueLeafTypeB); err == nil { + n.typ = "LeafTypeB" + n.LeafTypeB = valueLeafTypeB + return nil + } + return fmt.Errorf("%s cannot be deserialized as a %T", data, n) +} + +func (n NestedObjectUnion) MarshalJSON() ([]byte, error) { + if n.typ == "LeafTypeA" || n.LeafTypeA != nil { + return json.Marshal(n.LeafTypeA) + } + if n.typ == "LeafTypeB" || n.LeafTypeB != nil { + return json.Marshal(n.LeafTypeB) + } + return nil, fmt.Errorf("type %T does not include a non-empty union type", n) +} + +type NestedObjectUnionVisitor interface { + VisitLeafTypeA(*LeafTypeA) error + VisitLeafTypeB(*LeafTypeB) error +} + +func (n *NestedObjectUnion) Accept(visitor NestedObjectUnionVisitor) error { + if n.typ == "LeafTypeA" || n.LeafTypeA != nil { + return visitor.VisitLeafTypeA(n.LeafTypeA) + } + if n.typ == "LeafTypeB" || n.LeafTypeB != nil { + return visitor.VisitLeafTypeB(n.LeafTypeB) + } + return fmt.Errorf("type %T does not include a non-empty union type", n) +} + // Nested layer 1. type NestedUnionL1 struct { Integer int @@ -907,6 +1428,78 @@ func (n *NestedUnionRoot) Accept(visitor NestedUnionRootVisitor) error { type OptionalMetadata = map[string]any +// Outer union where one variant is an object containing a nested union field. +// Tests that the deserializer correctly handles transitive union deserialization. +type OuterNestedUnion struct { + String string + WrapperObject *WrapperObject + + typ string +} + +func NewOuterNestedUnionFromString(value string) *OuterNestedUnion { + return &OuterNestedUnion{typ: "String", String: value} +} + +func NewOuterNestedUnionFromWrapperObject(value *WrapperObject) *OuterNestedUnion { + return &OuterNestedUnion{typ: "WrapperObject", WrapperObject: value} +} + +func (o *OuterNestedUnion) GetString() string { + if o == nil { + return "" + } + return o.String +} + +func (o *OuterNestedUnion) GetWrapperObject() *WrapperObject { + if o == nil { + return nil + } + return o.WrapperObject +} + +func (o *OuterNestedUnion) UnmarshalJSON(data []byte) error { + var valueString string + if err := json.Unmarshal(data, &valueString); err == nil { + o.typ = "String" + o.String = valueString + return nil + } + valueWrapperObject := new(WrapperObject) + if err := json.Unmarshal(data, &valueWrapperObject); err == nil { + o.typ = "WrapperObject" + o.WrapperObject = valueWrapperObject + return nil + } + return fmt.Errorf("%s cannot be deserialized as a %T", data, o) +} + +func (o OuterNestedUnion) MarshalJSON() ([]byte, error) { + if o.typ == "String" || o.String != "" { + return json.Marshal(o.String) + } + if o.typ == "WrapperObject" || o.WrapperObject != nil { + return json.Marshal(o.WrapperObject) + } + return nil, fmt.Errorf("type %T does not include a non-empty union type", o) +} + +type OuterNestedUnionVisitor interface { + VisitString(string) error + VisitWrapperObject(*WrapperObject) error +} + +func (o *OuterNestedUnion) Accept(visitor OuterNestedUnionVisitor) error { + if o.typ == "String" || o.String != "" { + return visitor.VisitString(o.String) + } + if o.typ == "WrapperObject" || o.WrapperObject != nil { + return visitor.VisitWrapperObject(o.WrapperObject) + } + return fmt.Errorf("type %T does not include a non-empty union type", o) +} + // Tests that nested properties with camelCase wire names are properly // converted from snake_case Ruby keys when passed as Hash values. type PaymentMethodUnion struct { @@ -1776,3 +2369,103 @@ func (u *UnionWithTypeAliases) Accept(visitor UnionWithTypeAliasesVisitor) error // A user identifier (alias for string) type UserID = string + +var ( + wrapperObjectFieldInner = big.NewInt(1 << 0) + wrapperObjectFieldLabel = big.NewInt(1 << 1) +) + +type WrapperObject struct { + Inner *NestedObjectUnion `json:"inner,omitempty" url:"inner,omitempty"` + Label string `json:"label" url:"label"` + + // Private bitmask of fields set to an explicit value and therefore not to be omitted + explicitFields *big.Int `json:"-" url:"-"` + + extraProperties map[string]interface{} + rawJSON json.RawMessage +} + +func (w *WrapperObject) GetInner() *NestedObjectUnion { + if w == nil { + return nil + } + return w.Inner +} + +func (w *WrapperObject) GetLabel() string { + if w == nil { + return "" + } + return w.Label +} + +func (w *WrapperObject) GetExtraProperties() map[string]interface{} { + if w == nil { + return nil + } + return w.extraProperties +} + +func (w *WrapperObject) require(field *big.Int) { + if w.explicitFields == nil { + w.explicitFields = big.NewInt(0) + } + w.explicitFields.Or(w.explicitFields, field) +} + +// SetInner sets the Inner field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (w *WrapperObject) SetInner(inner *NestedObjectUnion) { + w.Inner = inner + w.require(wrapperObjectFieldInner) +} + +// SetLabel sets the Label field and marks it as non-optional; +// this prevents an empty or null value for this field from being omitted during serialization. +func (w *WrapperObject) SetLabel(label string) { + w.Label = label + w.require(wrapperObjectFieldLabel) +} + +func (w *WrapperObject) UnmarshalJSON(data []byte) error { + type unmarshaler WrapperObject + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *w = WrapperObject(value) + extraProperties, err := internal.ExtractExtraProperties(data, *w) + if err != nil { + return err + } + w.extraProperties = extraProperties + w.rawJSON = json.RawMessage(data) + return nil +} + +func (w *WrapperObject) MarshalJSON() ([]byte, error) { + type embed WrapperObject + var marshaler = struct { + embed + }{ + embed: embed(*w), + } + explicitMarshaler := internal.HandleExplicitFields(marshaler, w.explicitFields) + return json.Marshal(explicitMarshaler) +} + +func (w *WrapperObject) String() string { + if w == nil { + return "" + } + if len(w.rawJSON) > 0 { + if value, err := internal.StringifyJSON(w.rawJSON); err == nil { + return value + } + } + if value, err := internal.StringifyJSON(w); err == nil { + return value + } + return fmt.Sprintf("%#v", w) +} diff --git a/seed/go-sdk/undiscriminated-unions/v0/union/client.go b/seed/go-sdk/undiscriminated-unions/v0/union/client.go index 183674cfa872..ccf61f640f42 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/union/client.go +++ b/seed/go-sdk/undiscriminated-unions/v0/union/client.go @@ -127,6 +127,38 @@ func (c *Client) NestedUnions( return response.Body, nil } +func (c *Client) NestedObjectUnions( + ctx context.Context, + request *fern.OuterNestedUnion, + opts ...option.RequestOption, +) (string, error) { + response, err := c.WithRawResponse.NestedObjectUnions( + ctx, + request, + opts..., + ) + if err != nil { + return "", err + } + return response.Body, nil +} + +func (c *Client) AliasedObjectUnion( + ctx context.Context, + request *fern.AliasedObjectUnion, + opts ...option.RequestOption, +) (string, error) { + response, err := c.WithRawResponse.AliasedObjectUnion( + ctx, + request, + opts..., + ) + if err != nil { + return "", err + } + return response.Body, nil +} + func (c *Client) GetWithBaseProperties( ctx context.Context, request *fern.UnionWithBaseProperties, diff --git a/seed/go-sdk/undiscriminated-unions/v0/union/raw_client.go b/seed/go-sdk/undiscriminated-unions/v0/union/raw_client.go index cc66d615117b..b3192adba407 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/union/raw_client.go +++ b/seed/go-sdk/undiscriminated-unions/v0/union/raw_client.go @@ -275,6 +275,88 @@ func (r *RawClient) NestedUnions( }, nil } +func (r *RawClient) NestedObjectUnions( + ctx context.Context, + request *fern.OuterNestedUnion, + opts ...option.RequestOption, +) (*core.Response[string], error) { + options := core.NewRequestOptions(opts...) + baseURL := internal.ResolveBaseURL( + options.BaseURL, + r.baseURL, + "", + ) + endpointURL := baseURL + "/nested-objects" + headers := internal.MergeHeaders( + r.options.ToHeader(), + options.ToHeader(), + ) + var response string + raw, err := r.caller.Call( + ctx, + &internal.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + Headers: headers, + MaxAttempts: options.MaxAttempts, + BodyProperties: options.BodyProperties, + QueryParameters: options.QueryParameters, + Client: options.HTTPClient, + Request: request, + Response: &response, + }, + ) + if err != nil { + return nil, err + } + return &core.Response[string]{ + StatusCode: raw.StatusCode, + Header: raw.Header, + Body: response, + }, nil +} + +func (r *RawClient) AliasedObjectUnion( + ctx context.Context, + request *fern.AliasedObjectUnion, + opts ...option.RequestOption, +) (*core.Response[string], error) { + options := core.NewRequestOptions(opts...) + baseURL := internal.ResolveBaseURL( + options.BaseURL, + r.baseURL, + "", + ) + endpointURL := baseURL + "/aliased-object" + headers := internal.MergeHeaders( + r.options.ToHeader(), + options.ToHeader(), + ) + var response string + raw, err := r.caller.Call( + ctx, + &internal.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + Headers: headers, + MaxAttempts: options.MaxAttempts, + BodyProperties: options.BodyProperties, + QueryParameters: options.QueryParameters, + Client: options.HTTPClient, + Request: request, + Response: &response, + }, + ) + if err != nil { + return nil, err + } + return &core.Response[string]{ + StatusCode: raw.StatusCode, + Header: raw.Header, + Body: response, + }, nil +} + func (r *RawClient) GetWithBaseProperties( ctx context.Context, request *fern.UnionWithBaseProperties, diff --git a/seed/go-sdk/undiscriminated-unions/v0/union_test.go b/seed/go-sdk/undiscriminated-unions/v0/union_test.go index 8707d2aac7ee..29c9dbbc4362 100644 --- a/seed/go-sdk/undiscriminated-unions/v0/union_test.go +++ b/seed/go-sdk/undiscriminated-unions/v0/union_test.go @@ -54,6 +54,55 @@ func TestSettersMarkExplicitPaymentRequest(t *testing.T) { } +func TestGettersAliasedObjectUnion(t *testing.T) { + t.Run("GetAliasedLeafA", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &AliasedObjectUnion{} + var expected AliasedLeafA + obj.AliasedLeafA = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetAliasedLeafA(), "getter should return the property value") + }) + + t.Run("GetAliasedLeafA_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *AliasedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetAliasedLeafA() // Should return zero value + }) + + t.Run("GetAliasedLeafB", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &AliasedObjectUnion{} + var expected AliasedLeafB + obj.AliasedLeafB = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetAliasedLeafB(), "getter should return the property value") + }) + + t.Run("GetAliasedLeafB_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *AliasedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetAliasedLeafB() // Should return zero value + }) + +} + func TestSettersConvertToken(t *testing.T) { t.Run("SetMethod", func(t *testing.T) { obj := &ConvertToken{} @@ -213,6 +262,414 @@ func TestGettersKey(t *testing.T) { } +func TestSettersLeafObjectA(t *testing.T) { + t.Run("SetOnlyInA", func(t *testing.T) { + obj := &LeafObjectA{} + var fernTestValueOnlyInA string + obj.SetOnlyInA(fernTestValueOnlyInA) + assert.Equal(t, fernTestValueOnlyInA, obj.OnlyInA) + assert.NotNil(t, obj.explicitFields) + }) + + t.Run("SetSharedNumber", func(t *testing.T) { + obj := &LeafObjectA{} + var fernTestValueSharedNumber int + obj.SetSharedNumber(fernTestValueSharedNumber) + assert.Equal(t, fernTestValueSharedNumber, obj.SharedNumber) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafObjectA(t *testing.T) { + t.Run("GetOnlyInA", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var expected string + obj.OnlyInA = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetOnlyInA(), "getter should return the property value") + }) + + t.Run("GetOnlyInA_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetOnlyInA() // Should return zero value + }) + + t.Run("GetSharedNumber", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var expected int + obj.SharedNumber = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetSharedNumber(), "getter should return the property value") + }) + + t.Run("GetSharedNumber_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetSharedNumber() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafObjectA(t *testing.T) { + t.Run("SetOnlyInA_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var fernTestValueOnlyInA string + + // Act + obj.SetOnlyInA(fernTestValueOnlyInA) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + + t.Run("SetSharedNumber_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + var fernTestValueSharedNumber int + + // Act + obj.SetSharedNumber(fernTestValueSharedNumber) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestSettersLeafObjectB(t *testing.T) { + t.Run("SetOnlyInB", func(t *testing.T) { + obj := &LeafObjectB{} + var fernTestValueOnlyInB string + obj.SetOnlyInB(fernTestValueOnlyInB) + assert.Equal(t, fernTestValueOnlyInB, obj.OnlyInB) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafObjectB(t *testing.T) { + t.Run("GetOnlyInB", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectB{} + var expected string + obj.OnlyInB = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetOnlyInB(), "getter should return the property value") + }) + + t.Run("GetOnlyInB_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectB + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetOnlyInB() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafObjectB(t *testing.T) { + t.Run("SetOnlyInB_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectB{} + var fernTestValueOnlyInB string + + // Act + obj.SetOnlyInB(fernTestValueOnlyInB) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestSettersLeafTypeA(t *testing.T) { + t.Run("SetAlpha", func(t *testing.T) { + obj := &LeafTypeA{} + var fernTestValueAlpha string + obj.SetAlpha(fernTestValueAlpha) + assert.Equal(t, fernTestValueAlpha, obj.Alpha) + assert.NotNil(t, obj.explicitFields) + }) + + t.Run("SetBeta", func(t *testing.T) { + obj := &LeafTypeA{} + var fernTestValueBeta int + obj.SetBeta(fernTestValueBeta) + assert.Equal(t, fernTestValueBeta, obj.Beta) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafTypeA(t *testing.T) { + t.Run("GetAlpha", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var expected string + obj.Alpha = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetAlpha(), "getter should return the property value") + }) + + t.Run("GetAlpha_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetAlpha() // Should return zero value + }) + + t.Run("GetBeta", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var expected int + obj.Beta = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetBeta(), "getter should return the property value") + }) + + t.Run("GetBeta_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetBeta() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafTypeA(t *testing.T) { + t.Run("SetAlpha_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var fernTestValueAlpha string + + // Act + obj.SetAlpha(fernTestValueAlpha) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + + t.Run("SetBeta_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeA{} + var fernTestValueBeta int + + // Act + obj.SetBeta(fernTestValueBeta) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestSettersLeafTypeB(t *testing.T) { + t.Run("SetGamma", func(t *testing.T) { + obj := &LeafTypeB{} + var fernTestValueGamma string + obj.SetGamma(fernTestValueGamma) + assert.Equal(t, fernTestValueGamma, obj.Gamma) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersLeafTypeB(t *testing.T) { + t.Run("GetGamma", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeB{} + var expected string + obj.Gamma = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetGamma(), "getter should return the property value") + }) + + t.Run("GetGamma_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeB + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetGamma() // Should return zero value + }) + +} + +func TestSettersMarkExplicitLeafTypeB(t *testing.T) { + t.Run("SetGamma_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafTypeB{} + var fernTestValueGamma string + + // Act + obj.SetGamma(fernTestValueGamma) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + func TestGettersMetadataUnion(t *testing.T) { t.Run("GetOptionalMetadata", func(t *testing.T) { t.Parallel() @@ -596,6 +1053,75 @@ func TestSettersMarkExplicitNamedMetadata(t *testing.T) { } +func TestGettersNestedObjectUnion(t *testing.T) { + t.Run("GetLeafTypeA", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + var expected *LeafTypeA + obj.LeafTypeA = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetLeafTypeA(), "getter should return the property value") + }) + + t.Run("GetLeafTypeA_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + obj.LeafTypeA = nil + + // Act & Assert + assert.Nil(t, obj.GetLeafTypeA(), "getter should return nil when property is nil") + }) + + t.Run("GetLeafTypeA_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetLeafTypeA() // Should return zero value + }) + + t.Run("GetLeafTypeB", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + var expected *LeafTypeB + obj.LeafTypeB = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetLeafTypeB(), "getter should return the property value") + }) + + t.Run("GetLeafTypeB_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedObjectUnion{} + obj.LeafTypeB = nil + + // Act & Assert + assert.Nil(t, obj.GetLeafTypeB(), "getter should return nil when property is nil") + }) + + t.Run("GetLeafTypeB_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedObjectUnion + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetLeafTypeB() // Should return zero value + }) + +} + func TestGettersNestedUnionL1(t *testing.T) { t.Run("GetInteger", func(t *testing.T) { t.Parallel() @@ -848,59 +1374,118 @@ func TestGettersNestedUnionRoot(t *testing.T) { assert.Equal(t, expected, obj.GetStringList(), "getter should return the property value") }) - t.Run("GetStringList_NilValue", func(t *testing.T) { + t.Run("GetStringList_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedUnionRoot{} + obj.StringList = nil + + // Act & Assert + assert.Nil(t, obj.GetStringList(), "getter should return nil when property is nil") + }) + + t.Run("GetStringList_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedUnionRoot + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetStringList() // Should return zero value + }) + + t.Run("GetNestedUnionL1", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedUnionRoot{} + var expected *NestedUnionL1 + obj.NestedUnionL1 = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetNestedUnionL1(), "getter should return the property value") + }) + + t.Run("GetNestedUnionL1_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &NestedUnionRoot{} + obj.NestedUnionL1 = nil + + // Act & Assert + assert.Nil(t, obj.GetNestedUnionL1(), "getter should return nil when property is nil") + }) + + t.Run("GetNestedUnionL1_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *NestedUnionRoot + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetNestedUnionL1() // Should return zero value + }) + +} + +func TestGettersOuterNestedUnion(t *testing.T) { + t.Run("GetString", func(t *testing.T) { t.Parallel() // Arrange - obj := &NestedUnionRoot{} - obj.StringList = nil + obj := &OuterNestedUnion{} + var expected string + obj.String = expected // Act & Assert - assert.Nil(t, obj.GetStringList(), "getter should return nil when property is nil") + assert.Equal(t, expected, obj.GetString(), "getter should return the property value") }) - t.Run("GetStringList_NilReceiver", func(t *testing.T) { + t.Run("GetString_NilReceiver", func(t *testing.T) { t.Parallel() - var obj *NestedUnionRoot + var obj *OuterNestedUnion // Should not panic - getters should handle nil receiver gracefully defer func() { if r := recover(); r != nil { t.Errorf("Getter panicked on nil receiver: %v", r) } }() - _ = obj.GetStringList() // Should return zero value + _ = obj.GetString() // Should return zero value }) - t.Run("GetNestedUnionL1", func(t *testing.T) { + t.Run("GetWrapperObject", func(t *testing.T) { t.Parallel() // Arrange - obj := &NestedUnionRoot{} - var expected *NestedUnionL1 - obj.NestedUnionL1 = expected + obj := &OuterNestedUnion{} + var expected *WrapperObject + obj.WrapperObject = expected // Act & Assert - assert.Equal(t, expected, obj.GetNestedUnionL1(), "getter should return the property value") + assert.Equal(t, expected, obj.GetWrapperObject(), "getter should return the property value") }) - t.Run("GetNestedUnionL1_NilValue", func(t *testing.T) { + t.Run("GetWrapperObject_NilValue", func(t *testing.T) { t.Parallel() // Arrange - obj := &NestedUnionRoot{} - obj.NestedUnionL1 = nil + obj := &OuterNestedUnion{} + obj.WrapperObject = nil // Act & Assert - assert.Nil(t, obj.GetNestedUnionL1(), "getter should return nil when property is nil") + assert.Nil(t, obj.GetWrapperObject(), "getter should return nil when property is nil") }) - t.Run("GetNestedUnionL1_NilReceiver", func(t *testing.T) { + t.Run("GetWrapperObject_NilReceiver", func(t *testing.T) { t.Parallel() - var obj *NestedUnionRoot + var obj *OuterNestedUnion // Should not panic - getters should handle nil receiver gracefully defer func() { if r := recover(); r != nil { t.Errorf("Getter panicked on nil receiver: %v", r) } }() - _ = obj.GetNestedUnionL1() // Should return zero value + _ = obj.GetWrapperObject() // Should return zero value }) } @@ -1591,59 +2176,334 @@ func TestGettersUnionWithTypeAliases(t *testing.T) { _ = obj.GetString() // Should return zero value }) - t.Run("GetUserID", func(t *testing.T) { + t.Run("GetUserID", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &UnionWithTypeAliases{} + var expected UserID + obj.UserID = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetUserID(), "getter should return the property value") + }) + + t.Run("GetUserID_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *UnionWithTypeAliases + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetUserID() // Should return zero value + }) + + t.Run("GetName", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &UnionWithTypeAliases{} + var expected Name + obj.Name = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetName(), "getter should return the property value") + }) + + t.Run("GetName_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *UnionWithTypeAliases + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetName() // Should return zero value + }) + +} + +func TestSettersWrapperObject(t *testing.T) { + t.Run("SetInner", func(t *testing.T) { + obj := &WrapperObject{} + var fernTestValueInner *NestedObjectUnion + obj.SetInner(fernTestValueInner) + assert.Equal(t, fernTestValueInner, obj.Inner) + assert.NotNil(t, obj.explicitFields) + }) + + t.Run("SetLabel", func(t *testing.T) { + obj := &WrapperObject{} + var fernTestValueLabel string + obj.SetLabel(fernTestValueLabel) + assert.Equal(t, fernTestValueLabel, obj.Label) + assert.NotNil(t, obj.explicitFields) + }) + +} + +func TestGettersWrapperObject(t *testing.T) { + t.Run("GetInner", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var expected *NestedObjectUnion + obj.Inner = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetInner(), "getter should return the property value") + }) + + t.Run("GetInner_NilValue", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + obj.Inner = nil + + // Act & Assert + assert.Nil(t, obj.GetInner(), "getter should return nil when property is nil") + }) + + t.Run("GetInner_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetInner() // Should return zero value + }) + + t.Run("GetLabel", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var expected string + obj.Label = expected + + // Act & Assert + assert.Equal(t, expected, obj.GetLabel(), "getter should return the property value") + }) + + t.Run("GetLabel_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + // Should not panic - getters should handle nil receiver gracefully + defer func() { + if r := recover(); r != nil { + t.Errorf("Getter panicked on nil receiver: %v", r) + } + }() + _ = obj.GetLabel() // Should return zero value + }) + +} + +func TestSettersMarkExplicitWrapperObject(t *testing.T) { + t.Run("SetInner_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var fernTestValueInner *NestedObjectUnion + + // Act + obj.SetInner(fernTestValueInner) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + + t.Run("SetLabel_MarksExplicit", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + var fernTestValueLabel string + + // Act + obj.SetLabel(fernTestValueLabel) + + // Assert - object with explicitly set field can be marshaled/unmarshaled + bytes, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed for test setup") + + // This test ensures JSON marshaling and unmarshaling succeed when the field has a zero/nil value + // Detect if marshaled JSON is an object or primitive to use correct unmarshal target + if len(bytes) > 0 && bytes[0] == '{' { + // JSON object - unmarshal into map + var unmarshaled map[string]interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } else { + // JSON primitive (string, number, boolean, null) - unmarshal into interface{} + var unmarshaled interface{} + err = json.Unmarshal(bytes, &unmarshaled) + require.NoError(t, err, "unmarshaling should succeed for test verification") + } + + // Note: This does not explicitly assert the presence of a specific JSON field + // It verifies that setting a field via setter allows successful JSON round-trip + }) + +} + +func TestJSONMarshalingConvertToken(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &ConvertToken{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled ConvertToken + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { + t.Parallel() + var obj ConvertToken + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") + }) + + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj ConvertToken + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) +} + +func TestJSONMarshalingLeafObjectA(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectA{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled LeafObjectA + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { + t.Parallel() + var obj LeafObjectA + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") + }) + + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj LeafObjectA + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) +} + +func TestJSONMarshalingLeafObjectB(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &LeafObjectB{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled LeafObjectB + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { t.Parallel() - // Arrange - obj := &UnionWithTypeAliases{} - var expected UserID - obj.UserID = expected - - // Act & Assert - assert.Equal(t, expected, obj.GetUserID(), "getter should return the property value") + var obj LeafObjectB + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") }) - t.Run("GetUserID_NilReceiver", func(t *testing.T) { + t.Run("UnmarshalEmptyObject", func(t *testing.T) { t.Parallel() - var obj *UnionWithTypeAliases - // Should not panic - getters should handle nil receiver gracefully - defer func() { - if r := recover(); r != nil { - t.Errorf("Getter panicked on nil receiver: %v", r) - } - }() - _ = obj.GetUserID() // Should return zero value + var obj LeafObjectB + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") }) +} - t.Run("GetName", func(t *testing.T) { +func TestJSONMarshalingLeafTypeA(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { t.Parallel() // Arrange - obj := &UnionWithTypeAliases{} - var expected Name - obj.Name = expected + obj := &LeafTypeA{} - // Act & Assert - assert.Equal(t, expected, obj.GetName(), "getter should return the property value") + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled LeafTypeA + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") }) - t.Run("GetName_NilReceiver", func(t *testing.T) { + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { t.Parallel() - var obj *UnionWithTypeAliases - // Should not panic - getters should handle nil receiver gracefully - defer func() { - if r := recover(); r != nil { - t.Errorf("Getter panicked on nil receiver: %v", r) - } - }() - _ = obj.GetName() // Should return zero value + var obj LeafTypeA + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") }) + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj LeafTypeA + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) } -func TestJSONMarshalingConvertToken(t *testing.T) { +func TestJSONMarshalingLeafTypeB(t *testing.T) { t.Run("MarshalUnmarshal", func(t *testing.T) { t.Parallel() // Arrange - obj := &ConvertToken{} + obj := &LeafTypeB{} // Act - Marshal to JSON data, err := json.Marshal(obj) @@ -1652,21 +2512,21 @@ func TestJSONMarshalingConvertToken(t *testing.T) { assert.NotEmpty(t, data, "marshaled data should not be empty") // Unmarshal back and verify round-trip - var unmarshaled ConvertToken + var unmarshaled LeafTypeB err = json.Unmarshal(data, &unmarshaled) assert.NoError(t, err, "round-trip unmarshal should succeed") }) t.Run("UnmarshalInvalidJSON", func(t *testing.T) { t.Parallel() - var obj ConvertToken + var obj LeafTypeB err := json.Unmarshal([]byte(`{invalid json}`), &obj) assert.Error(t, err, "unmarshaling invalid JSON should return an error") }) t.Run("UnmarshalEmptyObject", func(t *testing.T) { t.Parallel() - var obj ConvertToken + var obj LeafTypeB err := json.Unmarshal([]byte(`{}`), &obj) assert.NoError(t, err, "unmarshaling empty object should succeed") }) @@ -1804,6 +2664,39 @@ func TestJSONMarshalingTypeWithOptionalUnion(t *testing.T) { }) } +func TestJSONMarshalingWrapperObject(t *testing.T) { + t.Run("MarshalUnmarshal", func(t *testing.T) { + t.Parallel() + // Arrange + obj := &WrapperObject{} + + // Act - Marshal to JSON + data, err := json.Marshal(obj) + require.NoError(t, err, "marshaling should succeed") + assert.NotNil(t, data, "marshaled data should not be nil") + assert.NotEmpty(t, data, "marshaled data should not be empty") + + // Unmarshal back and verify round-trip + var unmarshaled WrapperObject + err = json.Unmarshal(data, &unmarshaled) + assert.NoError(t, err, "round-trip unmarshal should succeed") + }) + + t.Run("UnmarshalInvalidJSON", func(t *testing.T) { + t.Parallel() + var obj WrapperObject + err := json.Unmarshal([]byte(`{invalid json}`), &obj) + assert.Error(t, err, "unmarshaling invalid JSON should return an error") + }) + + t.Run("UnmarshalEmptyObject", func(t *testing.T) { + t.Parallel() + var obj WrapperObject + err := json.Unmarshal([]byte(`{}`), &obj) + assert.NoError(t, err, "unmarshaling empty object should succeed") + }) +} + func TestStringConvertToken(t *testing.T) { t.Run("StringMethod", func(t *testing.T) { t.Parallel() @@ -1820,6 +2713,70 @@ func TestStringConvertToken(t *testing.T) { }) } +func TestStringLeafObjectA(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectA{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + +func TestStringLeafObjectB(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectB{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectB + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + +func TestStringLeafTypeA(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeA{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + +func TestStringLeafTypeB(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeB{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeB + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + func TestStringNamedMetadata(t *testing.T) { t.Run("StringMethod", func(t *testing.T) { t.Parallel() @@ -1884,6 +2841,22 @@ func TestStringTypeWithOptionalUnion(t *testing.T) { }) } +func TestStringWrapperObject(t *testing.T) { + t.Run("StringMethod", func(t *testing.T) { + t.Parallel() + obj := &WrapperObject{} + result := obj.String() + assert.NotEmpty(t, result, "String() should return a non-empty representation") + }) + + t.Run("StringMethod_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + result := obj.String() + assert.Equal(t, "", result, "String() should return for nil receiver") + }) +} + func TestEnumKeyType(t *testing.T) { t.Run("NewFromString_name", func(t *testing.T) { t.Parallel() @@ -1936,6 +2909,98 @@ func TestExtraPropertiesConvertToken(t *testing.T) { }) } +func TestExtraPropertiesLeafObjectA(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectA{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectA + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + +func TestExtraPropertiesLeafObjectB(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafObjectB{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafObjectB + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + +func TestExtraPropertiesLeafTypeA(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeA{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeA + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + +func TestExtraPropertiesLeafTypeB(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &LeafTypeB{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *LeafTypeB + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} + func TestExtraPropertiesNamedMetadata(t *testing.T) { t.Run("GetExtraProperties", func(t *testing.T) { t.Parallel() @@ -2027,3 +3092,26 @@ func TestExtraPropertiesTypeWithOptionalUnion(t *testing.T) { assert.Nil(t, extraProps, "nil receiver should return nil without panicking") }) } + +func TestExtraPropertiesWrapperObject(t *testing.T) { + t.Run("GetExtraProperties", func(t *testing.T) { + t.Parallel() + obj := &WrapperObject{} + // Should not panic when calling GetExtraProperties() + defer func() { + if r := recover(); r != nil { + t.Errorf("GetExtraProperties() panicked: %v", r) + } + }() + extraProps := obj.GetExtraProperties() + // Result can be nil or an empty/non-empty map + _ = extraProps + }) + + t.Run("GetExtraProperties_NilReceiver", func(t *testing.T) { + t.Parallel() + var obj *WrapperObject + extraProps := obj.GetExtraProperties() + assert.Nil(t, extraProps, "nil receiver should return nil without panicking") + }) +} diff --git a/seed/go-sdk/unions-with-local-date/.fern/metadata.json b/seed/go-sdk/unions-with-local-date/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/unions-with-local-date/.fern/metadata.json +++ b/seed/go-sdk/unions-with-local-date/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/unions/no-custom-config/.fern/metadata.json b/seed/go-sdk/unions/no-custom-config/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/unions/no-custom-config/.fern/metadata.json +++ b/seed/go-sdk/unions/no-custom-config/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/unions/package-name/.fern/metadata.json b/seed/go-sdk/unions/package-name/.fern/metadata.json index e787d33f3a05..4a8193d82327 100644 --- a/seed/go-sdk/unions/package-name/.fern/metadata.json +++ b/seed/go-sdk/unions/package-name/.fern/metadata.json @@ -10,7 +10,6 @@ } }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/unions/v0/.fern/metadata.json b/seed/go-sdk/unions/v0/.fern/metadata.json index 1dc7814c35ab..103f72d27c70 100644 --- a/seed/go-sdk/unions/v0/.fern/metadata.json +++ b/seed/go-sdk/unions/v0/.fern/metadata.json @@ -11,7 +11,6 @@ "union": "v0" }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/unknown/.fern/metadata.json b/seed/go-sdk/unknown/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/unknown/.fern/metadata.json +++ b/seed/go-sdk/unknown/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/url-form-encoded/.fern/metadata.json b/seed/go-sdk/url-form-encoded/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/url-form-encoded/.fern/metadata.json +++ b/seed/go-sdk/url-form-encoded/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/validation/.fern/metadata.json b/seed/go-sdk/validation/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/validation/.fern/metadata.json +++ b/seed/go-sdk/validation/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/variables/.fern/metadata.json b/seed/go-sdk/variables/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/variables/.fern/metadata.json +++ b/seed/go-sdk/variables/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/version-no-default/.fern/metadata.json b/seed/go-sdk/version-no-default/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/version-no-default/.fern/metadata.json +++ b/seed/go-sdk/version-no-default/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/version/.fern/metadata.json b/seed/go-sdk/version/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/version/.fern/metadata.json +++ b/seed/go-sdk/version/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/webhook-audience/.fern/metadata.json b/seed/go-sdk/webhook-audience/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/webhook-audience/.fern/metadata.json +++ b/seed/go-sdk/webhook-audience/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/webhooks/.fern/metadata.json b/seed/go-sdk/webhooks/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/webhooks/.fern/metadata.json +++ b/seed/go-sdk/webhooks/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/websocket-bearer-auth/.fern/metadata.json b/seed/go-sdk/websocket-bearer-auth/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/websocket-bearer-auth/.fern/metadata.json +++ b/seed/go-sdk/websocket-bearer-auth/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/websocket-inferred-auth/.fern/metadata.json b/seed/go-sdk/websocket-inferred-auth/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/websocket-inferred-auth/.fern/metadata.json +++ b/seed/go-sdk/websocket-inferred-auth/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/websocket-multi-url/.fern/metadata.json b/seed/go-sdk/websocket-multi-url/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/websocket-multi-url/.fern/metadata.json +++ b/seed/go-sdk/websocket-multi-url/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/websocket/.fern/metadata.json b/seed/go-sdk/websocket/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/websocket/.fern/metadata.json +++ b/seed/go-sdk/websocket/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/go-sdk/x-fern-default/.fern/metadata.json b/seed/go-sdk/x-fern-default/.fern/metadata.json index e206b6bea6d5..4325dc2a3860 100644 --- a/seed/go-sdk/x-fern-default/.fern/metadata.json +++ b/seed/go-sdk/x-fern-default/.fern/metadata.json @@ -6,7 +6,6 @@ "enableWireTests": false }, "originGitCommit": "DUMMY", - "originGitCommitIsDirty": null, "invokedBy": "ci", "requestedVersion": "0.0.1", "ciProvider": "github", diff --git a/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Animal.java b/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Animal.java index 4bd68d68b653..14326affcad6 100644 --- a/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Animal.java +++ b/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Animal.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.api.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = Animal.Deserializer.class) @@ -81,13 +82,17 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public Animal deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Cat.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("fruit")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Cat.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Dog.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("fruit")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Dog.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Fruit.java b/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Fruit.java index 43876929eb25..dda5e0c72b43 100644 --- a/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Fruit.java +++ b/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Fruit.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.api.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = Fruit.Deserializer.class) @@ -81,13 +82,17 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public Fruit deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Acai.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("animal")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Acai.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Fig.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("animal")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Fig.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Node.java b/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Node.java index 9e88a939faf5..b04c62540ad9 100644 --- a/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Node.java +++ b/seed/java-sdk/circular-references-advanced/src/main/java/com/seed/api/resources/ast/types/Node.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.api.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = Node.Deserializer.class) @@ -81,9 +82,11 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public Node deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, BranchNode.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("children")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, BranchNode.class)); + } catch (RuntimeException e) { + } } try { return of(ObjectMappers.JSON_MAPPER.convertValue(value, LeafNode.class)); diff --git a/seed/java-sdk/circular-references/src/main/java/com/seed/api/resources/ast/types/TorU.java b/seed/java-sdk/circular-references/src/main/java/com/seed/api/resources/ast/types/TorU.java index caf582ab50fd..964193366e27 100644 --- a/seed/java-sdk/circular-references/src/main/java/com/seed/api/resources/ast/types/TorU.java +++ b/seed/java-sdk/circular-references/src/main/java/com/seed/api/resources/ast/types/TorU.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.api.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = TorU.Deserializer.class) @@ -81,13 +82,17 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public TorU deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, T.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("child")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, T.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, U.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("child")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, U.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/examples/default/src/main/java/com/seed/examples/resources/types/types/CastMember.java b/seed/java-sdk/examples/default/src/main/java/com/seed/examples/resources/types/types/CastMember.java index f6a429baf1bc..7239d7387562 100644 --- a/seed/java-sdk/examples/default/src/main/java/com/seed/examples/resources/types/types/CastMember.java +++ b/seed/java-sdk/examples/default/src/main/java/com/seed/examples/resources/types/types/CastMember.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.examples.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = CastMember.Deserializer.class) @@ -89,17 +90,29 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public CastMember deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("actorOrActressId")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/examples/default/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java b/seed/java-sdk/examples/default/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..c211ba7fc695 --- /dev/null +++ b/seed/java-sdk/examples/default/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.examples; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.examples.core.ObjectMappers; +import com.seed.examples.resources.types.types.Actor; +import com.seed.examples.resources.types.types.CastMember; +import com.seed.examples.resources.types.types.StuntDouble; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testCastMember_Actor() throws Exception { + String json = "{\"name\":\"test\",\"id\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof Actor, "Expected Actor but got different variant"); + } + + @Test + public void testCastMember_StuntDouble() throws Exception { + String json = "{\"name\":\"test\",\"actorOrActressId\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof StuntDouble, "Expected StuntDouble but got different variant"); + } +} diff --git a/seed/java-sdk/examples/inline-file-properties/src/main/java/com/seed/examples/resources/types/types/CastMember.java b/seed/java-sdk/examples/inline-file-properties/src/main/java/com/seed/examples/resources/types/types/CastMember.java index f6a429baf1bc..7239d7387562 100644 --- a/seed/java-sdk/examples/inline-file-properties/src/main/java/com/seed/examples/resources/types/types/CastMember.java +++ b/seed/java-sdk/examples/inline-file-properties/src/main/java/com/seed/examples/resources/types/types/CastMember.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.examples.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = CastMember.Deserializer.class) @@ -89,17 +90,29 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public CastMember deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("actorOrActressId")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/examples/inline-file-properties/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java b/seed/java-sdk/examples/inline-file-properties/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..c211ba7fc695 --- /dev/null +++ b/seed/java-sdk/examples/inline-file-properties/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.examples; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.examples.core.ObjectMappers; +import com.seed.examples.resources.types.types.Actor; +import com.seed.examples.resources.types.types.CastMember; +import com.seed.examples.resources.types.types.StuntDouble; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testCastMember_Actor() throws Exception { + String json = "{\"name\":\"test\",\"id\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof Actor, "Expected Actor but got different variant"); + } + + @Test + public void testCastMember_StuntDouble() throws Exception { + String json = "{\"name\":\"test\",\"actorOrActressId\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof StuntDouble, "Expected StuntDouble but got different variant"); + } +} diff --git a/seed/java-sdk/examples/no-custom-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java b/seed/java-sdk/examples/no-custom-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java index f6a429baf1bc..7239d7387562 100644 --- a/seed/java-sdk/examples/no-custom-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java +++ b/seed/java-sdk/examples/no-custom-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.examples.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = CastMember.Deserializer.class) @@ -89,17 +90,29 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public CastMember deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("actorOrActressId")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/examples/no-custom-config/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java b/seed/java-sdk/examples/no-custom-config/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..c211ba7fc695 --- /dev/null +++ b/seed/java-sdk/examples/no-custom-config/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.examples; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.examples.core.ObjectMappers; +import com.seed.examples.resources.types.types.Actor; +import com.seed.examples.resources.types.types.CastMember; +import com.seed.examples.resources.types.types.StuntDouble; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testCastMember_Actor() throws Exception { + String json = "{\"name\":\"test\",\"id\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof Actor, "Expected Actor but got different variant"); + } + + @Test + public void testCastMember_StuntDouble() throws Exception { + String json = "{\"name\":\"test\",\"actorOrActressId\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof StuntDouble, "Expected StuntDouble but got different variant"); + } +} diff --git a/seed/java-sdk/examples/readme-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java b/seed/java-sdk/examples/readme-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java index f6a429baf1bc..7239d7387562 100644 --- a/seed/java-sdk/examples/readme-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java +++ b/seed/java-sdk/examples/readme-config/src/main/java/com/seed/examples/resources/types/types/CastMember.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.examples.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = CastMember.Deserializer.class) @@ -89,17 +90,29 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public CastMember deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actor.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Actress.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("actorOrActressId")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, StuntDouble.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/examples/readme-config/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java b/seed/java-sdk/examples/readme-config/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..c211ba7fc695 --- /dev/null +++ b/seed/java-sdk/examples/readme-config/src/test/java/com/seed/examples/UndiscriminatedUnionTest.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.examples; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.examples.core.ObjectMappers; +import com.seed.examples.resources.types.types.Actor; +import com.seed.examples.resources.types.types.CastMember; +import com.seed.examples.resources.types.types.StuntDouble; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testCastMember_Actor() throws Exception { + String json = "{\"name\":\"test\",\"id\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof Actor, "Expected Actor but got different variant"); + } + + @Test + public void testCastMember_StuntDouble() throws Exception { + String json = "{\"name\":\"test\",\"actorOrActressId\":\"test\"}"; + CastMember union = ObjectMappers.JSON_MAPPER.readValue(json, CastMember.class); + assertTrue(union.get() instanceof StuntDouble, "Expected StuntDouble but got different variant"); + } +} diff --git a/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java b/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java index bc9c4f8f691f..4c8948db67a4 100644 --- a/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java +++ b/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java @@ -278,13 +278,22 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public Bar deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType1.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("foo") + && ((Map) value).containsKey("bar") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType1.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType2.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("baz") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType2.class)); + } catch (RuntimeException e) { + } } try { return of(ObjectMappers.JSON_MAPPER.convertValue(value, DiscriminatedUnion1.class)); @@ -313,9 +322,11 @@ public Bar deserialize(JsonParser p, DeserializationContext context) throws IOEx value, new TypeReference>() {})); } catch (RuntimeException e) { } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("foo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java b/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java index 1f5d4b8fb73a..eba7119ee426 100644 --- a/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java +++ b/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java @@ -92,13 +92,17 @@ static final class Deserializer extends StdDeserializer && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, AliasVariantType.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/test/java/com/seed/object/UndiscriminatedUnionTest.java b/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/test/java/com/seed/object/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..257f11455949 --- /dev/null +++ b/seed/java-sdk/java-inline-types/enable-forward-compatible-enums/src/test/java/com/seed/object/UndiscriminatedUnionTest.java @@ -0,0 +1,50 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.object; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.object.core.ObjectMappers; +import com.seed.object.types.AliasVariantType; +import com.seed.object.types.ReferenceType; +import com.seed.object.types.UndiscriminatedUnion1; +import com.seed.object.types.UndiscriminatedUnion1InlineType1; +import com.seed.object.types.UndiscriminatedUnion1InlineType2; +import com.seed.object.types.UndiscriminatedUnionTypeWithAliasVariant; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType1() throws Exception { + String json = "{\"foo\":\"test\",\"bar\":{},\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType1, + "Expected UndiscriminatedUnion1InlineType1 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType2() throws Exception { + String json = "{\"baz\":\"test\",\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType2, + "Expected UndiscriminatedUnion1InlineType2 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_ReferenceType() throws Exception { + String json = "{\"foo\":\"test\"}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue(union.get() instanceof ReferenceType, "Expected ReferenceType but got different variant"); + } + + @Test + public void testUndiscriminatedUnionTypeWithAliasVariant_AliasVariantType() throws Exception { + String json = "{\"prop\":\"test\"}"; + UndiscriminatedUnionTypeWithAliasVariant union = + ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnionTypeWithAliasVariant.class); + assertTrue(union.get() instanceof AliasVariantType, "Expected AliasVariantType but got different variant"); + } +} diff --git a/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java b/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java index a67843a4b48f..165f17662703 100644 --- a/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java +++ b/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java @@ -279,13 +279,22 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public Bar deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType1.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("foo") + && ((Map) value).containsKey("bar") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType1.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType2.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("baz") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType2.class)); + } catch (RuntimeException e) { + } } try { return of(ObjectMappers.JSON_MAPPER.convertValue(value, DiscriminatedUnion1.class)); @@ -314,9 +323,11 @@ public Bar deserialize(JsonParser p, DeserializationContext context) throws IOEx value, new TypeReference>() {})); } catch (RuntimeException e) { } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("foo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java b/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java index 49709dd1099c..ae057c821759 100644 --- a/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java +++ b/seed/java-sdk/java-inline-types/inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java @@ -92,13 +92,17 @@ static final class Deserializer extends StdDeserializer && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, AliasVariant.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/inline/src/test/java/com/seed/object/UndiscriminatedUnionTest.java b/seed/java-sdk/java-inline-types/inline/src/test/java/com/seed/object/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..257f11455949 --- /dev/null +++ b/seed/java-sdk/java-inline-types/inline/src/test/java/com/seed/object/UndiscriminatedUnionTest.java @@ -0,0 +1,50 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.object; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.object.core.ObjectMappers; +import com.seed.object.types.AliasVariantType; +import com.seed.object.types.ReferenceType; +import com.seed.object.types.UndiscriminatedUnion1; +import com.seed.object.types.UndiscriminatedUnion1InlineType1; +import com.seed.object.types.UndiscriminatedUnion1InlineType2; +import com.seed.object.types.UndiscriminatedUnionTypeWithAliasVariant; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType1() throws Exception { + String json = "{\"foo\":\"test\",\"bar\":{},\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType1, + "Expected UndiscriminatedUnion1InlineType1 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType2() throws Exception { + String json = "{\"baz\":\"test\",\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType2, + "Expected UndiscriminatedUnion1InlineType2 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_ReferenceType() throws Exception { + String json = "{\"foo\":\"test\"}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue(union.get() instanceof ReferenceType, "Expected ReferenceType but got different variant"); + } + + @Test + public void testUndiscriminatedUnionTypeWithAliasVariant_AliasVariantType() throws Exception { + String json = "{\"prop\":\"test\"}"; + UndiscriminatedUnionTypeWithAliasVariant union = + ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnionTypeWithAliasVariant.class); + assertTrue(union.get() instanceof AliasVariantType, "Expected AliasVariantType but got different variant"); + } +} diff --git a/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnion1.java b/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnion1.java index 828a6bd3ee60..eacda4d6307a 100644 --- a/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnion1.java +++ b/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnion1.java @@ -141,13 +141,22 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public UndiscriminatedUnion1 deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, UndiscriminatedUnion1InlineType1.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("foo") + && ((Map) value).containsKey("bar") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, UndiscriminatedUnion1InlineType1.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, UndiscriminatedUnion1InlineType2.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("baz") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, UndiscriminatedUnion1InlineType2.class)); + } catch (RuntimeException e) { + } } try { return of( @@ -177,9 +186,11 @@ public UndiscriminatedUnion1 deserialize(JsonParser p, DeserializationContext co value, new TypeReference>() {})); } catch (RuntimeException e) { } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("foo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java b/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java index 8adcc5eb6cf4..7aaca3f52143 100644 --- a/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java +++ b/seed/java-sdk/java-inline-types/no-inline/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.object.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = UndiscriminatedUnionTypeWithAliasVariant.Deserializer.class) @@ -83,13 +84,17 @@ static final class Deserializer extends StdDeserializer && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, AliasVariant.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/no-inline/src/test/java/com/seed/object/UndiscriminatedUnionTest.java b/seed/java-sdk/java-inline-types/no-inline/src/test/java/com/seed/object/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..257f11455949 --- /dev/null +++ b/seed/java-sdk/java-inline-types/no-inline/src/test/java/com/seed/object/UndiscriminatedUnionTest.java @@ -0,0 +1,50 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.object; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.object.core.ObjectMappers; +import com.seed.object.types.AliasVariantType; +import com.seed.object.types.ReferenceType; +import com.seed.object.types.UndiscriminatedUnion1; +import com.seed.object.types.UndiscriminatedUnion1InlineType1; +import com.seed.object.types.UndiscriminatedUnion1InlineType2; +import com.seed.object.types.UndiscriminatedUnionTypeWithAliasVariant; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType1() throws Exception { + String json = "{\"foo\":\"test\",\"bar\":{},\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType1, + "Expected UndiscriminatedUnion1InlineType1 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType2() throws Exception { + String json = "{\"baz\":\"test\",\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType2, + "Expected UndiscriminatedUnion1InlineType2 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_ReferenceType() throws Exception { + String json = "{\"foo\":\"test\"}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue(union.get() instanceof ReferenceType, "Expected ReferenceType but got different variant"); + } + + @Test + public void testUndiscriminatedUnionTypeWithAliasVariant_AliasVariantType() throws Exception { + String json = "{\"prop\":\"test\"}"; + UndiscriminatedUnionTypeWithAliasVariant union = + ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnionTypeWithAliasVariant.class); + assertTrue(union.get() instanceof AliasVariantType, "Expected AliasVariantType but got different variant"); + } +} diff --git a/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java b/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java index bc9c4f8f691f..4c8948db67a4 100644 --- a/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java +++ b/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/requests/GetUndiscriminatedUnionRequest.java @@ -278,13 +278,22 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public Bar deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType1.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("foo") + && ((Map) value).containsKey("bar") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType1.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType2.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("baz") + && ((Map) value).containsKey("ref")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, InlineType2.class)); + } catch (RuntimeException e) { + } } try { return of(ObjectMappers.JSON_MAPPER.convertValue(value, DiscriminatedUnion1.class)); @@ -313,9 +322,11 @@ public Bar deserialize(JsonParser p, DeserializationContext context) throws IOEx value, new TypeReference>() {})); } catch (RuntimeException e) { } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("foo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, ReferenceType.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java b/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java index 1f5d4b8fb73a..eba7119ee426 100644 --- a/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java +++ b/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/main/java/com/seed/object/types/UndiscriminatedUnionTypeWithAliasVariant.java @@ -92,13 +92,17 @@ static final class Deserializer extends StdDeserializer && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, AliasVariantType.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("prop")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, NonAliasVariant.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/test/java/com/seed/object/UndiscriminatedUnionTest.java b/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/test/java/com/seed/object/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..257f11455949 --- /dev/null +++ b/seed/java-sdk/java-inline-types/no-wrapped-aliases/src/test/java/com/seed/object/UndiscriminatedUnionTest.java @@ -0,0 +1,50 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.object; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.object.core.ObjectMappers; +import com.seed.object.types.AliasVariantType; +import com.seed.object.types.ReferenceType; +import com.seed.object.types.UndiscriminatedUnion1; +import com.seed.object.types.UndiscriminatedUnion1InlineType1; +import com.seed.object.types.UndiscriminatedUnion1InlineType2; +import com.seed.object.types.UndiscriminatedUnionTypeWithAliasVariant; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType1() throws Exception { + String json = "{\"foo\":\"test\",\"bar\":{},\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType1, + "Expected UndiscriminatedUnion1InlineType1 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_UndiscriminatedUnion1InlineType2() throws Exception { + String json = "{\"baz\":\"test\",\"ref\":{}}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue( + union.get() instanceof UndiscriminatedUnion1InlineType2, + "Expected UndiscriminatedUnion1InlineType2 but got different variant"); + } + + @Test + public void testUndiscriminatedUnion1_ReferenceType() throws Exception { + String json = "{\"foo\":\"test\"}"; + UndiscriminatedUnion1 union = ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnion1.class); + assertTrue(union.get() instanceof ReferenceType, "Expected ReferenceType but got different variant"); + } + + @Test + public void testUndiscriminatedUnionTypeWithAliasVariant_AliasVariantType() throws Exception { + String json = "{\"prop\":\"test\"}"; + UndiscriminatedUnionTypeWithAliasVariant union = + ObjectMappers.JSON_MAPPER.readValue(json, UndiscriminatedUnionTypeWithAliasVariant.class); + assertTrue(union.get() instanceof AliasVariantType, "Expected AliasVariantType but got different variant"); + } +} diff --git a/seed/python-sdk/basic-auth-pw-omitted/.fern/metadata.json b/seed/java-sdk/java-websocket-shared-discriminator/.fern/metadata.json similarity index 80% rename from seed/python-sdk/basic-auth-pw-omitted/.fern/metadata.json rename to seed/java-sdk/java-websocket-shared-discriminator/.fern/metadata.json index 0ee76b66eb30..8558dfdb1357 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/.fern/metadata.json +++ b/seed/java-sdk/java-websocket-shared-discriminator/.fern/metadata.json @@ -1,6 +1,6 @@ { "cliVersion": "DUMMY", - "generatorName": "fernapi/fern-python-sdk", + "generatorName": "fernapi/fern-java-sdk", "generatorVersion": "local", "originGitCommit": "DUMMY", "invokedBy": "ci", diff --git a/seed/java-sdk/java-websocket-shared-discriminator/.github/workflows/ci.yml b/seed/java-sdk/java-websocket-shared-discriminator/.github/workflows/ci.yml new file mode 100644 index 000000000000..09c8c666ad73 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/.github/workflows/ci.yml @@ -0,0 +1,65 @@ +name: ci + +on: [push] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + compile: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Compile + run: ./gradlew compileJava + + test: + needs: [ compile ] + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Test + run: ./gradlew test + publish: + needs: [ compile, test ] + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Java + id: setup-jre + uses: actions/setup-java@v1 + with: + java-version: "11" + architecture: x64 + + - name: Publish to maven + run: | + ./gradlew publish + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + MAVEN_PUBLISH_REGISTRY_URL: "" diff --git a/seed/java-sdk/java-websocket-shared-discriminator/.gitignore b/seed/java-sdk/java-websocket-shared-discriminator/.gitignore new file mode 100644 index 000000000000..d4199abc2cd4 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/.gitignore @@ -0,0 +1,24 @@ +*.class +.project +.gradle +? +.classpath +.checkstyle +.settings +.node +build + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Eclipse/IntelliJ APT +generated_src/ +generated_testSrc/ +generated/ + +bin +build \ No newline at end of file diff --git a/seed/java-sdk/java-websocket-shared-discriminator/build.gradle b/seed/java-sdk/java-websocket-shared-discriminator/build.gradle new file mode 100644 index 000000000000..99c049ab9c72 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/build.gradle @@ -0,0 +1,102 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'com.diffplug.spotless' version '6.11.0' +} + +repositories { + mavenCentral() + maven { + url 'https://s01.oss.sonatype.org/content/repositories/releases/' + } +} + +dependencies { + api 'com.squareup.okhttp3:okhttp:5.2.1' + api 'com.fasterxml.jackson.core:jackson-databind:2.18.6' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.6' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.6' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' +} + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +tasks.withType(Javadoc) { + failOnError false + options.addStringOption('Xdoclint:none', '-quiet') +} + +spotless { + java { + palantirJavaFormat() + } +} + + +java { + withSourcesJar() + withJavadocJar() +} + + +group = 'com.fern' + +version = '0.0.1' + +jar { + dependsOn(":generatePomFileForMavenPublication") + archiveBaseName = "java-websocket-shared-discriminator" +} + +sourcesJar { + archiveBaseName = "java-websocket-shared-discriminator" +} + +javadocJar { + archiveBaseName = "java-websocket-shared-discriminator" +} + +test { + useJUnitPlatform() + testLogging { + showStandardStreams = true + } +} + +publishing { + publications { + maven(MavenPublication) { + groupId = 'com.fern' + artifactId = 'java-websocket-shared-discriminator' + version = '0.0.1' + from components.java + pom { + licenses { + license { + name = 'The MIT License (MIT)' + url = 'https://mit-license.org/' + } + } + scm { + connection = 'scm:git:git://github.com/java-websocket-shared-discriminator/fern.git' + developerConnection = 'scm:git:git://github.com/java-websocket-shared-discriminator/fern.git' + url = 'https://github.com/java-websocket-shared-discriminator/fern' + } + } + } + } + repositories { + maven { + url "$System.env.MAVEN_PUBLISH_REGISTRY_URL" + credentials { + username "$System.env.MAVEN_USERNAME" + password "$System.env.MAVEN_PASSWORD" + } + } + } +} + diff --git a/seed/java-sdk/java-websocket-shared-discriminator/reference.md b/seed/java-sdk/java-websocket-shared-discriminator/reference.md new file mode 100644 index 000000000000..cf5aa0741655 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/reference.md @@ -0,0 +1 @@ +# Reference diff --git a/seed/java-sdk/java-websocket-shared-discriminator/sample-app/build.gradle b/seed/java-sdk/java-websocket-shared-discriminator/sample-app/build.gradle new file mode 100644 index 000000000000..4ee8f227b7af --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/sample-app/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java-library' +} + +repositories { + mavenCentral() + maven { + url 'https://s01.oss.sonatype.org/content/repositories/releases/' + } +} + +dependencies { + implementation rootProject +} + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + diff --git a/seed/java-sdk/java-websocket-shared-discriminator/sample-app/src/main/java/sample/App.java b/seed/java-sdk/java-websocket-shared-discriminator/sample-app/src/main/java/sample/App.java new file mode 100644 index 000000000000..b7bb610a0c25 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/sample-app/src/main/java/sample/App.java @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +package sample; + +import java.lang.String; + +public final class App { + public static void main(String[] args) { + // import com.seed.javaWebsocketSharedDiscriminator.AsyncSeedJavaWebsocketSharedDiscriminatorClient + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/settings.gradle b/seed/java-sdk/java-websocket-shared-discriminator/settings.gradle new file mode 100644 index 000000000000..08a6bb639c2e --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/settings.gradle @@ -0,0 +1,3 @@ +rootProject.name = 'java-websocket-shared-discriminator' + +include 'sample-app' \ No newline at end of file diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/py.typed b/seed/java-sdk/java-websocket-shared-discriminator/snippet.json similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/py.typed rename to seed/java-sdk/java-websocket-shared-discriminator/snippet.json diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/AsyncSeedJavaWebsocketSharedDiscriminatorClient.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/AsyncSeedJavaWebsocketSharedDiscriminatorClient.java new file mode 100644 index 000000000000..ccd1338d2d5b --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/AsyncSeedJavaWebsocketSharedDiscriminatorClient.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator; + +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.core.Suppliers; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.AsyncRealtimeClient; +import java.util.function.Supplier; + +public class AsyncSeedJavaWebsocketSharedDiscriminatorClient { + protected final ClientOptions clientOptions; + + protected final Supplier realtimeClient; + + public AsyncSeedJavaWebsocketSharedDiscriminatorClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.realtimeClient = Suppliers.memoize(() -> new AsyncRealtimeClient(clientOptions)); + } + + public AsyncRealtimeClient realtime() { + return this.realtimeClient.get(); + } + + public static AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder builder() { + return new AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder(); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder.java new file mode 100644 index 000000000000..0820184c26b8 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder.java @@ -0,0 +1,189 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator; + +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.core.Environment; +import com.seed.javaWebsocketSharedDiscriminator.core.LogConfig; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import okhttp3.OkHttpClient; + +public class AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder { + private Optional timeout = Optional.empty(); + + private Optional maxRetries = Optional.empty(); + + private final Map customHeaders = new HashMap<>(); + + private Environment environment; + + private OkHttpClient httpClient; + + private Optional logging = Optional.empty(); + + public AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + /** + * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. + */ + public AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder timeout(int timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + /** + * Sets the maximum number of retries for the client. Defaults to 2 retries. + */ + public AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder maxRetries(int maxRetries) { + this.maxRetries = Optional.of(maxRetries); + return this; + } + + /** + * Sets the underlying OkHttp client + */ + public AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder httpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder logging(LogConfig logging) { + this.logging = Optional.of(logging); + return this; + } + + /** + * Add a custom header to be sent with all requests. + * For headers that need to be computed dynamically or conditionally, use the setAdditional() method override instead. + * + * @param name The header name + * @param value The header value + * @return This builder for method chaining + */ + public AsyncSeedJavaWebsocketSharedDiscriminatorClientBuilder addHeader(String name, String value) { + this.customHeaders.put(name, value); + return this; + } + + protected ClientOptions buildClientOptions() { + ClientOptions.Builder builder = ClientOptions.builder(); + setEnvironment(builder); + setHttpClient(builder); + setTimeouts(builder); + setRetries(builder); + setLogging(builder); + for (Map.Entry header : this.customHeaders.entrySet()) { + builder.addHeader(header.getKey(), header.getValue()); + } + setAdditional(builder); + return builder.build(); + } + + /** + * Sets the environment configuration for the client. + * Override this method to modify URLs or add environment-specific logic. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setEnvironment(ClientOptions.Builder builder) { + builder.environment(this.environment); + } + + /** + * Sets the request timeout configuration. + * Override this method to customize timeout behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setTimeouts(ClientOptions.Builder builder) { + if (this.timeout.isPresent()) { + builder.timeout(this.timeout.get()); + } + } + + /** + * Sets the retry configuration for failed requests. + * Override this method to implement custom retry strategies. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setRetries(ClientOptions.Builder builder) { + if (this.maxRetries.isPresent()) { + builder.maxRetries(this.maxRetries.get()); + } + } + + /** + * Sets the OkHttp client configuration. + * Override this method to customize HTTP client behavior (interceptors, connection pools, etc). + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setHttpClient(ClientOptions.Builder builder) { + if (this.httpClient != null) { + builder.httpClient(this.httpClient); + } + } + + /** + * Sets the logging configuration for the SDK. + * Override this method to customize logging behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setLogging(ClientOptions.Builder builder) { + if (this.logging.isPresent()) { + builder.logging(this.logging.get()); + } + } + + /** + * Override this method to add any additional configuration to the client. + * This method is called at the end of the configuration chain, allowing you to add + * custom headers, modify settings, or perform any other client customization. + * + * @param builder The ClientOptions.Builder to configure + * + * Example: + *
{@code
+     * @Override
+     * protected void setAdditional(ClientOptions.Builder builder) {
+     *     builder.addHeader("X-Request-ID", () -> UUID.randomUUID().toString());
+     *     builder.addHeader("X-Client-Version", "1.0.0");
+     * }
+     * }
+ */ + protected void setAdditional(ClientOptions.Builder builder) {} + + /** + * Override this method to add custom validation logic before the client is built. + * This method is called at the beginning of the build() method to ensure the configuration is valid. + * Throw an exception to prevent client creation if validation fails. + * + * Example: + *
{@code
+     * @Override
+     * protected void validateConfiguration() {
+     *     super.validateConfiguration(); // Run parent validations
+     *     if (tenantId == null || tenantId.isEmpty()) {
+     *         throw new IllegalStateException("tenantId is required");
+     *     }
+     * }
+     * }
+ */ + protected void validateConfiguration() {} + + public AsyncSeedJavaWebsocketSharedDiscriminatorClient build() { + validateConfiguration(); + return new AsyncSeedJavaWebsocketSharedDiscriminatorClient(buildClientOptions()); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/SeedJavaWebsocketSharedDiscriminatorClient.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/SeedJavaWebsocketSharedDiscriminatorClient.java new file mode 100644 index 000000000000..e54c2ef91b55 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/SeedJavaWebsocketSharedDiscriminatorClient.java @@ -0,0 +1,28 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator; + +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.core.Suppliers; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.RealtimeClient; +import java.util.function.Supplier; + +public class SeedJavaWebsocketSharedDiscriminatorClient { + protected final ClientOptions clientOptions; + + protected final Supplier realtimeClient; + + public SeedJavaWebsocketSharedDiscriminatorClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.realtimeClient = Suppliers.memoize(() -> new RealtimeClient(clientOptions)); + } + + public RealtimeClient realtime() { + return this.realtimeClient.get(); + } + + public static SeedJavaWebsocketSharedDiscriminatorClientBuilder builder() { + return new SeedJavaWebsocketSharedDiscriminatorClientBuilder(); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/SeedJavaWebsocketSharedDiscriminatorClientBuilder.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/SeedJavaWebsocketSharedDiscriminatorClientBuilder.java new file mode 100644 index 000000000000..53988f1f197e --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/SeedJavaWebsocketSharedDiscriminatorClientBuilder.java @@ -0,0 +1,189 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator; + +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.core.Environment; +import com.seed.javaWebsocketSharedDiscriminator.core.LogConfig; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import okhttp3.OkHttpClient; + +public class SeedJavaWebsocketSharedDiscriminatorClientBuilder { + private Optional timeout = Optional.empty(); + + private Optional maxRetries = Optional.empty(); + + private final Map customHeaders = new HashMap<>(); + + private Environment environment; + + private OkHttpClient httpClient; + + private Optional logging = Optional.empty(); + + public SeedJavaWebsocketSharedDiscriminatorClientBuilder url(String url) { + this.environment = Environment.custom(url); + return this; + } + + /** + * Sets the timeout (in seconds) for the client. Defaults to 60 seconds. + */ + public SeedJavaWebsocketSharedDiscriminatorClientBuilder timeout(int timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + /** + * Sets the maximum number of retries for the client. Defaults to 2 retries. + */ + public SeedJavaWebsocketSharedDiscriminatorClientBuilder maxRetries(int maxRetries) { + this.maxRetries = Optional.of(maxRetries); + return this; + } + + /** + * Sets the underlying OkHttp client + */ + public SeedJavaWebsocketSharedDiscriminatorClientBuilder httpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public SeedJavaWebsocketSharedDiscriminatorClientBuilder logging(LogConfig logging) { + this.logging = Optional.of(logging); + return this; + } + + /** + * Add a custom header to be sent with all requests. + * For headers that need to be computed dynamically or conditionally, use the setAdditional() method override instead. + * + * @param name The header name + * @param value The header value + * @return This builder for method chaining + */ + public SeedJavaWebsocketSharedDiscriminatorClientBuilder addHeader(String name, String value) { + this.customHeaders.put(name, value); + return this; + } + + protected ClientOptions buildClientOptions() { + ClientOptions.Builder builder = ClientOptions.builder(); + setEnvironment(builder); + setHttpClient(builder); + setTimeouts(builder); + setRetries(builder); + setLogging(builder); + for (Map.Entry header : this.customHeaders.entrySet()) { + builder.addHeader(header.getKey(), header.getValue()); + } + setAdditional(builder); + return builder.build(); + } + + /** + * Sets the environment configuration for the client. + * Override this method to modify URLs or add environment-specific logic. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setEnvironment(ClientOptions.Builder builder) { + builder.environment(this.environment); + } + + /** + * Sets the request timeout configuration. + * Override this method to customize timeout behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setTimeouts(ClientOptions.Builder builder) { + if (this.timeout.isPresent()) { + builder.timeout(this.timeout.get()); + } + } + + /** + * Sets the retry configuration for failed requests. + * Override this method to implement custom retry strategies. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setRetries(ClientOptions.Builder builder) { + if (this.maxRetries.isPresent()) { + builder.maxRetries(this.maxRetries.get()); + } + } + + /** + * Sets the OkHttp client configuration. + * Override this method to customize HTTP client behavior (interceptors, connection pools, etc). + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setHttpClient(ClientOptions.Builder builder) { + if (this.httpClient != null) { + builder.httpClient(this.httpClient); + } + } + + /** + * Sets the logging configuration for the SDK. + * Override this method to customize logging behavior. + * + * @param builder The ClientOptions.Builder to configure + */ + protected void setLogging(ClientOptions.Builder builder) { + if (this.logging.isPresent()) { + builder.logging(this.logging.get()); + } + } + + /** + * Override this method to add any additional configuration to the client. + * This method is called at the end of the configuration chain, allowing you to add + * custom headers, modify settings, or perform any other client customization. + * + * @param builder The ClientOptions.Builder to configure + * + * Example: + *
{@code
+     * @Override
+     * protected void setAdditional(ClientOptions.Builder builder) {
+     *     builder.addHeader("X-Request-ID", () -> UUID.randomUUID().toString());
+     *     builder.addHeader("X-Client-Version", "1.0.0");
+     * }
+     * }
+ */ + protected void setAdditional(ClientOptions.Builder builder) {} + + /** + * Override this method to add custom validation logic before the client is built. + * This method is called at the beginning of the build() method to ensure the configuration is valid. + * Throw an exception to prevent client creation if validation fails. + * + * Example: + *
{@code
+     * @Override
+     * protected void validateConfiguration() {
+     *     super.validateConfiguration(); // Run parent validations
+     *     if (tenantId == null || tenantId.isEmpty()) {
+     *         throw new IllegalStateException("tenantId is required");
+     *     }
+     * }
+     * }
+ */ + protected void validateConfiguration() {} + + public SeedJavaWebsocketSharedDiscriminatorClient build() { + validateConfiguration(); + return new SeedJavaWebsocketSharedDiscriminatorClient(buildClientOptions()); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ClientOptions.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ClientOptions.java new file mode 100644 index 000000000000..4649515e91b4 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ClientOptions.java @@ -0,0 +1,240 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import okhttp3.OkHttpClient; + +public final class ClientOptions { + private final Environment environment; + + private final Map headers; + + private final Map> headerSuppliers; + + private final OkHttpClient httpClient; + + private final int timeout; + + private final int maxRetries; + + private final Optional webSocketFactory; + + private final Optional logging; + + private ClientOptions( + Environment environment, + Map headers, + Map> headerSuppliers, + OkHttpClient httpClient, + int timeout, + int maxRetries, + Optional webSocketFactory, + Optional logging) { + this.environment = environment; + this.headers = new HashMap<>(); + this.headers.putAll(headers); + this.headers.putAll(new HashMap() { + { + put("User-Agent", "com.fern:java-websocket-shared-discriminator/0.0.1"); + put("X-Fern-Language", "JAVA"); + put("X-Fern-SDK-Name", "com.seed.fern:java-websocket-shared-discriminator-sdk"); + } + }); + this.headerSuppliers = headerSuppliers; + this.httpClient = httpClient; + this.timeout = timeout; + this.maxRetries = maxRetries; + this.webSocketFactory = webSocketFactory; + this.logging = logging; + } + + public Environment environment() { + return this.environment; + } + + public Map headers(RequestOptions requestOptions) { + Map values = new HashMap<>(this.headers); + headerSuppliers.forEach((key, supplier) -> { + values.put(key, supplier.get()); + }); + if (requestOptions != null) { + values.putAll(requestOptions.getHeaders()); + } + return values; + } + + public int timeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.timeout; + } + return requestOptions.getTimeout().orElse(this.timeout); + } + + public OkHttpClient httpClient() { + return this.httpClient; + } + + public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) { + if (requestOptions == null) { + return this.httpClient; + } + return this.httpClient + .newBuilder() + .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit()) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .build(); + } + + public int maxRetries() { + return this.maxRetries; + } + + public Optional webSocketFactory() { + return this.webSocketFactory; + } + + public Optional logging() { + return this.logging; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Environment environment; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + private int maxRetries = 2; + + private Optional timeout = Optional.empty(); + + private OkHttpClient httpClient = null; + + private Optional logging = Optional.empty(); + + private Optional webSocketFactory = Optional.empty(); + + public Builder environment(Environment environment) { + this.environment = environment; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(int timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + /** + * Override the timeout in seconds. Defaults to 60 seconds. + */ + public Builder timeout(Optional timeout) { + this.timeout = timeout; + return this; + } + + /** + * Override the maximum number of retries. Defaults to 2 retries. + */ + public Builder maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public Builder httpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Set a custom WebSocketFactory for creating WebSocket connections. + */ + public Builder webSocketFactory(WebSocketFactory webSocketFactory) { + this.webSocketFactory = Optional.of(webSocketFactory); + return this; + } + + /** + * Configure logging for the SDK. Silent by default — no log output unless explicitly configured. + */ + public Builder logging(LogConfig logging) { + this.logging = Optional.of(logging); + return this; + } + + public ClientOptions build() { + OkHttpClient.Builder httpClientBuilder = + this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder(); + + if (this.httpClient != null) { + timeout.ifPresent(timeout -> httpClientBuilder + .callTimeout(timeout, TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS)); + } else { + httpClientBuilder + .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS) + .connectTimeout(0, TimeUnit.SECONDS) + .writeTimeout(0, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.SECONDS) + .addInterceptor(new RetryInterceptor(this.maxRetries)); + } + + Logger logger = Logger.from(this.logging); + httpClientBuilder.addInterceptor(new LoggingInterceptor(logger)); + + this.httpClient = httpClientBuilder.build(); + this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000); + + return new ClientOptions( + environment, + headers, + headerSuppliers, + httpClient, + this.timeout.get(), + this.maxRetries, + this.webSocketFactory, + this.logging); + } + + /** + * Create a new Builder initialized with values from an existing ClientOptions + */ + public static Builder from(ClientOptions clientOptions) { + Builder builder = new Builder(); + builder.environment = clientOptions.environment(); + builder.timeout = Optional.of(clientOptions.timeout(null)); + builder.httpClient = clientOptions.httpClient(); + builder.headers.putAll(clientOptions.headers); + builder.headerSuppliers.putAll(clientOptions.headerSuppliers); + builder.maxRetries = clientOptions.maxRetries(); + builder.logging = clientOptions.logging(); + return builder; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ConsoleLogger.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ConsoleLogger.java new file mode 100644 index 000000000000..cc4e07eda88b --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ConsoleLogger.java @@ -0,0 +1,51 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.logging.Level; + +/** + * Default logger implementation that writes to the console using {@link java.util.logging.Logger}. + * + *

Uses the "fern" logger name with a simple format of "LEVEL - message". + */ +public final class ConsoleLogger implements ILogger { + + private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger("fern"); + + static { + if (logger.getHandlers().length == 0) { + java.util.logging.ConsoleHandler handler = new java.util.logging.ConsoleHandler(); + handler.setFormatter(new java.util.logging.SimpleFormatter() { + @Override + public String format(java.util.logging.LogRecord record) { + return record.getLevel() + " - " + record.getMessage() + System.lineSeparator(); + } + }); + logger.addHandler(handler); + logger.setUseParentHandlers(false); + logger.setLevel(Level.ALL); + } + } + + @Override + public void debug(String message) { + logger.log(Level.FINE, message); + } + + @Override + public void info(String message) { + logger.log(Level.INFO, message); + } + + @Override + public void warn(String message) { + logger.log(Level.WARNING, message); + } + + @Override + public void error(String message) { + logger.log(Level.SEVERE, message); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DateTimeDeserializer.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DateTimeDeserializer.java new file mode 100644 index 000000000000..733f8f2ffe79 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DateTimeDeserializer.java @@ -0,0 +1,55 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalQueries; + +/** + * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects. + */ +class DateTimeDeserializer extends JsonDeserializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer()); + } + + /** + * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + JsonToken token = parser.currentToken(); + if (token == JsonToken.VALUE_NUMBER_INT) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC); + } else { + TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest( + parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from); + + if (temporal.query(TemporalQueries.offset()) == null) { + return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC); + } else { + return OffsetDateTime.from(temporal); + } + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DisconnectReason.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DisconnectReason.java new file mode 100644 index 000000000000..3ba8ce431aa7 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DisconnectReason.java @@ -0,0 +1,26 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * Reason for WebSocket disconnection. + */ +public class DisconnectReason { + private final int code; + + private final String reason; + + public DisconnectReason(int code, String reason) { + this.code = code; + this.reason = reason; + } + + public int getCode() { + return code; + } + + public String getReason() { + return reason; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DoubleSerializer.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DoubleSerializer.java new file mode 100644 index 000000000000..6c295a234357 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/DoubleSerializer.java @@ -0,0 +1,43 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; + +/** + * Custom serializer that writes integer-valued doubles without a decimal point. + * For example, {@code 24000.0} is serialized as {@code 24000} instead of {@code 24000.0}. + * Non-integer values like {@code 3.14} are serialized normally. + */ +class DoubleSerializer extends JsonSerializer { + private static final SimpleModule MODULE; + + static { + MODULE = new SimpleModule() + .addSerializer(Double.class, new DoubleSerializer()) + .addSerializer(double.class, new DoubleSerializer()); + } + + /** + * Gets a module wrapping this serializer as an adapter for the Jackson ObjectMapper. + * + * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper. + */ + public static SimpleModule getModule() { + return MODULE; + } + + @Override + public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value != null && value == Math.floor(value) && !Double.isInfinite(value) && !Double.isNaN(value)) { + gen.writeNumber(value.longValue()); + } else { + gen.writeNumber(value); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Environment.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Environment.java new file mode 100644 index 000000000000..2f4c74dcf6d0 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Environment.java @@ -0,0 +1,20 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +public final class Environment { + private final String url; + + private Environment(String url) { + this.url = url; + } + + public String getUrl() { + return this.url; + } + + public static Environment custom(String url) { + return new Environment(url); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/FileStream.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/FileStream.java new file mode 100644 index 000000000000..0c0dfc7a7459 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/FileStream.java @@ -0,0 +1,60 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.InputStream; +import java.util.Objects; +import okhttp3.MediaType; +import okhttp3.RequestBody; +import org.jetbrains.annotations.Nullable; + +/** + * Represents a file stream with associated metadata for file uploads. + */ +public class FileStream { + private final InputStream inputStream; + private final String fileName; + private final MediaType contentType; + + /** + * Constructs a FileStream with the given input stream and optional metadata. + * + * @param inputStream The input stream of the file content. Must not be null. + * @param fileName The name of the file, or null if unknown. + * @param contentType The MIME type of the file content, or null if unknown. + * @throws NullPointerException if inputStream is null + */ + public FileStream(InputStream inputStream, @Nullable String fileName, @Nullable MediaType contentType) { + this.inputStream = Objects.requireNonNull(inputStream, "Input stream cannot be null"); + this.fileName = fileName; + this.contentType = contentType; + } + + public FileStream(InputStream inputStream) { + this(inputStream, null, null); + } + + public InputStream getInputStream() { + return inputStream; + } + + @Nullable + public String getFileName() { + return fileName; + } + + @Nullable + public MediaType getContentType() { + return contentType; + } + + /** + * Creates a RequestBody suitable for use with OkHttp client. + * + * @return A RequestBody instance representing this file stream. + */ + public RequestBody toRequestBody() { + return new InputStreamRequestBody(contentType, inputStream); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ILogger.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ILogger.java new file mode 100644 index 000000000000..751e7f1fee6f --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ILogger.java @@ -0,0 +1,38 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * Interface for custom logger implementations. + * + *

Implement this interface to provide a custom logging backend for the SDK. + * The SDK will call the appropriate method based on the log level. + * + *

Example: + *

{@code
+ * public class MyCustomLogger implements ILogger {
+ *     public void debug(String message) {
+ *         System.out.println("[DBG] " + message);
+ *     }
+ *     public void info(String message) {
+ *         System.out.println("[INF] " + message);
+ *     }
+ *     public void warn(String message) {
+ *         System.out.println("[WRN] " + message);
+ *     }
+ *     public void error(String message) {
+ *         System.out.println("[ERR] " + message);
+ *     }
+ * }
+ * }
+ */ +public interface ILogger { + void debug(String message); + + void info(String message); + + void warn(String message); + + void error(String message); +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/InputStreamRequestBody.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/InputStreamRequestBody.java new file mode 100644 index 000000000000..0beaa1ed1432 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/InputStreamRequestBody.java @@ -0,0 +1,74 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okio.BufferedSink; +import okio.Okio; +import okio.Source; +import org.jetbrains.annotations.Nullable; + +/** + * A custom implementation of OkHttp's RequestBody that wraps an InputStream. + * This class allows streaming of data from an InputStream directly to an HTTP request body, + * which is useful for file uploads or sending large amounts of data without loading it all into memory. + */ +public class InputStreamRequestBody extends RequestBody { + private final InputStream inputStream; + private final MediaType contentType; + + /** + * Constructs an InputStreamRequestBody with the specified content type and input stream. + * + * @param contentType the MediaType of the content, or null if not known + * @param inputStream the InputStream containing the data to be sent + * @throws NullPointerException if inputStream is null + */ + public InputStreamRequestBody(@Nullable MediaType contentType, InputStream inputStream) { + this.contentType = contentType; + this.inputStream = Objects.requireNonNull(inputStream, "inputStream == null"); + } + + /** + * Returns the content type of this request body. + * + * @return the MediaType of the content, or null if not specified + */ + @Nullable + @Override + public MediaType contentType() { + return contentType; + } + + /** + * Returns the content length of this request body, if known. + * This method attempts to determine the length using the InputStream's available() method, + * which may not always accurately reflect the total length of the stream. + * + * @return the content length, or -1 if the length is unknown + * @throws IOException if an I/O error occurs + */ + @Override + public long contentLength() throws IOException { + return inputStream.available() == 0 ? -1 : inputStream.available(); + } + + /** + * Writes the content of the InputStream to the given BufferedSink. + * This method is responsible for transferring the data from the InputStream to the network request. + * + * @param sink the BufferedSink to write the content to + * @throws IOException if an I/O error occurs during writing + */ + @Override + public void writeTo(BufferedSink sink) throws IOException { + try (Source source = Okio.source(inputStream)) { + sink.writeAll(source); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LogConfig.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LogConfig.java new file mode 100644 index 000000000000..152b56ab0369 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LogConfig.java @@ -0,0 +1,98 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * Configuration for SDK logging. + * + *

Use the builder to configure logging behavior: + *

{@code
+ * LogConfig config = LogConfig.builder()
+ *     .level(LogLevel.DEBUG)
+ *     .silent(false)
+ *     .build();
+ * }
+ * + *

Or with a custom logger: + *

{@code
+ * LogConfig config = LogConfig.builder()
+ *     .level(LogLevel.DEBUG)
+ *     .logger(new MyCustomLogger())
+ *     .silent(false)
+ *     .build();
+ * }
+ * + *

Defaults: + *

    + *
  • {@code level} — {@link LogLevel#INFO}
  • + *
  • {@code logger} — {@link ConsoleLogger} (writes to stderr via java.util.logging)
  • + *
  • {@code silent} — {@code true} (no output unless explicitly enabled)
  • + *
+ */ +public final class LogConfig { + + private final LogLevel level; + private final ILogger logger; + private final boolean silent; + + private LogConfig(LogLevel level, ILogger logger, boolean silent) { + this.level = level; + this.logger = logger; + this.silent = silent; + } + + public LogLevel level() { + return level; + } + + public ILogger logger() { + return logger; + } + + public boolean silent() { + return silent; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private LogLevel level = LogLevel.INFO; + private ILogger logger = new ConsoleLogger(); + private boolean silent = true; + + private Builder() {} + + /** + * Set the minimum log level. Only messages at this level or above will be logged. + * Defaults to {@link LogLevel#INFO}. + */ + public Builder level(LogLevel level) { + this.level = level; + return this; + } + + /** + * Set a custom logger implementation. Defaults to {@link ConsoleLogger}. + */ + public Builder logger(ILogger logger) { + this.logger = logger; + return this; + } + + /** + * Set whether logging is silent (disabled). Defaults to {@code true}. + * Set to {@code false} to enable log output. + */ + public Builder silent(boolean silent) { + this.silent = silent; + return this; + } + + public LogConfig build() { + return new LogConfig(level, logger, silent); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LogLevel.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LogLevel.java new file mode 100644 index 000000000000..cfcba427663e --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LogLevel.java @@ -0,0 +1,36 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * Log levels for SDK logging configuration. + * Silent by default — no log output unless explicitly configured. + */ +public enum LogLevel { + DEBUG(1), + INFO(2), + WARN(3), + ERROR(4); + + private final int value; + + LogLevel(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + /** + * Parse a log level from a string (case-insensitive). + * + * @param level the level string (debug, info, warn, error) + * @return the corresponding LogLevel + * @throws IllegalArgumentException if the string does not match any level + */ + public static LogLevel fromString(String level) { + return LogLevel.valueOf(level.toUpperCase()); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Logger.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Logger.java new file mode 100644 index 000000000000..796f61c12303 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Logger.java @@ -0,0 +1,97 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * SDK logger that filters messages based on level and silent mode. + * + *

Silent by default — no log output unless explicitly configured. + * Create via {@link LogConfig} or directly: + *

{@code
+ * Logger logger = new Logger(LogLevel.DEBUG, new ConsoleLogger(), false);
+ * logger.debug("request sent");
+ * }
+ */ +public final class Logger { + + private static final Logger DEFAULT = new Logger(LogLevel.INFO, new ConsoleLogger(), true); + + private final LogLevel level; + private final ILogger logger; + private final boolean silent; + + public Logger(LogLevel level, ILogger logger, boolean silent) { + this.level = level; + this.logger = logger; + this.silent = silent; + } + + /** + * Returns a default silent logger (no output). + */ + public static Logger getDefault() { + return DEFAULT; + } + + /** + * Creates a Logger from a {@link LogConfig}. If config is {@code null}, returns the default silent logger. + */ + public static Logger from(LogConfig config) { + if (config == null) { + return DEFAULT; + } + return new Logger(config.level(), config.logger(), config.silent()); + } + + /** + * Creates a Logger from an {@code Optional}. If empty, returns the default silent logger. + */ + public static Logger from(java.util.Optional config) { + return config.map(Logger::from).orElse(DEFAULT); + } + + private boolean shouldLog(LogLevel messageLevel) { + return !silent && level.getValue() <= messageLevel.getValue(); + } + + public boolean isDebug() { + return shouldLog(LogLevel.DEBUG); + } + + public boolean isInfo() { + return shouldLog(LogLevel.INFO); + } + + public boolean isWarn() { + return shouldLog(LogLevel.WARN); + } + + public boolean isError() { + return shouldLog(LogLevel.ERROR); + } + + public void debug(String message) { + if (isDebug()) { + logger.debug(message); + } + } + + public void info(String message) { + if (isInfo()) { + logger.info(message); + } + } + + public void warn(String message) { + if (isWarn()) { + logger.warn(message); + } + } + + public void error(String message) { + if (isError()) { + logger.error(message); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LoggingInterceptor.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LoggingInterceptor.java new file mode 100644 index 000000000000..8ef6a1c7e270 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/LoggingInterceptor.java @@ -0,0 +1,104 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +/** + * OkHttp interceptor that logs HTTP requests and responses. + * + *

Logs request method, URL, and headers (with sensitive values redacted) at debug level. + * Logs response status at debug level, and 4xx/5xx responses at error level. + * Does nothing if the logger is silent. + */ +public final class LoggingInterceptor implements Interceptor { + + private static final Set SENSITIVE_HEADERS = new HashSet<>(Arrays.asList( + "authorization", + "www-authenticate", + "x-api-key", + "api-key", + "apikey", + "x-api-token", + "x-auth-token", + "auth-token", + "proxy-authenticate", + "proxy-authorization", + "cookie", + "set-cookie", + "x-csrf-token", + "x-xsrf-token", + "x-session-token", + "x-access-token")); + + private final Logger logger; + + public LoggingInterceptor(Logger logger) { + this.logger = logger; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + if (logger.isDebug()) { + StringBuilder sb = new StringBuilder(); + sb.append("HTTP Request: ").append(request.method()).append(" ").append(request.url()); + sb.append(" headers={"); + boolean first = true; + for (String name : request.headers().names()) { + if (!first) { + sb.append(", "); + } + sb.append(name).append("="); + if (SENSITIVE_HEADERS.contains(name.toLowerCase())) { + sb.append("[REDACTED]"); + } else { + sb.append(request.header(name)); + } + first = false; + } + sb.append("}"); + sb.append(" has_body=").append(request.body() != null); + logger.debug(sb.toString()); + } + + Response response = chain.proceed(request); + + if (logger.isDebug()) { + StringBuilder sb = new StringBuilder(); + sb.append("HTTP Response: status=").append(response.code()); + sb.append(" url=").append(response.request().url()); + sb.append(" headers={"); + boolean first = true; + for (String name : response.headers().names()) { + if (!first) { + sb.append(", "); + } + sb.append(name).append("="); + if (SENSITIVE_HEADERS.contains(name.toLowerCase())) { + sb.append("[REDACTED]"); + } else { + sb.append(response.header(name)); + } + first = false; + } + sb.append("}"); + logger.debug(sb.toString()); + } + + if (response.code() >= 400 && logger.isError()) { + logger.error("HTTP Error: status=" + response.code() + " url=" + + response.request().url()); + } + + return response; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/MediaTypes.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/MediaTypes.java new file mode 100644 index 000000000000..92f5e97a67d1 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/MediaTypes.java @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import okhttp3.MediaType; + +public final class MediaTypes { + + public static final MediaType APPLICATION_JSON = MediaType.parse("application/json"); + + private MediaTypes() {} +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Nullable.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Nullable.java new file mode 100644 index 000000000000..b0884e1cf526 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Nullable.java @@ -0,0 +1,140 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.Optional; +import java.util.function.Function; + +public final class Nullable { + + private final Either, Null> value; + + private Nullable() { + this.value = Either.left(Optional.empty()); + } + + private Nullable(T value) { + if (value == null) { + this.value = Either.right(Null.INSTANCE); + } else { + this.value = Either.left(Optional.of(value)); + } + } + + public static Nullable ofNull() { + return new Nullable<>(null); + } + + public static Nullable of(T value) { + return new Nullable<>(value); + } + + public static Nullable empty() { + return new Nullable<>(); + } + + public static Nullable ofOptional(Optional value) { + if (value.isPresent()) { + return of(value.get()); + } else { + return empty(); + } + } + + public boolean isNull() { + return this.value.isRight(); + } + + public boolean isEmpty() { + return this.value.isLeft() && !this.value.getLeft().isPresent(); + } + + public T get() { + if (this.isNull()) { + return null; + } + + return this.value.getLeft().get(); + } + + public Nullable map(Function mapper) { + if (this.isNull()) { + return Nullable.ofNull(); + } + + return Nullable.ofOptional(this.value.getLeft().map(mapper)); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Nullable)) { + return false; + } + + if (((Nullable) other).isNull() && this.isNull()) { + return true; + } + + return this.value.getLeft().equals(((Nullable) other).value.getLeft()); + } + + private static final class Either { + private L left = null; + private R right = null; + + private Either(L left, R right) { + if (left != null && right != null) { + throw new IllegalArgumentException("Left and right argument cannot both be non-null."); + } + + if (left == null && right == null) { + throw new IllegalArgumentException("Left and right argument cannot both be null."); + } + + if (left != null) { + this.left = left; + } + + if (right != null) { + this.right = right; + } + } + + public static Either left(L left) { + return new Either<>(left, null); + } + + public static Either right(R right) { + return new Either<>(null, right); + } + + public boolean isLeft() { + return this.left != null; + } + + public boolean isRight() { + return this.right != null; + } + + public L getLeft() { + if (!this.isLeft()) { + throw new IllegalArgumentException("Cannot get left from right Either."); + } + return this.left; + } + + public R getRight() { + if (!this.isRight()) { + throw new IllegalArgumentException("Cannot get right from left Either."); + } + return this.right; + } + } + + private static final class Null { + private static final Null INSTANCE = new Null(); + + private Null() {} + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/NullableNonemptyFilter.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/NullableNonemptyFilter.java new file mode 100644 index 000000000000..197763bb06b0 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/NullableNonemptyFilter.java @@ -0,0 +1,22 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.Optional; + +public final class NullableNonemptyFilter { + @Override + public boolean equals(Object o) { + boolean isOptionalEmpty = isOptionalEmpty(o); + + return isOptionalEmpty; + } + + private boolean isOptionalEmpty(Object o) { + if (o instanceof Optional) { + return !((Optional) o).isPresent(); + } + return false; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ObjectMappers.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ObjectMappers.java new file mode 100644 index 000000000000..bda2de28cfb7 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ObjectMappers.java @@ -0,0 +1,46 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.io.IOException; + +public final class ObjectMappers { + public static final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .addModule(DateTimeDeserializer.getModule()) + .addModule(DoubleSerializer.getModule()) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + private ObjectMappers() {} + + public static String stringify(Object o) { + try { + return JSON_MAPPER + .setSerializationInclusion(JsonInclude.Include.ALWAYS) + .writerWithDefaultPrettyPrinter() + .writeValueAsString(o); + } catch (IOException e) { + return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode()); + } + } + + public static Object parseErrorBody(String responseBodyString) { + try { + return JSON_MAPPER.readValue(responseBodyString, Object.class); + } catch (JsonProcessingException ignored) { + return responseBodyString; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/OkHttpWebSocketFactory.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/OkHttpWebSocketFactory.java new file mode 100644 index 000000000000..6d34b0d775e6 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/OkHttpWebSocketFactory.java @@ -0,0 +1,31 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; + +/** + * Default WebSocketFactory implementation using OkHttpClient. + * This factory delegates WebSocket creation to the provided OkHttpClient instance. + */ +public final class OkHttpWebSocketFactory implements WebSocketFactory { + private final OkHttpClient okHttpClient; + + /** + * Creates a new OkHttpWebSocketFactory with the specified OkHttpClient. + * + * @param okHttpClient The OkHttpClient instance to use for creating WebSockets + */ + public OkHttpWebSocketFactory(OkHttpClient okHttpClient) { + this.okHttpClient = okHttpClient; + } + + @Override + public WebSocket create(Request request, WebSocketListener listener) { + return okHttpClient.newWebSocket(request, listener); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/QueryStringMapper.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/QueryStringMapper.java new file mode 100644 index 000000000000..6bbe04ea1e84 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/QueryStringMapper.java @@ -0,0 +1,142 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import okhttp3.HttpUrl; +import okhttp3.MultipartBody; + +public class QueryStringMapper { + + private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER; + + public static void addQueryParameter(HttpUrl.Builder httpUrl, String key, Object value, boolean arraysAsRepeats) { + JsonNode valueNode = MAPPER.valueToTree(value); + + List> flat; + if (valueNode.isObject()) { + flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats); + } else if (valueNode.isArray()) { + flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats); + } else { + if (valueNode.isTextual()) { + httpUrl.addQueryParameter(key, valueNode.textValue()); + } else { + httpUrl.addQueryParameter(key, valueNode.toString()); + } + return; + } + + for (Map.Entry field : flat) { + if (field.getValue().isTextual()) { + httpUrl.addQueryParameter(key + field.getKey(), field.getValue().textValue()); + } else { + httpUrl.addQueryParameter(key + field.getKey(), field.getValue().toString()); + } + } + } + + public static void addFormDataPart( + MultipartBody.Builder multipartBody, String key, Object value, boolean arraysAsRepeats) { + JsonNode valueNode = MAPPER.valueToTree(value); + + List> flat; + if (valueNode.isObject()) { + flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats); + } else if (valueNode.isArray()) { + flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats); + } else { + if (valueNode.isTextual()) { + multipartBody.addFormDataPart(key, valueNode.textValue()); + } else { + multipartBody.addFormDataPart(key, valueNode.toString()); + } + return; + } + + for (Map.Entry field : flat) { + if (field.getValue().isTextual()) { + multipartBody.addFormDataPart( + key + field.getKey(), field.getValue().textValue()); + } else { + multipartBody.addFormDataPart( + key + field.getKey(), field.getValue().toString()); + } + } + } + + public static List> flattenObject(ObjectNode object, boolean arraysAsRepeats) { + List> flat = new ArrayList<>(); + + Iterator> fields = object.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + + String key = "[" + field.getKey() + "]"; + + if (field.getValue().isObject()) { + List> flatField = + flattenObject((ObjectNode) field.getValue(), arraysAsRepeats); + addAll(flat, flatField, key); + } else if (field.getValue().isArray()) { + List> flatField = + flattenArray((ArrayNode) field.getValue(), key, arraysAsRepeats); + addAll(flat, flatField, ""); + } else { + flat.add(new AbstractMap.SimpleEntry<>(key, field.getValue())); + } + } + + return flat; + } + + private static List> flattenArray( + ArrayNode array, String key, boolean arraysAsRepeats) { + List> flat = new ArrayList<>(); + + Iterator elements = array.elements(); + + int index = 0; + while (elements.hasNext()) { + JsonNode element = elements.next(); + + String indexKey = key + "[" + index + "]"; + + if (arraysAsRepeats) { + indexKey = key; + } + + if (element.isObject()) { + List> flatField = flattenObject((ObjectNode) element, arraysAsRepeats); + addAll(flat, flatField, indexKey); + } else if (element.isArray()) { + List> flatField = flattenArray((ArrayNode) element, "", arraysAsRepeats); + addAll(flat, flatField, indexKey); + } else { + flat.add(new AbstractMap.SimpleEntry<>(indexKey, element)); + } + + index++; + } + + return flat; + } + + private static void addAll( + List> target, List> source, String prefix) { + for (Map.Entry entry : source) { + Map.Entry entryToAdd = + new AbstractMap.SimpleEntry<>(prefix + entry.getKey(), entry.getValue()); + target.add(entryToAdd); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ReconnectingWebSocketListener.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ReconnectingWebSocketListener.java new file mode 100644 index 000000000000..dcd320814aa8 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ReconnectingWebSocketListener.java @@ -0,0 +1,494 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import static java.util.concurrent.TimeUnit.*; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okio.ByteString; + +/** + * WebSocketListener with automatic reconnection, exponential backoff, and message queuing. + * Provides production-ready resilience for WebSocket connections. + */ +public abstract class ReconnectingWebSocketListener extends WebSocketListener { + private final long minReconnectionDelayMs; + + private final long maxReconnectionDelayMs; + + private final double reconnectionDelayGrowFactor; + + private final int maxRetries; + + private final int maxEnqueuedMessages; + + private final AtomicInteger retryCount = new AtomicInteger(0); + + private final AtomicBoolean connectLock = new AtomicBoolean(false); + + private final AtomicBoolean shouldReconnect = new AtomicBoolean(true); + + protected volatile WebSocket webSocket; + + private volatile long connectionEstablishedTime = 0L; + + private final ConcurrentLinkedQueue messageQueue = new ConcurrentLinkedQueue<>(); + + private final ConcurrentLinkedQueue binaryMessageQueue = new ConcurrentLinkedQueue<>(); + + private final ScheduledExecutorService reconnectExecutor = Executors.newSingleThreadScheduledExecutor(); + + private final Supplier connectionSupplier; + + /** + * Creates a new reconnecting WebSocket listener. + * + * @param options Reconnection configuration options + * @param connectionSupplier Supplier that creates new WebSocket connections + */ + public ReconnectingWebSocketListener( + ReconnectingWebSocketListener.ReconnectOptions options, Supplier connectionSupplier) { + this.minReconnectionDelayMs = options.minReconnectionDelayMs; + this.maxReconnectionDelayMs = options.maxReconnectionDelayMs; + this.reconnectionDelayGrowFactor = options.reconnectionDelayGrowFactor; + this.maxRetries = options.maxRetries; + this.maxEnqueuedMessages = options.maxEnqueuedMessages; + this.connectionSupplier = connectionSupplier; + } + + /** + * Initiates a WebSocket connection with automatic reconnection enabled. + * + * Connection behavior: + * - Times out after 4000 milliseconds + * - Thread-safe via atomic lock (returns immediately if connection in progress) + * - Retry count not incremented for initial connection attempt + * + * Error handling: + * - TimeoutException: Includes retry attempt context + * - InterruptedException: Preserves thread interruption status + * - ExecutionException: Extracts actual cause and adds context + */ + public void connect() { + if (!connectLock.compareAndSet(false, true)) { + return; + } + if (retryCount.get() >= maxRetries) { + connectLock.set(false); + return; + } + try { + CompletableFuture connectionFuture = CompletableFuture.supplyAsync(connectionSupplier); + try { + webSocket = connectionFuture.get(4000, MILLISECONDS); + } catch (TimeoutException e) { + connectionFuture.cancel(true); + TimeoutException timeoutError = + new TimeoutException("WebSocket connection timeout after " + 4000 + " milliseconds" + + (retryCount.get() > 0 + ? " (retry attempt #" + retryCount.get() + : " (initial connection attempt)")); + onWebSocketFailure(null, timeoutError, null); + if (shouldReconnect.get()) { + scheduleReconnect(); + } + } catch (InterruptedException e) { + connectionFuture.cancel(true); + Thread.currentThread().interrupt(); + InterruptedException interruptError = new InterruptedException("WebSocket connection interrupted" + + (retryCount.get() > 0 + ? " during retry attempt #" + retryCount.get() + : " during initial connection")); + interruptError.initCause(e); + onWebSocketFailure(null, interruptError, null); + } catch (ExecutionException e) { + Throwable cause = e.getCause() != null ? e.getCause() : e; + String context = retryCount.get() > 0 + ? "WebSocket connection failed during retry attempt #" + retryCount.get() + : "WebSocket connection failed during initial attempt"; + RuntimeException wrappedException = new RuntimeException( + context + ": " + cause.getClass().getSimpleName() + ": " + cause.getMessage()); + wrappedException.initCause(cause); + onWebSocketFailure(null, wrappedException, null); + if (shouldReconnect.get()) { + scheduleReconnect(); + } + } + } finally { + connectLock.set(false); + } + } + + /** + * Disconnects the WebSocket and disables automatic reconnection. + * + * This method: + * - Disables automatic reconnection + * - Clears queued messages to prevent stale data + * - Closes the WebSocket with standard close code 1000 + * - Properly shuts down the reconnect executor to prevent thread leaks + * - Waits up to 5 seconds for executor termination + */ + public void disconnect() { + shouldReconnect.set(false); + messageQueue.clear(); + binaryMessageQueue.clear(); + if (webSocket != null) { + webSocket.close(1000, "Client disconnecting"); + } + reconnectExecutor.shutdown(); + try { + if (!reconnectExecutor.awaitTermination(5, SECONDS)) { + reconnectExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + reconnectExecutor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + /** + * Sends a message or queues it if not connected. + * + * Thread-safe: Synchronized to prevent race conditions with flushMessageQueue(). + * + * Behavior: + * - If connected: Attempts direct send, queues if buffer full + * - If disconnected: Queues message up to maxEnqueuedMessages limit + * - If queue full: Message is dropped + * + * @param message The message to send + * @return true if sent immediately, false if queued or dropped + */ + public synchronized boolean send(String message) { + WebSocket ws = webSocket; + if (ws != null) { + boolean sent = ws.send(message); + if (!sent && messageQueue.size() < maxEnqueuedMessages) { + messageQueue.offer(message); + return false; + } + return sent; + } else { + if (messageQueue.size() < maxEnqueuedMessages) { + messageQueue.offer(message); + return false; + } + return false; + } + } + + /** + * Sends binary data or queues it if not connected. + * + * Thread-safe: Synchronized to prevent race conditions with flushMessageQueue(). + * + * Behavior: + * - If connected: Attempts direct send, queues if buffer full + * - If disconnected: Queues data up to maxEnqueuedMessages limit + * - If queue full: Data is dropped + * + * @param data The binary data to send + * @return true if sent immediately, false if queued or dropped + */ + public synchronized boolean sendBinary(ByteString data) { + WebSocket ws = webSocket; + if (ws != null) { + boolean sent = ws.send(data); + if (!sent && binaryMessageQueue.size() < maxEnqueuedMessages) { + binaryMessageQueue.offer(data); + return false; + } + return sent; + } else { + if (binaryMessageQueue.size() < maxEnqueuedMessages) { + binaryMessageQueue.offer(data); + return false; + } + return false; + } + } + + /** + * Gets the current WebSocket instance. + * Thread-safe method to access the WebSocket connection. + * @return the WebSocket or null if not connected + */ + public WebSocket getWebSocket() { + return webSocket; + } + + /** + * @hidden + */ + @Override + public void onOpen(WebSocket webSocket, Response response) { + this.webSocket = webSocket; + connectionEstablishedTime = System.currentTimeMillis(); + retryCount.set(0); + flushMessageQueue(); + onWebSocketOpen(webSocket, response); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + onWebSocketMessage(webSocket, text); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + onWebSocketBinaryMessage(webSocket, bytes); + } + + /** + * @hidden + */ + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + this.webSocket = null; + long uptime = 0L; + if (connectionEstablishedTime > 0) { + uptime = System.currentTimeMillis() - connectionEstablishedTime; + if (uptime >= 5000) { + retryCount.set(0); + } + } + connectionEstablishedTime = 0L; + Throwable enhancedError = t; + if (t != null) { + String errorContext = "WebSocket connection failed"; + if (uptime > 0) { + errorContext += " after " + (uptime / 1000) + " seconds"; + } + if (response != null) { + errorContext += " with HTTP " + response.code() + " " + response.message(); + } + enhancedError = + new RuntimeException(errorContext + ": " + t.getClass().getSimpleName() + ": " + t.getMessage()); + enhancedError.initCause(t); + } + onWebSocketFailure(webSocket, enhancedError, response); + if (shouldReconnect.get()) { + scheduleReconnect(); + } + } + + /** + * @hidden + */ + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + this.webSocket = null; + if (connectionEstablishedTime > 0) { + long uptime = System.currentTimeMillis() - connectionEstablishedTime; + if (uptime >= 5000) { + retryCount.set(0); + } + } + connectionEstablishedTime = 0L; + onWebSocketClosed(webSocket, code, reason); + if (code != 1000 && shouldReconnect.get()) { + scheduleReconnect(); + } + } + + /** + * Calculates the next reconnection delay using exponential backoff. + * + * Uses 0-based retry count where: + * - 0 = initial connection (not used by this method) + * - 1 = first retry (returns minReconnectionDelayMs) + * - 2+ = exponential backoff up to maxReconnectionDelayMs + */ + private long getNextDelay() { + if (retryCount.get() == 1) { + return minReconnectionDelayMs; + } + long delay = (long) (minReconnectionDelayMs * Math.pow(reconnectionDelayGrowFactor, retryCount.get() - 1)); + return Math.min(delay, maxReconnectionDelayMs); + } + + /** + * Schedules a reconnection attempt with appropriate delay. + * Increments retry count and uses exponential backoff. + */ + private void scheduleReconnect() { + retryCount.incrementAndGet(); + long delay = getNextDelay(); + reconnectExecutor.schedule(this::connect, delay, MILLISECONDS); + } + + /** + * Sends all queued messages after reconnection. + * + * Thread-safe: Synchronized to prevent race conditions with send() method. + * + * Algorithm: + * 1. Drains queue into temporary list to avoid holding lock during sends + * 2. Attempts to send each message in order + * 3. If any send fails, re-queues that message and all subsequent messages + * 4. Preserves message ordering during re-queueing + * 5. Repeats for binary message queue + */ + private synchronized void flushMessageQueue() { + WebSocket ws = webSocket; + if (ws != null) { + ArrayList tempQueue = new ArrayList<>(); + String message; + while ((message = messageQueue.poll()) != null) { + tempQueue.add(message); + } + for (int i = 0; i < tempQueue.size(); i++) { + if (!ws.send(tempQueue.get(i))) { + for (int j = i; j < tempQueue.size(); j++) { + messageQueue.offer(tempQueue.get(j)); + } + break; + } + } + ArrayList tempBinaryQueue = new ArrayList<>(); + ByteString binaryMsg; + while ((binaryMsg = binaryMessageQueue.poll()) != null) { + tempBinaryQueue.add(binaryMsg); + } + for (int i = 0; i < tempBinaryQueue.size(); i++) { + if (!ws.send(tempBinaryQueue.get(i))) { + for (int j = i; j < tempBinaryQueue.size(); j++) { + binaryMessageQueue.offer(tempBinaryQueue.get(j)); + } + break; + } + } + } + } + + protected abstract void onWebSocketOpen(WebSocket webSocket, Response response); + + protected abstract void onWebSocketMessage(WebSocket webSocket, String text); + + protected abstract void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes); + + protected abstract void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response); + + protected abstract void onWebSocketClosed(WebSocket webSocket, int code, String reason); + + /** + * Configuration options for automatic reconnection. + */ + public static final class ReconnectOptions { + public final long minReconnectionDelayMs; + + public final long maxReconnectionDelayMs; + + public final double reconnectionDelayGrowFactor; + + public final int maxRetries; + + public final int maxEnqueuedMessages; + + private ReconnectOptions(Builder builder) { + this.minReconnectionDelayMs = builder.minReconnectionDelayMs; + this.maxReconnectionDelayMs = builder.maxReconnectionDelayMs; + this.reconnectionDelayGrowFactor = builder.reconnectionDelayGrowFactor; + this.maxRetries = builder.maxRetries; + this.maxEnqueuedMessages = builder.maxEnqueuedMessages; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private long minReconnectionDelayMs; + + private long maxReconnectionDelayMs; + + private double reconnectionDelayGrowFactor; + + private int maxRetries; + + private int maxEnqueuedMessages; + + public Builder() { + this.minReconnectionDelayMs = 1000; + this.maxReconnectionDelayMs = 10000; + this.reconnectionDelayGrowFactor = 1.3; + this.maxRetries = 2147483647; + this.maxEnqueuedMessages = 1000; + } + + public Builder minReconnectionDelayMs(long minReconnectionDelayMs) { + this.minReconnectionDelayMs = minReconnectionDelayMs; + return this; + } + + public Builder maxReconnectionDelayMs(long maxReconnectionDelayMs) { + this.maxReconnectionDelayMs = maxReconnectionDelayMs; + return this; + } + + public Builder reconnectionDelayGrowFactor(double reconnectionDelayGrowFactor) { + this.reconnectionDelayGrowFactor = reconnectionDelayGrowFactor; + return this; + } + + public Builder maxRetries(int maxRetries) { + this.maxRetries = maxRetries; + return this; + } + + public Builder maxEnqueuedMessages(int maxEnqueuedMessages) { + this.maxEnqueuedMessages = maxEnqueuedMessages; + return this; + } + + /** + * Builds the ReconnectOptions with validation. + * + * Validates that: + * - All delay values are positive + * - minReconnectionDelayMs <= maxReconnectionDelayMs + * - reconnectionDelayGrowFactor >= 1.0 + * - maxRetries and maxEnqueuedMessages are non-negative + * + * @return The validated ReconnectOptions instance + * @throws IllegalArgumentException if configuration is invalid + */ + public ReconnectOptions build() { + if (minReconnectionDelayMs <= 0) { + throw new IllegalArgumentException("minReconnectionDelayMs must be positive"); + } + if (maxReconnectionDelayMs <= 0) { + throw new IllegalArgumentException("maxReconnectionDelayMs must be positive"); + } + if (minReconnectionDelayMs > maxReconnectionDelayMs) { + throw new IllegalArgumentException("minReconnectionDelayMs (" + minReconnectionDelayMs + + ") must not exceed maxReconnectionDelayMs (" + maxReconnectionDelayMs + ")"); + } + if (reconnectionDelayGrowFactor < 1.0) { + throw new IllegalArgumentException("reconnectionDelayGrowFactor must be >= 1.0"); + } + if (maxRetries < 0) { + throw new IllegalArgumentException("maxRetries must be non-negative"); + } + if (maxEnqueuedMessages < 0) { + throw new IllegalArgumentException("maxEnqueuedMessages must be non-negative"); + } + return new ReconnectOptions(this); + } + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/RequestOptions.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/RequestOptions.java new file mode 100644 index 000000000000..6201b03887ed --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/RequestOptions.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public final class RequestOptions { + private final Optional timeout; + + private final TimeUnit timeoutTimeUnit; + + private final Map headers; + + private final Map> headerSuppliers; + + private final Map queryParameters; + + private final Map> queryParameterSuppliers; + + private RequestOptions( + Optional timeout, + TimeUnit timeoutTimeUnit, + Map headers, + Map> headerSuppliers, + Map queryParameters, + Map> queryParameterSuppliers) { + this.timeout = timeout; + this.timeoutTimeUnit = timeoutTimeUnit; + this.headers = headers; + this.headerSuppliers = headerSuppliers; + this.queryParameters = queryParameters; + this.queryParameterSuppliers = queryParameterSuppliers; + } + + public Optional getTimeout() { + return timeout; + } + + public TimeUnit getTimeoutTimeUnit() { + return timeoutTimeUnit; + } + + public Map getHeaders() { + Map headers = new HashMap<>(); + headers.putAll(this.headers); + this.headerSuppliers.forEach((key, supplier) -> { + headers.put(key, supplier.get()); + }); + return headers; + } + + public Map getQueryParameters() { + Map queryParameters = new HashMap<>(this.queryParameters); + this.queryParameterSuppliers.forEach((key, supplier) -> { + queryParameters.put(key, supplier.get()); + }); + return queryParameters; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Optional timeout = Optional.empty(); + + private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS; + + private final Map headers = new HashMap<>(); + + private final Map> headerSuppliers = new HashMap<>(); + + private final Map queryParameters = new HashMap<>(); + + private final Map> queryParameterSuppliers = new HashMap<>(); + + public Builder timeout(Integer timeout) { + this.timeout = Optional.of(timeout); + return this; + } + + public Builder timeout(Integer timeout, TimeUnit timeoutTimeUnit) { + this.timeout = Optional.of(timeout); + this.timeoutTimeUnit = timeoutTimeUnit; + return this; + } + + public Builder addHeader(String key, String value) { + this.headers.put(key, value); + return this; + } + + public Builder addHeader(String key, Supplier value) { + this.headerSuppliers.put(key, value); + return this; + } + + public Builder addQueryParameter(String key, String value) { + this.queryParameters.put(key, value); + return this; + } + + public Builder addQueryParameter(String key, Supplier value) { + this.queryParameterSuppliers.put(key, value); + return this; + } + + public RequestOptions build() { + return new RequestOptions( + timeout, timeoutTimeUnit, headers, headerSuppliers, queryParameters, queryParameterSuppliers); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ResponseBodyInputStream.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ResponseBodyInputStream.java new file mode 100644 index 000000000000..9a43a0d06aca --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ResponseBodyInputStream.java @@ -0,0 +1,45 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.FilterInputStream; +import java.io.IOException; +import okhttp3.Response; + +/** + * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the + * OkHttp Response object is properly closed when the stream is closed. + * + * This class extends FilterInputStream and takes an OkHttp Response object as a parameter. + * It retrieves the InputStream from the Response and overrides the close method to close + * both the InputStream and the Response object, ensuring proper resource management and preventing + * premature closure of the underlying HTTP connection. + */ +public class ResponseBodyInputStream extends FilterInputStream { + private final Response response; + + /** + * Constructs a ResponseBodyInputStream that wraps the InputStream from the given OkHttp + * Response object. + * + * @param response the OkHttp Response object from which the InputStream is retrieved + * @throws IOException if an I/O error occurs while retrieving the InputStream + */ + public ResponseBodyInputStream(Response response) throws IOException { + super(response.body().byteStream()); + this.response = response; + } + + /** + * Closes the InputStream and the associated OkHttp Response object. This ensures that the + * underlying HTTP connection is properly closed after the stream is no longer needed. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + response.close(); // Ensure the response is closed when the stream is closed + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ResponseBodyReader.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ResponseBodyReader.java new file mode 100644 index 000000000000..2e30c36d4065 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/ResponseBodyReader.java @@ -0,0 +1,44 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.FilterReader; +import java.io.IOException; +import okhttp3.Response; + +/** + * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the + * OkHttp Response object is properly closed when the reader is closed. + * + * This class extends FilterReader and takes an OkHttp Response object as a parameter. + * It retrieves the Reader from the Response and overrides the close method to close + * both the Reader and the Response object, ensuring proper resource management and preventing + * premature closure of the underlying HTTP connection. + */ +public class ResponseBodyReader extends FilterReader { + private final Response response; + + /** + * Constructs a ResponseBodyReader that wraps the Reader from the given OkHttp Response object. + * + * @param response the OkHttp Response object from which the Reader is retrieved + * @throws IOException if an I/O error occurs while retrieving the Reader + */ + public ResponseBodyReader(Response response) throws IOException { + super(response.body().charStream()); + this.response = response; + } + + /** + * Closes the Reader and the associated OkHttp Response object. This ensures that the + * underlying HTTP connection is properly closed after the reader is no longer needed. + * + * @throws IOException if an I/O error occurs + */ + @Override + public void close() throws IOException { + super.close(); + response.close(); // Ensure the response is closed when the reader is closed + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/RetryInterceptor.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/RetryInterceptor.java new file mode 100644 index 000000000000..92aaf8970c78 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/RetryInterceptor.java @@ -0,0 +1,181 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.IOException; +import java.time.Duration; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Optional; +import java.util.Random; +import okhttp3.Interceptor; +import okhttp3.Response; + +public class RetryInterceptor implements Interceptor { + + private static final Duration INITIAL_RETRY_DELAY = Duration.ofMillis(1000); + private static final Duration MAX_RETRY_DELAY = Duration.ofMillis(60000); + private static final double JITTER_FACTOR = 0.2; + + private final int maxRetries; + private final Random random = new Random(); + + public RetryInterceptor(int maxRetries) { + this.maxRetries = maxRetries; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Response response = chain.proceed(chain.request()); + + if (shouldRetry(response.code())) { + return retryChain(response, chain); + } + + return response; + } + + private Response retryChain(Response response, Chain chain) throws IOException { + ExponentialBackoff backoff = new ExponentialBackoff(this.maxRetries); + Optional nextBackoff = backoff.nextBackoff(response); + while (nextBackoff.isPresent()) { + try { + Thread.sleep(nextBackoff.get().toMillis()); + } catch (InterruptedException e) { + throw new IOException("Interrupted while trying request", e); + } + response.close(); + response = chain.proceed(chain.request()); + if (shouldRetry(response.code())) { + nextBackoff = backoff.nextBackoff(response); + } else { + return response; + } + } + + return response; + } + + /** + * Calculates the retry delay from response headers, with fallback to exponential backoff. + * Priority: Retry-After > X-RateLimit-Reset > Exponential Backoff + */ + private Duration getRetryDelayFromHeaders(Response response, int retryAttempt) { + // Check for Retry-After header first (RFC 7231), with no jitter + String retryAfter = response.header("Retry-After"); + if (retryAfter != null) { + // Parse as number of seconds... + Optional secondsDelay = tryParseLong(retryAfter) + .map(seconds -> seconds * 1000) + .filter(delayMs -> delayMs > 0) + .map(delayMs -> Math.min(delayMs, MAX_RETRY_DELAY.toMillis())) + .map(Duration::ofMillis); + if (secondsDelay.isPresent()) { + return secondsDelay.get(); + } + + // ...or as an HTTP date; both are valid + Optional dateDelay = tryParseHttpDate(retryAfter) + .map(resetTime -> resetTime.toInstant().toEpochMilli() - System.currentTimeMillis()) + .filter(delayMs -> delayMs > 0) + .map(delayMs -> Math.min(delayMs, MAX_RETRY_DELAY.toMillis())) + .map(Duration::ofMillis); + if (dateDelay.isPresent()) { + return dateDelay.get(); + } + } + + // Then check for industry-standard X-RateLimit-Reset header, with positive jitter + String rateLimitReset = response.header("X-RateLimit-Reset"); + if (rateLimitReset != null) { + // Assume Unix timestamp in epoch seconds + Optional rateLimitDelay = tryParseLong(rateLimitReset) + .map(resetTimeSeconds -> (resetTimeSeconds * 1000) - System.currentTimeMillis()) + .filter(delayMs -> delayMs > 0) + .map(delayMs -> Math.min(delayMs, MAX_RETRY_DELAY.toMillis())) + .map(this::addPositiveJitter) + .map(Duration::ofMillis); + if (rateLimitDelay.isPresent()) { + return rateLimitDelay.get(); + } + } + + // Fall back to exponential backoff, with symmetric jitter + long baseDelay = INITIAL_RETRY_DELAY.toMillis() * (1L << retryAttempt); // 2^retryAttempt + long cappedDelay = Math.min(baseDelay, MAX_RETRY_DELAY.toMillis()); + return Duration.ofMillis(addSymmetricJitter(cappedDelay)); + } + + /** + * Attempts to parse a string as a long, returning empty Optional on failure. + */ + private Optional tryParseLong(String value) { + if (value == null) { + return Optional.empty(); + } + try { + return Optional.of(Long.parseLong(value)); + } catch (NumberFormatException e) { + return Optional.empty(); + } + } + + /** + * Attempts to parse a string as an HTTP date (RFC 1123), returning empty Optional on failure. + */ + private Optional tryParseHttpDate(String value) { + if (value == null) { + return Optional.empty(); + } + try { + return Optional.of(ZonedDateTime.parse(value, DateTimeFormatter.RFC_1123_DATE_TIME)); + } catch (DateTimeParseException e) { + return Optional.empty(); + } + } + + /** + * Adds positive jitter (100-120% of original value) to prevent thundering herd. + * Used for X-RateLimit-Reset header delays. + */ + private long addPositiveJitter(long delayMs) { + double jitterMultiplier = 1.0 + (random.nextDouble() * JITTER_FACTOR); + return (long) (delayMs * jitterMultiplier); + } + + /** + * Adds symmetric jitter (90-110% of original value) to prevent thundering herd. + * Used for exponential backoff delays. + */ + private long addSymmetricJitter(long delayMs) { + double jitterMultiplier = 1.0 + ((random.nextDouble() - 0.5) * JITTER_FACTOR); + return (long) (delayMs * jitterMultiplier); + } + + private static boolean shouldRetry(int statusCode) { + return statusCode == 408 || statusCode == 429 || statusCode >= 500; + } + + private final class ExponentialBackoff { + + private final int maxNumRetries; + + private int retryNumber = 0; + + ExponentialBackoff(int maxNumRetries) { + this.maxNumRetries = maxNumRetries; + } + + public Optional nextBackoff(Response response) { + if (retryNumber >= maxNumRetries) { + return Optional.empty(); + } + + Duration delay = getRetryDelayFromHeaders(response, retryNumber); + retryNumber += 1; + return Optional.of(delay); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Rfc2822DateTimeDeserializer.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Rfc2822DateTimeDeserializer.java new file mode 100644 index 000000000000..684981f1f381 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Rfc2822DateTimeDeserializer.java @@ -0,0 +1,25 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Custom deserializer that handles converting RFC 2822 (RFC 1123) dates into {@link OffsetDateTime} objects. + * This is used for fields with format "date-time-rfc-2822", such as Twilio's dateCreated, dateSent, dateUpdated. + */ +public class Rfc2822DateTimeDeserializer extends JsonDeserializer { + + @Override + public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { + String raw = parser.getValueAsString(); + return ZonedDateTime.parse(raw, DateTimeFormatter.RFC_1123_DATE_TIME).toOffsetDateTime(); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorApiException.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorApiException.java new file mode 100644 index 000000000000..5b00fc47a294 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorApiException.java @@ -0,0 +1,74 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import okhttp3.Response; + +/** + * This exception type will be thrown for any non-2XX API responses. + */ +public class SeedJavaWebsocketSharedDiscriminatorApiException extends SeedJavaWebsocketSharedDiscriminatorException { + /** + * The error code of the response that triggered the exception. + */ + private final int statusCode; + + /** + * The body of the response that triggered the exception. + */ + private final Object body; + + private final Map> headers; + + public SeedJavaWebsocketSharedDiscriminatorApiException(String message, int statusCode, Object body) { + super(message); + this.statusCode = statusCode; + this.body = body; + this.headers = new HashMap<>(); + } + + public SeedJavaWebsocketSharedDiscriminatorApiException( + String message, int statusCode, Object body, Response rawResponse) { + super(message); + this.statusCode = statusCode; + this.body = body; + this.headers = new HashMap<>(); + rawResponse.headers().forEach(header -> { + String key = header.component1(); + String value = header.component2(); + this.headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value); + }); + } + + /** + * @return the statusCode + */ + public int statusCode() { + return this.statusCode; + } + + /** + * @return the body + */ + public Object body() { + return this.body; + } + + /** + * @return the headers + */ + public Map> headers() { + return this.headers; + } + + @Override + public String toString() { + return "SeedJavaWebsocketSharedDiscriminatorApiException{" + "message: " + getMessage() + ", statusCode: " + + statusCode + ", body: " + ObjectMappers.stringify(body) + "}"; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorException.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorException.java new file mode 100644 index 000000000000..11874455b681 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorException.java @@ -0,0 +1,17 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * This class serves as the base exception for all errors in the SDK. + */ +public class SeedJavaWebsocketSharedDiscriminatorException extends RuntimeException { + public SeedJavaWebsocketSharedDiscriminatorException(String message) { + super(message); + } + + public SeedJavaWebsocketSharedDiscriminatorException(String message, Exception e) { + super(message, e); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorHttpResponse.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorHttpResponse.java new file mode 100644 index 000000000000..6700a779873e --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SeedJavaWebsocketSharedDiscriminatorHttpResponse.java @@ -0,0 +1,37 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import okhttp3.Response; + +public final class SeedJavaWebsocketSharedDiscriminatorHttpResponse { + + private final T body; + + private final Map> headers; + + public SeedJavaWebsocketSharedDiscriminatorHttpResponse(T body, Response rawResponse) { + this.body = body; + + Map> headers = new HashMap<>(); + rawResponse.headers().forEach(header -> { + String key = header.component1(); + String value = header.component2(); + headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value); + }); + this.headers = headers; + } + + public T body() { + return this.body; + } + + public Map> headers() { + return headers; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SseEvent.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SseEvent.java new file mode 100644 index 000000000000..118d6c6c5e69 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SseEvent.java @@ -0,0 +1,114 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Objects; +import java.util.Optional; + +/** + * Represents a Server-Sent Event with all standard fields. + * Used for event-level discrimination where the discriminator is at the SSE envelope level. + * + * @param The type of the data field + */ +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonIgnoreProperties(ignoreUnknown = true) +public final class SseEvent { + private final String event; + private final T data; + private final String id; + private final Long retry; + + private SseEvent(String event, T data, String id, Long retry) { + this.event = event; + this.data = data; + this.id = id; + this.retry = retry; + } + + @JsonProperty("event") + public Optional getEvent() { + return Optional.ofNullable(event); + } + + @JsonProperty("data") + public T getData() { + return data; + } + + @JsonProperty("id") + public Optional getId() { + return Optional.ofNullable(id); + } + + @JsonProperty("retry") + public Optional getRetry() { + return Optional.ofNullable(retry); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SseEvent sseEvent = (SseEvent) o; + return Objects.equals(event, sseEvent.event) + && Objects.equals(data, sseEvent.data) + && Objects.equals(id, sseEvent.id) + && Objects.equals(retry, sseEvent.retry); + } + + @Override + public int hashCode() { + return Objects.hash(event, data, id, retry); + } + + @Override + public String toString() { + return "SseEvent{" + "event='" + + event + '\'' + ", data=" + + data + ", id='" + + id + '\'' + ", retry=" + + retry + '}'; + } + + public static Builder builder() { + return new Builder<>(); + } + + public static final class Builder { + private String event; + private T data; + private String id; + private Long retry; + + private Builder() {} + + public Builder event(String event) { + this.event = event; + return this; + } + + public Builder data(T data) { + this.data = data; + return this; + } + + public Builder id(String id) { + this.id = id; + return this; + } + + public Builder retry(Long retry) { + this.retry = retry; + return this; + } + + public SseEvent build() { + return new SseEvent<>(event, data, id, retry); + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SseEventParser.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SseEventParser.java new file mode 100644 index 000000000000..d51418ac3503 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/SseEventParser.java @@ -0,0 +1,228 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.core.type.TypeReference; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Utility class for parsing Server-Sent Events with support for discriminated unions. + *

+ * Handles two discrimination patterns: + *

    + *
  1. Data-level discrimination: The discriminator (e.g., 'type') is inside the JSON data payload. + * Jackson's polymorphic deserialization handles this automatically.
  2. + *
  3. Event-level discrimination: The discriminator (e.g., 'event') is at the SSE envelope level. + * This requires constructing the full SSE envelope for Jackson to process.
  4. + *
+ */ +public final class SseEventParser { + + private static final Set SSE_ENVELOPE_FIELDS = new HashSet<>(Arrays.asList("event", "data", "id", "retry")); + + private SseEventParser() { + // Utility class + } + + /** + * Parse an SSE event using event-level discrimination. + *

+ * Constructs the full SSE envelope object with event, data, id, and retry fields, + * then deserializes it to the target union type. + * + * @param eventType The SSE event type (from event: field) + * @param data The SSE data content (from data: field) + * @param id The SSE event ID (from id: field), may be null + * @param retry The SSE retry value (from retry: field), may be null + * @param unionClass The target union class + * @param discriminatorProperty The property name used for discrimination (e.g., "event") + * @param The target type + * @return The deserialized object + */ + public static T parseEventLevelUnion( + String eventType, String data, String id, Long retry, Class unionClass, String discriminatorProperty) { + try { + // Determine if data should be parsed as JSON based on the variant's expected type + Object parsedData = parseDataForVariant(eventType, data, unionClass, discriminatorProperty); + + // Construct the SSE envelope object + Map envelope = new HashMap<>(); + envelope.put(discriminatorProperty, eventType); + envelope.put("data", parsedData); + if (id != null) { + envelope.put("id", id); + } + if (retry != null) { + envelope.put("retry", retry); + } + + // Serialize to JSON and deserialize to target type + String envelopeJson = ObjectMappers.JSON_MAPPER.writeValueAsString(envelope); + return ObjectMappers.JSON_MAPPER.readValue(envelopeJson, unionClass); + } catch (Exception e) { + throw new RuntimeException("Failed to parse SSE event with event-level discrimination", e); + } + } + + /** + * Parse an SSE event using data-level discrimination. + *

+ * Simply parses the data field as JSON and deserializes it to the target type. + * Jackson's polymorphic deserialization handles the discrimination automatically. + * + * @param data The SSE data content (from data: field) + * @param valueType The target type + * @param The target type + * @return The deserialized object + */ + public static T parseDataLevelUnion(String data, Class valueType) { + try { + return ObjectMappers.JSON_MAPPER.readValue(data, valueType); + } catch (Exception e) { + throw new RuntimeException("Failed to parse SSE data with data-level discrimination", e); + } + } + + /** + * Determines if the given discriminator property indicates event-level discrimination. + * Event-level discrimination occurs when the discriminator is an SSE envelope field. + * + * @param discriminatorProperty The discriminator property name + * @return true if event-level discrimination, false otherwise + */ + public static boolean isEventLevelDiscrimination(String discriminatorProperty) { + return SSE_ENVELOPE_FIELDS.contains(discriminatorProperty); + } + + /** + * Attempts to find the discriminator property from the union class's Jackson annotations. + * + * @param unionClass The union class to inspect + * @return The discriminator property name, or empty if not found + */ + public static Optional findDiscriminatorProperty(Class unionClass) { + try { + // Look for JsonTypeInfo on the class itself + JsonTypeInfo typeInfo = unionClass.getAnnotation(JsonTypeInfo.class); + if (typeInfo != null && !typeInfo.property().isEmpty()) { + return Optional.of(typeInfo.property()); + } + + // Look for inner Value interface with JsonTypeInfo + for (Class innerClass : unionClass.getDeclaredClasses()) { + typeInfo = innerClass.getAnnotation(JsonTypeInfo.class); + if (typeInfo != null && !typeInfo.property().isEmpty()) { + return Optional.of(typeInfo.property()); + } + } + } catch (Exception e) { + // Ignore reflection errors + } + return Optional.empty(); + } + + /** + * Parse the data field based on what the matching variant expects. + * If the variant expects a String for its data field, returns the raw string. + * Otherwise, parses the data as JSON. + */ + private static Object parseDataForVariant( + String eventType, String data, Class unionClass, String discriminatorProperty) { + if (data == null || data.isEmpty()) { + return data; + } + + try { + // Try to find the variant class that matches this event type + Class variantClass = findVariantClass(unionClass, eventType, discriminatorProperty); + if (variantClass != null) { + // Check if the variant expects a String for the data field + Field dataField = findField(variantClass, "data"); + if (dataField != null && String.class.equals(dataField.getType())) { + // Variant expects String - return raw data + return data; + } + } + + // Try to parse as JSON + return ObjectMappers.JSON_MAPPER.readValue(data, new TypeReference>() {}); + } catch (Exception e) { + // If JSON parsing fails, return as string + return data; + } + } + + /** + * Find the variant class that matches the given discriminator value. + */ + private static Class findVariantClass( + Class unionClass, String discriminatorValue, String discriminatorProperty) { + try { + // Look for JsonSubTypes annotation + JsonSubTypes subTypes = findJsonSubTypes(unionClass); + if (subTypes == null) { + return null; + } + + for (JsonSubTypes.Type subType : subTypes.value()) { + JsonTypeName typeName = subType.value().getAnnotation(JsonTypeName.class); + if (typeName != null && typeName.value().equals(discriminatorValue)) { + return subType.value(); + } + // Also check the name attribute of @JsonSubTypes.Type + if (subType.name().equals(discriminatorValue)) { + return subType.value(); + } + } + } catch (Exception e) { + // Ignore reflection errors + } + return null; + } + + /** + * Find JsonSubTypes annotation on the class or its inner classes. + */ + private static JsonSubTypes findJsonSubTypes(Class unionClass) { + // Check the class itself + JsonSubTypes subTypes = unionClass.getAnnotation(JsonSubTypes.class); + if (subTypes != null) { + return subTypes; + } + + // Check inner classes (for Fern-style unions with inner Value interface) + for (Class innerClass : unionClass.getDeclaredClasses()) { + subTypes = innerClass.getAnnotation(JsonSubTypes.class); + if (subTypes != null) { + return subTypes; + } + } + return null; + } + + /** + * Find a field by name in a class, including private fields. + */ + private static Field findField(Class clazz, String fieldName) { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // Check superclass + Class superClass = clazz.getSuperclass(); + if (superClass != null && superClass != Object.class) { + return findField(superClass, fieldName); + } + return null; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Stream.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Stream.java new file mode 100644 index 000000000000..daf5c1ee56f5 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Stream.java @@ -0,0 +1,513 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.io.Closeable; +import java.io.IOException; +import java.io.Reader; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Scanner; + +/** + * The {@code Stream} class implements {@link Iterable} to provide a simple mechanism for reading and parsing + * objects of a given type from data streamed via a {@link Reader} using a specified delimiter. + *

+ * {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a + * {@code Scanner} to block during iteration if the next object is not available. + * Iterable stream for parsing JSON and Server-Sent Events (SSE) data. + * Supports both newline-delimited JSON and SSE with optional stream termination. + * + * @param The type of objects in the stream. + */ +public final class Stream implements Iterable, Closeable { + + private static final String NEWLINE = "\n"; + private static final String DATA_PREFIX = "data:"; + + public enum StreamType { + JSON, + SSE, + SSE_EVENT_DISCRIMINATED + } + + private final Class valueType; + private final Scanner scanner; + private final StreamType streamType; + private final String messageTerminator; + private final String streamTerminator; + private final Reader sseReader; + private final String discriminatorProperty; + private boolean isClosed = false; + + /** + * Constructs a new {@code Stream} with the specified value type, reader, and delimiter. + * + * @param valueType The class of the objects in the stream. + * @param reader The reader that provides the streamed data. + * @param delimiter The delimiter used to separate elements in the stream. + */ + public Stream(Class valueType, Reader reader, String delimiter) { + this.valueType = valueType; + this.scanner = new Scanner(reader).useDelimiter(delimiter); + this.streamType = StreamType.JSON; + this.messageTerminator = delimiter; + this.streamTerminator = null; + this.sseReader = null; + this.discriminatorProperty = null; + } + + private Stream(Class valueType, StreamType type, Reader reader, String terminator) { + this(valueType, type, reader, terminator, null); + } + + private Stream( + Class valueType, StreamType type, Reader reader, String terminator, String discriminatorProperty) { + this.valueType = valueType; + this.streamType = type; + this.discriminatorProperty = discriminatorProperty; + if (type == StreamType.JSON) { + this.scanner = new Scanner(reader).useDelimiter(terminator); + this.messageTerminator = terminator; + this.streamTerminator = null; + this.sseReader = null; + } else { + this.scanner = null; + this.messageTerminator = NEWLINE; + this.streamTerminator = terminator; + this.sseReader = reader; + } + } + + public static Stream fromJson(Class valueType, Reader reader, String delimiter) { + return new Stream<>(valueType, reader, delimiter); + } + + public static Stream fromJson(Class valueType, Reader reader) { + return new Stream<>(valueType, reader, NEWLINE); + } + + public static Stream fromSse(Class valueType, Reader sseReader) { + return new Stream<>(valueType, StreamType.SSE, sseReader, null); + } + + public static Stream fromSse(Class valueType, Reader sseReader, String streamTerminator) { + return new Stream<>(valueType, StreamType.SSE, sseReader, streamTerminator); + } + + /** + * Creates a stream from SSE data with event-level discrimination support. + * Use this when the SSE payload is a discriminated union where the discriminator + * is an SSE envelope field (e.g., 'event'). + * + * @param valueType The class of the objects in the stream. + * @param sseReader The reader that provides the SSE data. + * @param discriminatorProperty The property name used for discrimination (e.g., "event"). + * @param The type of objects in the stream. + * @return A new Stream instance configured for SSE with event-level discrimination. + */ + public static Stream fromSseWithEventDiscrimination( + Class valueType, Reader sseReader, String discriminatorProperty) { + return new Stream<>(valueType, StreamType.SSE_EVENT_DISCRIMINATED, sseReader, null, discriminatorProperty); + } + + /** + * Creates a stream from SSE data with event-level discrimination support and a stream terminator. + * + * @param valueType The class of the objects in the stream. + * @param sseReader The reader that provides the SSE data. + * @param discriminatorProperty The property name used for discrimination (e.g., "event"). + * @param streamTerminator The terminator string that signals end of stream (e.g., "[DONE]"). + * @param The type of objects in the stream. + * @return A new Stream instance configured for SSE with event-level discrimination. + */ + public static Stream fromSseWithEventDiscrimination( + Class valueType, Reader sseReader, String discriminatorProperty, String streamTerminator) { + return new Stream<>( + valueType, StreamType.SSE_EVENT_DISCRIMINATED, sseReader, streamTerminator, discriminatorProperty); + } + + @Override + public void close() throws IOException { + if (!isClosed) { + isClosed = true; + if (scanner != null) { + scanner.close(); + } + if (sseReader != null) { + sseReader.close(); + } + } + } + + private boolean isStreamClosed() { + return isClosed; + } + + /** + * Returns an iterator over the elements in this stream that blocks during iteration when the next object is + * not yet available. + * + * @return An iterator that can be used to traverse the elements in the stream. + */ + @Override + public Iterator iterator() { + switch (streamType) { + case SSE: + return new SSEIterator(); + case SSE_EVENT_DISCRIMINATED: + return new SSEEventDiscriminatedIterator(); + case JSON: + default: + return new JsonIterator(); + } + } + + private final class JsonIterator implements Iterator { + + /** + * Returns {@code true} if there are more elements in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return {@code true} if there are more elements, {@code false} otherwise. + */ + @Override + public boolean hasNext() { + if (isStreamClosed()) { + return false; + } + return scanner.hasNext(); + } + + /** + * Returns the next element in the stream. + *

+ * Will block and wait for input if the stream has not ended and the next object is not yet available. + * + * @return The next element in the stream. + * @throws NoSuchElementException If there are no more elements in the stream. + */ + @Override + public T next() { + if (isStreamClosed()) { + throw new NoSuchElementException("Stream is closed"); + } + + if (!scanner.hasNext()) { + throw new NoSuchElementException(); + } else { + try { + T parsedResponse = + ObjectMappers.JSON_MAPPER.readValue(scanner.next().trim(), valueType); + return parsedResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + private final class SSEIterator implements Iterator { + private Scanner sseScanner; + private T nextItem; + private boolean hasNextItem = false; + private boolean endOfStream = false; + private StringBuilder eventDataBuffer = new StringBuilder(); + private String currentEventType = null; + + private SSEIterator() { + if (sseReader != null && !isStreamClosed()) { + this.sseScanner = new Scanner(sseReader); + } else { + this.endOfStream = true; + } + } + + @Override + public boolean hasNext() { + if (isStreamClosed() || endOfStream) { + return false; + } + + if (hasNextItem) { + return true; + } + + return readNextMessage(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("No more elements in stream"); + } + + T result = nextItem; + nextItem = null; + hasNextItem = false; + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private boolean readNextMessage() { + if (sseScanner == null || isStreamClosed()) { + endOfStream = true; + return false; + } + + try { + while (sseScanner.hasNextLine()) { + String line = sseScanner.nextLine(); + + if (line.trim().isEmpty()) { + if (eventDataBuffer.length() > 0) { + try { + nextItem = ObjectMappers.JSON_MAPPER.readValue(eventDataBuffer.toString(), valueType); + hasNextItem = true; + eventDataBuffer.setLength(0); + currentEventType = null; + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse SSE event: " + parseEx.getMessage()); + eventDataBuffer.setLength(0); + currentEventType = null; + continue; + } + } + continue; + } + + if (line.startsWith(DATA_PREFIX)) { + String dataContent = line.substring(DATA_PREFIX.length()); + if (dataContent.startsWith(" ")) { + dataContent = dataContent.substring(1); + } + + if (eventDataBuffer.length() == 0 + && streamTerminator != null + && dataContent.trim().equals(streamTerminator)) { + endOfStream = true; + return false; + } + + if (eventDataBuffer.length() > 0) { + eventDataBuffer.append('\n'); + } + eventDataBuffer.append(dataContent); + } else if (line.startsWith("event:")) { + String eventValue = line.length() > 6 ? line.substring(6) : ""; + if (eventValue.startsWith(" ")) { + eventValue = eventValue.substring(1); + } + currentEventType = eventValue; + } else if (line.startsWith("id:")) { + // Event ID field (ignored) + } else if (line.startsWith("retry:")) { + // Retry field (ignored) + } else if (line.startsWith(":")) { + // Comment line (ignored) + } + } + + if (eventDataBuffer.length() > 0) { + try { + nextItem = ObjectMappers.JSON_MAPPER.readValue(eventDataBuffer.toString(), valueType); + hasNextItem = true; + eventDataBuffer.setLength(0); + currentEventType = null; + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse final SSE event: " + parseEx.getMessage()); + eventDataBuffer.setLength(0); + currentEventType = null; + } + } + + endOfStream = true; + return false; + + } catch (Exception e) { + System.err.println("Failed to parse SSE stream: " + e.getMessage()); + endOfStream = true; + return false; + } + } + } + + /** + * Iterator for SSE streams with event-level discrimination. + * Uses SseEventParser to construct the full SSE envelope for Jackson deserialization. + */ + private final class SSEEventDiscriminatedIterator implements Iterator { + private Scanner sseScanner; + private T nextItem; + private boolean hasNextItem = false; + private boolean endOfStream = false; + private StringBuilder eventDataBuffer = new StringBuilder(); + private String currentEventType = null; + private String currentEventId = null; + private Long currentRetry = null; + + private SSEEventDiscriminatedIterator() { + if (sseReader != null && !isStreamClosed()) { + this.sseScanner = new Scanner(sseReader); + } else { + this.endOfStream = true; + } + } + + @Override + public boolean hasNext() { + if (isStreamClosed() || endOfStream) { + return false; + } + + if (hasNextItem) { + return true; + } + + return readNextMessage(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException("No more elements in stream"); + } + + T result = nextItem; + nextItem = null; + hasNextItem = false; + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private boolean readNextMessage() { + if (sseScanner == null || isStreamClosed()) { + endOfStream = true; + return false; + } + + try { + while (sseScanner.hasNextLine()) { + String line = sseScanner.nextLine(); + + if (line.trim().isEmpty()) { + if (eventDataBuffer.length() > 0 || currentEventType != null) { + try { + // Use SseEventParser for event-level discrimination + nextItem = SseEventParser.parseEventLevelUnion( + currentEventType, + eventDataBuffer.toString(), + currentEventId, + currentRetry, + valueType, + discriminatorProperty); + hasNextItem = true; + resetEventState(); + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse SSE event: " + parseEx.getMessage()); + resetEventState(); + continue; + } + } + continue; + } + + if (line.startsWith(DATA_PREFIX)) { + String dataContent = line.substring(DATA_PREFIX.length()); + if (dataContent.startsWith(" ")) { + dataContent = dataContent.substring(1); + } + + if (eventDataBuffer.length() == 0 + && streamTerminator != null + && dataContent.trim().equals(streamTerminator)) { + endOfStream = true; + return false; + } + + if (eventDataBuffer.length() > 0) { + eventDataBuffer.append('\n'); + } + eventDataBuffer.append(dataContent); + } else if (line.startsWith("event:")) { + String eventValue = line.length() > 6 ? line.substring(6) : ""; + if (eventValue.startsWith(" ")) { + eventValue = eventValue.substring(1); + } + currentEventType = eventValue; + } else if (line.startsWith("id:")) { + String idValue = line.length() > 3 ? line.substring(3) : ""; + if (idValue.startsWith(" ")) { + idValue = idValue.substring(1); + } + currentEventId = idValue; + } else if (line.startsWith("retry:")) { + String retryValue = line.length() > 6 ? line.substring(6) : ""; + if (retryValue.startsWith(" ")) { + retryValue = retryValue.substring(1); + } + try { + currentRetry = Long.parseLong(retryValue.trim()); + } catch (NumberFormatException e) { + // Ignore invalid retry values + } + } else if (line.startsWith(":")) { + // Comment line (ignored) + } + } + + // Handle any remaining buffered data at end of stream + if (eventDataBuffer.length() > 0 || currentEventType != null) { + try { + nextItem = SseEventParser.parseEventLevelUnion( + currentEventType, + eventDataBuffer.toString(), + currentEventId, + currentRetry, + valueType, + discriminatorProperty); + hasNextItem = true; + resetEventState(); + return true; + } catch (Exception parseEx) { + System.err.println("Failed to parse final SSE event: " + parseEx.getMessage()); + resetEventState(); + } + } + + endOfStream = true; + return false; + + } catch (Exception e) { + System.err.println("Failed to parse SSE stream: " + e.getMessage()); + endOfStream = true; + return false; + } + } + + private void resetEventState() { + eventDataBuffer.setLength(0); + currentEventType = null; + currentEventId = null; + currentRetry = null; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Suppliers.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Suppliers.java new file mode 100644 index 000000000000..8671647c2421 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/Suppliers.java @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +public final class Suppliers { + private Suppliers() {} + + public static Supplier memoize(Supplier delegate) { + AtomicReference value = new AtomicReference<>(); + return () -> { + T val = value.get(); + if (val == null) { + val = value.updateAndGet(cur -> cur == null ? Objects.requireNonNull(delegate.get()) : cur); + } + return val; + }; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/WebSocketFactory.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/WebSocketFactory.java new file mode 100644 index 000000000000..76f1ddbee7ff --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/WebSocketFactory.java @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import okhttp3.Request; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; + +/** + * Factory interface for creating WebSocket connections. + * Allows for pluggable WebSocket implementations and testing. + */ +public interface WebSocketFactory { + /** + * Creates a WebSocket connection with the specified request and listener. + * + * @param request The WebSocket connection request with URL and headers + * @param listener The listener for WebSocket events + * @return A WebSocket instance ready for communication + */ + WebSocket create(Request request, WebSocketListener listener); +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/WebSocketReadyState.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/WebSocketReadyState.java new file mode 100644 index 000000000000..7a67be62b87e --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/core/WebSocketReadyState.java @@ -0,0 +1,29 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +/** + * WebSocket connection ready state, based on the W3C WebSocket API. + */ +public enum WebSocketReadyState { + /** + * The connection is being established. + */ + CONNECTING, + + /** + * The connection is open and ready to communicate. + */ + OPEN, + + /** + * The connection is in the process of closing. + */ + CLOSING, + + /** + * The connection is closed. + */ + CLOSED +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/AsyncRealtimeClient.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/AsyncRealtimeClient.java new file mode 100644 index 000000000000..03094a6fbf1f --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/AsyncRealtimeClient.java @@ -0,0 +1,22 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime; + +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.websocket.RealtimeWebSocketClient; + +public class AsyncRealtimeClient { + protected final ClientOptions clientOptions; + + public AsyncRealtimeClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Creates a new WebSocket client for the realtime channel. + */ + public RealtimeWebSocketClient realtimeWebSocket() { + return new RealtimeWebSocketClient(clientOptions); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/RealtimeClient.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/RealtimeClient.java new file mode 100644 index 000000000000..2dc1fc5708ec --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/RealtimeClient.java @@ -0,0 +1,22 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime; + +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.websocket.RealtimeWebSocketClient; + +public class RealtimeClient { + protected final ClientOptions clientOptions; + + public RealtimeClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + } + + /** + * Creates a new WebSocket client for the realtime channel. + */ + public RealtimeWebSocketClient realtimeWebSocket() { + return new RealtimeWebSocketClient(clientOptions); + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/ConversationHistoryMessage.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/ConversationHistoryMessage.java new file mode 100644 index 000000000000..743f2bed6139 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/ConversationHistoryMessage.java @@ -0,0 +1,145 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ConversationHistoryMessage.Builder.class) +public final class ConversationHistoryMessage { + private final String role; + + private final String content; + + private final Map additionalProperties; + + private ConversationHistoryMessage(String role, String content, Map additionalProperties) { + this.role = role; + this.content = content; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("type") + public String getType() { + return "History"; + } + + @JsonProperty("role") + public String getRole() { + return role; + } + + @JsonProperty("content") + public String getContent() { + return content; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ConversationHistoryMessage && equalTo((ConversationHistoryMessage) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ConversationHistoryMessage other) { + return role.equals(other.role) && content.equals(other.content); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.role, this.content); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static RoleStage builder() { + return new Builder(); + } + + public interface RoleStage { + ContentStage role(@NotNull String role); + + Builder from(ConversationHistoryMessage other); + } + + public interface ContentStage { + _FinalStage content(@NotNull String content); + } + + public interface _FinalStage { + ConversationHistoryMessage build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements RoleStage, ContentStage, _FinalStage { + private String role; + + private String content; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(ConversationHistoryMessage other) { + role(other.getRole()); + content(other.getContent()); + return this; + } + + @java.lang.Override + @JsonSetter("role") + public ContentStage role(@NotNull String role) { + this.role = Objects.requireNonNull(role, "role must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("content") + public _FinalStage content(@NotNull String content) { + this.content = Objects.requireNonNull(content, "content must not be null"); + return this; + } + + @java.lang.Override + public ConversationHistoryMessage build() { + return new ConversationHistoryMessage(role, content, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/ConversationTextMessage.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/ConversationTextMessage.java new file mode 100644 index 000000000000..19d8a76ea872 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/ConversationTextMessage.java @@ -0,0 +1,145 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = ConversationTextMessage.Builder.class) +public final class ConversationTextMessage { + private final String text; + + private final double confidence; + + private final Map additionalProperties; + + private ConversationTextMessage(String text, double confidence, Map additionalProperties) { + this.text = text; + this.confidence = confidence; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("type") + public String getType() { + return "ConversationText"; + } + + @JsonProperty("text") + public String getText() { + return text; + } + + @JsonProperty("confidence") + public double getConfidence() { + return confidence; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof ConversationTextMessage && equalTo((ConversationTextMessage) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(ConversationTextMessage other) { + return text.equals(other.text) && confidence == other.confidence; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.text, this.confidence); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TextStage builder() { + return new Builder(); + } + + public interface TextStage { + ConfidenceStage text(@NotNull String text); + + Builder from(ConversationTextMessage other); + } + + public interface ConfidenceStage { + _FinalStage confidence(double confidence); + } + + public interface _FinalStage { + ConversationTextMessage build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TextStage, ConfidenceStage, _FinalStage { + private String text; + + private double confidence; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(ConversationTextMessage other) { + text(other.getText()); + confidence(other.getConfidence()); + return this; + } + + @java.lang.Override + @JsonSetter("text") + public ConfidenceStage text(@NotNull String text) { + this.text = Objects.requireNonNull(text, "text must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("confidence") + public _FinalStage confidence(double confidence) { + this.confidence = confidence; + return this; + } + + @java.lang.Override + public ConversationTextMessage build() { + return new ConversationTextMessage(text, confidence, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/FunctionCall.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/FunctionCall.java new file mode 100644 index 000000000000..1e4d17c0620b --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/FunctionCall.java @@ -0,0 +1,162 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FunctionCall.Builder.class) +public final class FunctionCall { + private final String id; + + private final String name; + + private final String arguments; + + private final Map additionalProperties; + + private FunctionCall(String id, String name, String arguments, Map additionalProperties) { + this.id = id; + this.name = name; + this.arguments = arguments; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("id") + public String getId() { + return id; + } + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("arguments") + public String getArguments() { + return arguments; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FunctionCall && equalTo((FunctionCall) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FunctionCall other) { + return id.equals(other.id) && name.equals(other.name) && arguments.equals(other.arguments); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.id, this.name, this.arguments); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static IdStage builder() { + return new Builder(); + } + + public interface IdStage { + NameStage id(@NotNull String id); + + Builder from(FunctionCall other); + } + + public interface NameStage { + ArgumentsStage name(@NotNull String name); + } + + public interface ArgumentsStage { + _FinalStage arguments(@NotNull String arguments); + } + + public interface _FinalStage { + FunctionCall build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements IdStage, NameStage, ArgumentsStage, _FinalStage { + private String id; + + private String name; + + private String arguments; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(FunctionCall other) { + id(other.getId()); + name(other.getName()); + arguments(other.getArguments()); + return this; + } + + @java.lang.Override + @JsonSetter("id") + public NameStage id(@NotNull String id) { + this.id = Objects.requireNonNull(id, "id must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("name") + public ArgumentsStage name(@NotNull String name) { + this.name = Objects.requireNonNull(name, "name must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("arguments") + public _FinalStage arguments(@NotNull String arguments) { + this.arguments = Objects.requireNonNull(arguments, "arguments must not be null"); + return this; + } + + @java.lang.Override + public FunctionCall build() { + return new FunctionCall(id, name, arguments, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/FunctionCallHistoryMessage.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/FunctionCallHistoryMessage.java new file mode 100644 index 000000000000..7e777946df0e --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/FunctionCallHistoryMessage.java @@ -0,0 +1,121 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = FunctionCallHistoryMessage.Builder.class) +public final class FunctionCallHistoryMessage { + private final List functionCalls; + + private final Map additionalProperties; + + private FunctionCallHistoryMessage(List functionCalls, Map additionalProperties) { + this.functionCalls = functionCalls; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("type") + public String getType() { + return "History"; + } + + @JsonProperty("function_calls") + public List getFunctionCalls() { + return functionCalls; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof FunctionCallHistoryMessage && equalTo((FunctionCallHistoryMessage) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(FunctionCallHistoryMessage other) { + return functionCalls.equals(other.functionCalls); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.functionCalls); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static Builder builder() { + return new Builder(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder { + private List functionCalls = new ArrayList<>(); + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + public Builder from(FunctionCallHistoryMessage other) { + functionCalls(other.getFunctionCalls()); + return this; + } + + @JsonSetter(value = "function_calls", nulls = Nulls.SKIP) + public Builder functionCalls(List functionCalls) { + this.functionCalls.clear(); + if (functionCalls != null) { + this.functionCalls.addAll(functionCalls); + } + return this; + } + + public Builder addFunctionCalls(FunctionCall functionCalls) { + this.functionCalls.add(functionCalls); + return this; + } + + public Builder addAllFunctionCalls(List functionCalls) { + if (functionCalls != null) { + this.functionCalls.addAll(functionCalls); + } + return this; + } + + public FunctionCallHistoryMessage build() { + return new FunctionCallHistoryMessage(functionCalls, additionalProperties); + } + + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/SendEvent.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/SendEvent.java new file mode 100644 index 000000000000..fccb2fe589f5 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/types/SendEvent.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = SendEvent.Builder.class) +public final class SendEvent { + private final String text; + + private final Map additionalProperties; + + private SendEvent(String text, Map additionalProperties) { + this.text = text; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("text") + public String getText() { + return text; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof SendEvent && equalTo((SendEvent) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(SendEvent other) { + return text.equals(other.text); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.text); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static TextStage builder() { + return new Builder(); + } + + public interface TextStage { + _FinalStage text(@NotNull String text); + + Builder from(SendEvent other); + } + + public interface _FinalStage { + SendEvent build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements TextStage, _FinalStage { + private String text; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(SendEvent other) { + text(other.getText()); + return this; + } + + @java.lang.Override + @JsonSetter("text") + public _FinalStage text(@NotNull String text) { + this.text = Objects.requireNonNull(text, "text must not be null"); + return this; + } + + @java.lang.Override + public SendEvent build() { + return new SendEvent(text, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/websocket/RealtimeWebSocketClient.java b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/websocket/RealtimeWebSocketClient.java new file mode 100644 index 000000000000..7e4c1aa11040 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/main/java/com/seed/javaWebsocketSharedDiscriminator/resources/realtime/websocket/RealtimeWebSocketClient.java @@ -0,0 +1,346 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.resources.realtime.websocket; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.seed.javaWebsocketSharedDiscriminator.core.ClientOptions; +import com.seed.javaWebsocketSharedDiscriminator.core.DisconnectReason; +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import com.seed.javaWebsocketSharedDiscriminator.core.ReconnectingWebSocketListener; +import com.seed.javaWebsocketSharedDiscriminator.core.WebSocketReadyState; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types.ConversationHistoryMessage; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types.ConversationTextMessage; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types.FunctionCallHistoryMessage; +import com.seed.javaWebsocketSharedDiscriminator.resources.realtime.types.SendEvent; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okio.ByteString; + +/** + * WebSocket client for the realtime channel. + * Provides real-time bidirectional communication with strongly-typed messages. + */ +public class RealtimeWebSocketClient implements AutoCloseable { + protected final ClientOptions clientOptions; + + private final ObjectMapper objectMapper; + + private final OkHttpClient okHttpClient; + + private ScheduledExecutorService timeoutExecutor; + + private volatile WebSocketReadyState readyState = WebSocketReadyState.CLOSED; + + private volatile Runnable onConnectedHandler; + + private volatile Consumer onDisconnectedHandler; + + private volatile Consumer onErrorHandler; + + private volatile Consumer onMessageHandler; + + private volatile ReconnectingWebSocketListener.ReconnectOptions reconnectOptions; + + private CompletableFuture connectionFuture; + + private ReconnectingWebSocketListener reconnectingListener; + + private volatile Consumer conversationHistoryHandler; + + private volatile Consumer functionCallHistoryHandler; + + private volatile Consumer conversationTextHandler; + + /** + * Creates a new async WebSocket client for the realtime channel. + */ + public RealtimeWebSocketClient(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + this.objectMapper = ObjectMappers.JSON_MAPPER; + this.okHttpClient = clientOptions.httpClient(); + } + + /** + * Establishes the WebSocket connection asynchronously with automatic reconnection. + * @return a CompletableFuture that completes when the connection is established + */ + public CompletableFuture connect() { + connectionFuture = new CompletableFuture<>(); + String baseUrl = clientOptions.environment().getUrl(); + String fullPath = "/realtime"; + if (baseUrl.endsWith("/") && fullPath.startsWith("/")) { + fullPath = fullPath.substring(1); + } else if (!baseUrl.endsWith("/") && !fullPath.startsWith("/")) { + fullPath = "/" + fullPath; + } + // OkHttp's HttpUrl only supports http/https schemes; convert wss/ws for URL parsing + if (baseUrl.startsWith("wss://")) { + baseUrl = "https://" + baseUrl.substring(6); + } else if (baseUrl.startsWith("ws://")) { + baseUrl = "http://" + baseUrl.substring(5); + } + HttpUrl parsedUrl = HttpUrl.parse(baseUrl + fullPath); + if (parsedUrl == null) { + throw new IllegalArgumentException("Invalid WebSocket URL: " + baseUrl + fullPath); + } + HttpUrl.Builder urlBuilder = parsedUrl.newBuilder(); + Request.Builder requestBuilder = new Request.Builder().url(urlBuilder.build()); + clientOptions.headers(null).forEach(requestBuilder::addHeader); + final Request request = requestBuilder.build(); + this.readyState = WebSocketReadyState.CONNECTING; + ReconnectingWebSocketListener.ReconnectOptions reconnectOpts = this.reconnectOptions != null + ? this.reconnectOptions + : ReconnectingWebSocketListener.ReconnectOptions.builder().build(); + this.reconnectingListener = + new ReconnectingWebSocketListener(reconnectOpts, () -> { + if (clientOptions.webSocketFactory().isPresent()) { + return clientOptions.webSocketFactory().get().create(request, this.reconnectingListener); + } else { + return okHttpClient.newWebSocket(request, this.reconnectingListener); + } + }) { + @Override + protected void onWebSocketOpen(WebSocket webSocket, Response response) { + readyState = WebSocketReadyState.OPEN; + if (onConnectedHandler != null) { + onConnectedHandler.run(); + } + connectionFuture.complete(null); + } + + @Override + protected void onWebSocketMessage(WebSocket webSocket, String text) { + handleIncomingMessage(text); + } + + @Override + protected void onWebSocketBinaryMessage(WebSocket webSocket, ByteString bytes) {} + + @Override + protected void onWebSocketFailure(WebSocket webSocket, Throwable t, Response response) { + readyState = WebSocketReadyState.CLOSED; + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException(t)); + } + connectionFuture.completeExceptionally(t); + } + + @Override + protected void onWebSocketClosed(WebSocket webSocket, int code, String reason) { + readyState = WebSocketReadyState.CLOSED; + if (onDisconnectedHandler != null) { + onDisconnectedHandler.accept(new DisconnectReason(code, reason)); + } + } + }; + reconnectingListener.connect(); + return connectionFuture; + } + + /** + * Disconnects the WebSocket connection and releases resources. + */ + public void disconnect() { + reconnectingListener.disconnect(); + if (timeoutExecutor != null) { + timeoutExecutor.shutdownNow(); + timeoutExecutor = null; + } + } + + /** + * Gets the current state of the WebSocket connection. + * + * This provides the actual connection state, similar to the W3C WebSocket API. + * + * @return the current WebSocket ready state + */ + public WebSocketReadyState getReadyState() { + return readyState; + } + + /** + * Sends a send message to the server asynchronously. + * @param message the message to send + * @return a CompletableFuture that completes when the message is sent + */ + public CompletableFuture sendSend(SendEvent message) { + return sendMessage(message); + } + + /** + * Registers a handler for ConversationHistory messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onConversationHistory(Consumer handler) { + this.conversationHistoryHandler = handler; + } + + /** + * Registers a handler for FunctionCallHistory messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onFunctionCallHistory(Consumer handler) { + this.functionCallHistoryHandler = handler; + } + + /** + * Registers a handler for ConversationText messages from the server. + * @param handler the handler to invoke when a message is received + */ + public void onConversationText(Consumer handler) { + this.conversationTextHandler = handler; + } + + /** + * Registers a handler called when the connection is established. + * @param handler the handler to invoke when connected + */ + public void onConnected(Runnable handler) { + this.onConnectedHandler = handler; + } + + /** + * Registers a handler called when the connection is closed. + * @param handler the handler to invoke when disconnected + */ + public void onDisconnected(Consumer handler) { + this.onDisconnectedHandler = handler; + } + + /** + * Registers a handler called when an error occurs. + * @param handler the handler to invoke on error + */ + public void onError(Consumer handler) { + this.onErrorHandler = handler; + } + + /** + * Registers a handler called for every incoming text message. + * The handler receives the raw JSON string before type-specific dispatch. + * @param handler the handler to invoke with the raw message JSON + */ + public void onMessage(Consumer handler) { + this.onMessageHandler = handler; + } + + /** + * Configures reconnection behavior. Must be called before {@link #connect}. + * + * @param options the reconnection options (backoff, retries, queue size) + */ + public void reconnectOptions(ReconnectingWebSocketListener.ReconnectOptions options) { + this.reconnectOptions = options; + } + + /** + * Closes this WebSocket client, releasing all resources. + * Equivalent to calling {@link #disconnect()}. + */ + @Override + public void close() { + disconnect(); + } + + /** + * Ensures the WebSocket is connected and ready to send messages. + * @throws IllegalStateException if the socket is not connected or not open + */ + private void assertSocketIsOpen() { + if (reconnectingListener.getWebSocket() == null) { + throw new IllegalStateException("WebSocket is not connected. Call connect() first."); + } + if (readyState != WebSocketReadyState.OPEN) { + throw new IllegalStateException("WebSocket is not open. Current state: " + readyState); + } + } + + private CompletableFuture sendMessage(Object body) { + CompletableFuture future = new CompletableFuture<>(); + try { + assertSocketIsOpen(); + String json = objectMapper.writeValueAsString(body); + // Use reconnecting listener's send method which handles queuing + reconnectingListener.send(json); + future.complete(null); + } catch (IllegalStateException e) { + future.completeExceptionally(e); + } catch (Exception e) { + future.completeExceptionally(new RuntimeException("Failed to send message", e)); + } + return future; + } + + private void handleIncomingMessage(String json) { + try { + if (onMessageHandler != null) { + onMessageHandler.accept(json); + } + JsonNode node = objectMapper.readTree(json); + if (node == null || node.isNull()) { + throw new IllegalArgumentException("Received null or invalid JSON message"); + } + if (node.has("role") + && node.has("content") + && "History".equals(node.path("type").asText())) { + ConversationHistoryMessage conversationHistoryHandlerEvent = null; + try { + conversationHistoryHandlerEvent = objectMapper.treeToValue(node, ConversationHistoryMessage.class); + } catch (Exception e) { + } + if (conversationHistoryHandlerEvent != null) { + if (conversationHistoryHandler != null) { + conversationHistoryHandler.accept(conversationHistoryHandlerEvent); + } + return; + } + } + if (node.has("text") + && node.has("confidence") + && "ConversationText".equals(node.path("type").asText())) { + ConversationTextMessage conversationTextHandlerEvent = null; + try { + conversationTextHandlerEvent = objectMapper.treeToValue(node, ConversationTextMessage.class); + } catch (Exception e) { + } + if (conversationTextHandlerEvent != null) { + if (conversationTextHandler != null) { + conversationTextHandler.accept(conversationTextHandlerEvent); + } + return; + } + } + if (node.has("function_calls") && "History".equals(node.path("type").asText())) { + FunctionCallHistoryMessage functionCallHistoryHandlerEvent = null; + try { + functionCallHistoryHandlerEvent = objectMapper.treeToValue(node, FunctionCallHistoryMessage.class); + } catch (Exception e) { + } + if (functionCallHistoryHandlerEvent != null) { + if (functionCallHistoryHandler != null) { + functionCallHistoryHandler.accept(functionCallHistoryHandlerEvent); + } + return; + } + } + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); + } + } catch (Exception e) { + if (onErrorHandler != null) { + onErrorHandler.accept(e); + } + } + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/StreamTest.java b/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/StreamTest.java new file mode 100644 index 000000000000..5c123d2814e1 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/StreamTest.java @@ -0,0 +1,120 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.javaWebsocketSharedDiscriminator.core.ObjectMappers; +import com.seed.javaWebsocketSharedDiscriminator.core.Stream; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +public final class StreamTest { + @Test + public void testJsonStream() { + List> messages = + Arrays.asList(createMap("message", "hello"), createMap("message", "world")); + List jsonStrings = messages.stream().map(StreamTest::mapToJson).collect(Collectors.toList()); + String input = String.join("\n", jsonStrings); + StringReader jsonInput = new StringReader(input); + Stream jsonStream = Stream.fromJson(Map.class, jsonInput); + int expectedMessages = 2; + int actualMessages = 0; + for (Map jsonObject : jsonStream) { + actualMessages++; + assertTrue(jsonObject.containsKey("message")); + } + assertEquals(expectedMessages, actualMessages); + } + + @Test + public void testSseStream() { + List> events = Arrays.asList(createMap("event", "start"), createMap("event", "end")); + List sseStrings = events.stream().map(StreamTest::mapToSse).collect(Collectors.toList()); + String input = String.join("\n" + "\n", sseStrings); + StringReader sseInput = new StringReader(input); + Stream sseStream = Stream.fromSse(Map.class, sseInput); + int expectedEvents = 2; + int actualEvents = 0; + for (Map eventData : sseStream) { + actualEvents++; + assertTrue(eventData.containsKey("event")); + } + assertEquals(expectedEvents, actualEvents); + } + + @Test + public void testSseStreamWithTerminator() { + List> events = Arrays.asList(createMap("message", "first"), createMap("message", "second")); + List sseStrings = + new ArrayList<>(events.stream().map(StreamTest::mapToSse).collect(Collectors.toList())); + sseStrings.add("data: [DONE]"); + String input = String.join("\n" + "\n", sseStrings); + StringReader sseInput = new StringReader(input); + Stream sseStream = Stream.fromSse(Map.class, sseInput, "[DONE]"); + int expectedEvents = 2; + int actualEvents = 0; + for (Map eventData : sseStream) { + actualEvents++; + assertTrue(eventData.containsKey("message")); + } + assertEquals(expectedEvents, actualEvents); + } + + @Test + public void testSseEventDiscriminatedStream() { + List sseStrings = Arrays.asList( + mapToSseWithEvent("start", createMap("status", "pending")), + mapToSseWithEvent("end", createMap("status", "complete"))); + String input = String.join("\n" + "\n", sseStrings); + StringReader sseInput = new StringReader(input); + Stream sseStream = Stream.fromSseWithEventDiscrimination(Map.class, sseInput, "event"); + int expectedEvents = 2; + int actualEvents = 0; + for (Map eventData : sseStream) { + actualEvents++; + // Event-level discrimination includes the event field in the parsed result + assertTrue(eventData.containsKey("event")); + assertTrue(eventData.containsKey("data")); + } + assertEquals(expectedEvents, actualEvents); + } + + @Test + public void testStreamResourceManagement() throws IOException { + StringReader testInput = new StringReader("{\"test\":\"data\"}"); + Stream testStream = Stream.fromJson(Map.class, testInput); + testStream.close(); + assertFalse(testStream.iterator().hasNext()); + } + + private static String mapToJson(Map map) { + try { + return ObjectMappers.JSON_MAPPER.writeValueAsString(map); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String mapToSse(Map map) { + return "data: " + mapToJson(map); + } + + private static String mapToSseWithEvent(String eventType, Map data) { + return "event: " + eventType + "\n" + "data: " + mapToJson(data); + } + + private static Map createMap(String key, String value) { + Map map = new HashMap<>(); + map.put(key, value); + return map; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/TestClient.java b/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/TestClient.java new file mode 100644 index 000000000000..53b139a95aba --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/TestClient.java @@ -0,0 +1,11 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator; + +public final class TestClient { + public void test() { + // Add tests here and mark this file in .fernignore + assert true; + } +} diff --git a/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/core/QueryStringMapperTest.java b/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/core/QueryStringMapperTest.java new file mode 100644 index 000000000000..744dc5a32754 --- /dev/null +++ b/seed/java-sdk/java-websocket-shared-discriminator/src/test/java/com/seed/javaWebsocketSharedDiscriminator/core/QueryStringMapperTest.java @@ -0,0 +1,339 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.javaWebsocketSharedDiscriminator.core; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import okhttp3.HttpUrl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public final class QueryStringMapperTest { + @Test + public void testObjectWithQuotedString_indexedArrays() { + Map map = new HashMap() { + { + put("hello", "\"world\""); + } + }; + + String expectedQueryString = "withquoted%5Bhello%5D=%22world%22"; + + String actualQueryString = queryString( + new HashMap() { + { + put("withquoted", map); + } + }, + false); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObjectWithQuotedString_arraysAsRepeats() { + Map map = new HashMap() { + { + put("hello", "\"world\""); + } + }; + + String expectedQueryString = "withquoted%5Bhello%5D=%22world%22"; + + String actualQueryString = queryString( + new HashMap() { + { + put("withquoted", map); + } + }, + true); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObject_indexedArrays() { + Map map = new HashMap() { + { + put("foo", "bar"); + put("baz", "qux"); + } + }; + + String expectedQueryString = "metadata%5Bfoo%5D=bar&metadata%5Bbaz%5D=qux"; + + String actualQueryString = queryString( + new HashMap() { + { + put("metadata", map); + } + }, + false); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObject_arraysAsRepeats() { + Map map = new HashMap() { + { + put("foo", "bar"); + put("baz", "qux"); + } + }; + + String expectedQueryString = "metadata%5Bfoo%5D=bar&metadata%5Bbaz%5D=qux"; + + String actualQueryString = queryString( + new HashMap() { + { + put("metadata", map); + } + }, + true); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testNestedObject_indexedArrays() { + Map> nestedMap = new HashMap>() { + { + put("mapkey1", new HashMap() { + { + put("mapkey1mapkey1", "mapkey1mapkey1value"); + put("mapkey1mapkey2", "mapkey1mapkey2value"); + } + }); + put("mapkey2", new HashMap() { + { + put("mapkey2mapkey1", "mapkey2mapkey1value"); + } + }); + } + }; + + String expectedQueryString = + "nested%5Bmapkey2%5D%5Bmapkey2mapkey1%5D=mapkey2mapkey1value&nested%5Bmapkey1%5D%5Bmapkey1mapkey1" + + "%5D=mapkey1mapkey1value&nested%5Bmapkey1%5D%5Bmapkey1mapkey2%5D=mapkey1mapkey2value"; + + String actualQueryString = queryString( + new HashMap() { + { + put("nested", nestedMap); + } + }, + false); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testNestedObject_arraysAsRepeats() { + Map> nestedMap = new HashMap>() { + { + put("mapkey1", new HashMap() { + { + put("mapkey1mapkey1", "mapkey1mapkey1value"); + put("mapkey1mapkey2", "mapkey1mapkey2value"); + } + }); + put("mapkey2", new HashMap() { + { + put("mapkey2mapkey1", "mapkey2mapkey1value"); + } + }); + } + }; + + String expectedQueryString = + "nested%5Bmapkey2%5D%5Bmapkey2mapkey1%5D=mapkey2mapkey1value&nested%5Bmapkey1%5D%5Bmapkey1mapkey1" + + "%5D=mapkey1mapkey1value&nested%5Bmapkey1%5D%5Bmapkey1mapkey2%5D=mapkey1mapkey2value"; + + String actualQueryString = queryString( + new HashMap() { + { + put("nested", nestedMap); + } + }, + true); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testDateTime_indexedArrays() { + OffsetDateTime dateTime = + OffsetDateTime.ofInstant(Instant.ofEpochSecond(1740412107L), ZoneId.of("America/New_York")); + + String expectedQueryString = "datetime=2025-02-24T10%3A48%3A27-05%3A00"; + + String actualQueryString = queryString( + new HashMap() { + { + put("datetime", dateTime); + } + }, + false); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testDateTime_arraysAsRepeats() { + OffsetDateTime dateTime = + OffsetDateTime.ofInstant(Instant.ofEpochSecond(1740412107L), ZoneId.of("America/New_York")); + + String expectedQueryString = "datetime=2025-02-24T10%3A48%3A27-05%3A00"; + + String actualQueryString = queryString( + new HashMap() { + { + put("datetime", dateTime); + } + }, + true); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObjectArray_indexedArrays() { + List> mapArray = new ArrayList>() { + { + add(new HashMap() { + { + put("key", "hello"); + put("value", "world"); + } + }); + add(new HashMap() { + { + put("key", "foo"); + put("value", "bar"); + } + }); + add(new HashMap<>()); + } + }; + + String expectedQueryString = "objects%5B0%5D%5Bvalue%5D=world&objects%5B0%5D%5Bkey%5D=hello&objects%5B1%5D" + + "%5Bvalue%5D=bar&objects%5B1%5D%5Bkey%5D=foo"; + + String actualQueryString = queryString( + new HashMap() { + { + put("objects", mapArray); + } + }, + false); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObjectArray_arraysAsRepeats() { + List> mapArray = new ArrayList>() { + { + add(new HashMap() { + { + put("key", "hello"); + put("value", "world"); + } + }); + add(new HashMap() { + { + put("key", "foo"); + put("value", "bar"); + } + }); + add(new HashMap<>()); + } + }; + + String expectedQueryString = + "objects%5Bvalue%5D=world&objects%5Bkey%5D=hello&objects%5Bvalue" + "%5D=bar&objects%5Bkey%5D=foo"; + + String actualQueryString = queryString( + new HashMap() { + { + put("objects", mapArray); + } + }, + true); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObjectWithArray_indexedArrays() { + Map objectWithArray = new HashMap() { + { + put("id", "abc123"); + put("contactIds", new ArrayList() { + { + add("id1"); + add("id2"); + add("id3"); + } + }); + } + }; + + String expectedQueryString = + "objectwitharray%5Bid%5D=abc123&objectwitharray%5BcontactIds%5D%5B0%5D=id1&objectwitharray" + + "%5BcontactIds%5D%5B1%5D=id2&objectwitharray%5BcontactIds%5D%5B2%5D=id3"; + + String actualQueryString = queryString( + new HashMap() { + { + put("objectwitharray", objectWithArray); + } + }, + false); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + @Test + public void testObjectWithArray_arraysAsRepeats() { + Map objectWithArray = new HashMap() { + { + put("id", "abc123"); + put("contactIds", new ArrayList() { + { + add("id1"); + add("id2"); + add("id3"); + } + }); + } + }; + + String expectedQueryString = "objectwitharray%5Bid%5D=abc123&objectwitharray%5BcontactIds" + + "%5D=id1&objectwitharray%5BcontactIds%5D=id2&objectwitharray%5BcontactIds%5D=id3"; + + String actualQueryString = queryString( + new HashMap() { + { + put("objectwitharray", objectWithArray); + } + }, + true); + + Assertions.assertEquals(expectedQueryString, actualQueryString); + } + + private static String queryString(Map params, boolean arraysAsRepeats) { + HttpUrl.Builder httpUrl = HttpUrl.parse("http://www.fakewebsite.com/").newBuilder(); + params.forEach((paramName, paramValue) -> + QueryStringMapper.addQueryParameter(httpUrl, paramName, paramValue, arraysAsRepeats)); + return httpUrl.build().encodedQuery(); + } +} diff --git a/seed/java-sdk/property-access/src/main/java/com/seed/propertyAccess/types/UserOrAdmin.java b/seed/java-sdk/property-access/src/main/java/com/seed/propertyAccess/types/UserOrAdmin.java index 613b961896ed..b971f3243f04 100644 --- a/seed/java-sdk/property-access/src/main/java/com/seed/propertyAccess/types/UserOrAdmin.java +++ b/seed/java-sdk/property-access/src/main/java/com/seed/propertyAccess/types/UserOrAdmin.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.propertyAccess.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = UserOrAdmin.Deserializer.class) @@ -81,13 +82,26 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public UserOrAdmin deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, User.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("id") + && ((Map) value).containsKey("email") + && ((Map) value).containsKey("password") + && ((Map) value).containsKey("profile")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, User.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Admin.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("adminLevel") + && ((Map) value).containsKey("id") + && ((Map) value).containsKey("email") + && ((Map) value).containsKey("password") + && ((Map) value).containsKey("profile")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Admin.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/property-access/src/test/java/com/seed/propertyAccess/UndiscriminatedUnionTest.java b/seed/java-sdk/property-access/src/test/java/com/seed/propertyAccess/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..f6c30c9a9057 --- /dev/null +++ b/seed/java-sdk/property-access/src/test/java/com/seed/propertyAccess/UndiscriminatedUnionTest.java @@ -0,0 +1,20 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.propertyAccess; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.propertyAccess.core.ObjectMappers; +import com.seed.propertyAccess.types.User; +import com.seed.propertyAccess.types.UserOrAdmin; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testUserOrAdmin_User() throws Exception { + String json = "{\"id\":\"test\",\"email\":\"test\",\"password\":\"test\",\"profile\":{}}"; + UserOrAdmin union = ObjectMappers.JSON_MAPPER.readValue(json, UserOrAdmin.class); + assertTrue(union.get() instanceof User, "Expected User but got different variant"); + } +} diff --git a/seed/java-sdk/simple-fhir/src/main/java/com/seed/api/types/ResourceList.java b/seed/java-sdk/simple-fhir/src/main/java/com/seed/api/types/ResourceList.java index 630aef97fd2a..ee1ceedd8f1e 100644 --- a/seed/java-sdk/simple-fhir/src/main/java/com/seed/api/types/ResourceList.java +++ b/seed/java-sdk/simple-fhir/src/main/java/com/seed/api/types/ResourceList.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.api.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = ResourceList.Deserializer.class) @@ -97,21 +98,46 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public ResourceList deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Account.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id") + && ((Map) value).containsKey("related_resources") + && ((Map) value).containsKey("memo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Account.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Patient.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("scripts") + && ((Map) value).containsKey("id") + && ((Map) value).containsKey("related_resources") + && ((Map) value).containsKey("memo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Patient.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Practitioner.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id") + && ((Map) value).containsKey("related_resources") + && ((Map) value).containsKey("memo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Practitioner.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, Script.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("id") + && ((Map) value).containsKey("related_resources") + && ((Map) value).containsKey("memo")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, Script.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/simple-fhir/src/test/java/com/seed/api/UndiscriminatedUnionTest.java b/seed/java-sdk/simple-fhir/src/test/java/com/seed/api/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..366a6a361ab2 --- /dev/null +++ b/seed/java-sdk/simple-fhir/src/test/java/com/seed/api/UndiscriminatedUnionTest.java @@ -0,0 +1,20 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.api; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.api.core.ObjectMappers; +import com.seed.api.types.Account; +import com.seed.api.types.ResourceList; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testResourceList_Account() throws Exception { + String json = "{\"name\":\"test\",\"id\":\"test\",\"related_resources\":[],\"memo\":{}}"; + ResourceList union = ObjectMappers.JSON_MAPPER.readValue(json, ResourceList.class); + assertTrue(union.get() instanceof Account, "Expected Account but got different variant"); + } +} diff --git a/seed/java-sdk/undiscriminated-union-with-response-property/src/main/java/com/seed/undiscriminatedUnionWithResponseProperty/types/MyUnion.java b/seed/java-sdk/undiscriminated-union-with-response-property/src/main/java/com/seed/undiscriminatedUnionWithResponseProperty/types/MyUnion.java index e7c69f97f61c..226a51635487 100644 --- a/seed/java-sdk/undiscriminated-union-with-response-property/src/main/java/com/seed/undiscriminatedUnionWithResponseProperty/types/MyUnion.java +++ b/seed/java-sdk/undiscriminated-union-with-response-property/src/main/java/com/seed/undiscriminatedUnionWithResponseProperty/types/MyUnion.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.undiscriminatedUnionWithResponseProperty.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = MyUnion.Deserializer.class) @@ -89,17 +90,23 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public MyUnion deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, VariantA.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("valueA")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, VariantA.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, VariantB.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("valueB")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, VariantB.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, VariantC.class)); - } catch (RuntimeException e) { + if (value instanceof Map && ((Map) value).containsKey("valueC")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, VariantC.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/undiscriminated-union-with-response-property/src/test/java/com/seed/undiscriminatedUnionWithResponseProperty/UndiscriminatedUnionTest.java b/seed/java-sdk/undiscriminated-union-with-response-property/src/test/java/com/seed/undiscriminatedUnionWithResponseProperty/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..70c3600c95be --- /dev/null +++ b/seed/java-sdk/undiscriminated-union-with-response-property/src/test/java/com/seed/undiscriminatedUnionWithResponseProperty/UndiscriminatedUnionTest.java @@ -0,0 +1,36 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnionWithResponseProperty; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.undiscriminatedUnionWithResponseProperty.core.ObjectMappers; +import com.seed.undiscriminatedUnionWithResponseProperty.types.MyUnion; +import com.seed.undiscriminatedUnionWithResponseProperty.types.VariantA; +import com.seed.undiscriminatedUnionWithResponseProperty.types.VariantB; +import com.seed.undiscriminatedUnionWithResponseProperty.types.VariantC; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testMyUnion_VariantA() throws Exception { + String json = "{\"valueA\":\"test\"}"; + MyUnion union = ObjectMappers.JSON_MAPPER.readValue(json, MyUnion.class); + assertTrue(union.get() instanceof VariantA, "Expected VariantA but got different variant"); + } + + @Test + public void testMyUnion_VariantB() throws Exception { + String json = "{\"valueB\":1}"; + MyUnion union = ObjectMappers.JSON_MAPPER.readValue(json, MyUnion.class); + assertTrue(union.get() instanceof VariantB, "Expected VariantB but got different variant"); + } + + @Test + public void testMyUnion_VariantC() throws Exception { + String json = "{\"valueC\":true}"; + MyUnion union = ObjectMappers.JSON_MAPPER.readValue(json, MyUnion.class); + assertTrue(union.get() instanceof VariantC, "Expected VariantC but got different variant"); + } +} diff --git a/seed/java-sdk/undiscriminated-unions/reference.md b/seed/java-sdk/undiscriminated-unions/reference.md index 7edfbbe9ca74..4117ea051ff4 100644 --- a/seed/java-sdk/undiscriminated-unions/reference.md +++ b/seed/java-sdk/undiscriminated-unions/reference.md @@ -252,6 +252,96 @@ client.union().nestedUnions( + + + + +

client.union.nestedObjectUnions(request) -> String +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.union().nestedObjectUnions( + OuterNestedUnion.of("string") +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `OuterNestedUnion` + +
+
+
+
+ + +
+
+
+ +
client.union.aliasedObjectUnion(request) -> String +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```java +client.union().aliasedObjectUnion( + AliasedObjectUnion.of( + LeafObjectA + .builder() + .onlyInA("onlyInA") + .sharedNumber(1) + .build() + ) +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `AliasedObjectUnion` + +
+
+
+
+ +
diff --git a/seed/java-sdk/undiscriminated-unions/snippet.json b/seed/java-sdk/undiscriminated-unions/snippet.json index fcb6d88f490f..fd7543db5e9e 100644 --- a/seed/java-sdk/undiscriminated-unions/snippet.json +++ b/seed/java-sdk/undiscriminated-unions/snippet.json @@ -117,6 +117,32 @@ "async_client": "package com.example.usage;\n\nimport com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient;\nimport com.seed.undiscriminatedUnions.resources.union.types.NestedUnionRoot;\n\npublic class Example {\n public static void main(String[] args) {\n SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient\n .builder()\n .build();\n\n client.union().nestedUnions(\n NestedUnionRoot.of(\"string\")\n );\n }\n}\n" } }, + { + "example_identifier": "7ae22e69", + "id": { + "method": "POST", + "path": "/nested-objects", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "java", + "sync_client": "package com.example.usage;\n\nimport com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient;\nimport com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion;\n\npublic class Example {\n public static void main(String[] args) {\n SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient\n .builder()\n .build();\n\n client.union().nestedObjectUnions(\n OuterNestedUnion.of(\"string\")\n );\n }\n}\n", + "async_client": "package com.example.usage;\n\nimport com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient;\nimport com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion;\n\npublic class Example {\n public static void main(String[] args) {\n SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient\n .builder()\n .build();\n\n client.union().nestedObjectUnions(\n OuterNestedUnion.of(\"string\")\n );\n }\n}\n" + } + }, + { + "example_identifier": "b3d21111", + "id": { + "method": "POST", + "path": "/aliased-object", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "java", + "sync_client": "package com.example.usage;\n\nimport com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient;\nimport com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion;\nimport com.seed.undiscriminatedUnions.resources.union.types.LeafObjectA;\n\npublic class Example {\n public static void main(String[] args) {\n SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient\n .builder()\n .build();\n\n client.union().aliasedObjectUnion(\n AliasedObjectUnion.of(\n LeafObjectA\n .builder()\n .onlyInA(\"onlyInA\")\n .sharedNumber(1)\n .build()\n )\n );\n }\n}\n", + "async_client": "package com.example.usage;\n\nimport com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient;\nimport com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion;\nimport com.seed.undiscriminatedUnions.resources.union.types.LeafObjectA;\n\npublic class Example {\n public static void main(String[] args) {\n SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient\n .builder()\n .build();\n\n client.union().aliasedObjectUnion(\n AliasedObjectUnion.of(\n LeafObjectA\n .builder()\n .onlyInA(\"onlyInA\")\n .sharedNumber(1)\n .build()\n )\n );\n }\n}\n" + } + }, { "example_identifier": "9577442f", "id": { diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncRawUnionClient.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncRawUnionClient.java index 9218663c43c7..872d6f73bdb2 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncRawUnionClient.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncRawUnionClient.java @@ -13,10 +13,12 @@ import com.seed.undiscriminatedUnions.core.SeedUndiscriminatedUnionsException; import com.seed.undiscriminatedUnions.core.SeedUndiscriminatedUnionsHttpResponse; import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; +import com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion; import com.seed.undiscriminatedUnions.resources.union.types.Key; import com.seed.undiscriminatedUnions.resources.union.types.MetadataUnion; import com.seed.undiscriminatedUnions.resources.union.types.MyUnion; import com.seed.undiscriminatedUnions.resources.union.types.NestedUnionRoot; +import com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithBaseProperties; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithDuplicateTypes; import java.io.IOException; @@ -434,6 +436,132 @@ public void onFailure(@NotNull Call call, @NotNull IOException e) { return future; } + public CompletableFuture> nestedObjectUnions( + OuterNestedUnion request) { + return nestedObjectUnions(request, null); + } + + public CompletableFuture> nestedObjectUnions( + OuterNestedUnion request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("nested-objects"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new SeedUndiscriminatedUnionsException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new SeedUndiscriminatedUnionsHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, String.class), response)); + return; + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new SeedUndiscriminatedUnionsApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (IOException e) { + future.completeExceptionally( + new SeedUndiscriminatedUnionsException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally( + new SeedUndiscriminatedUnionsException("Network error executing HTTP request", e)); + } + }); + return future; + } + + public CompletableFuture> aliasedObjectUnion( + AliasedObjectUnion request) { + return aliasedObjectUnion(request, null); + } + + public CompletableFuture> aliasedObjectUnion( + AliasedObjectUnion request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("aliased-object"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new SeedUndiscriminatedUnionsException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + CompletableFuture> future = new CompletableFuture<>(); + client.newCall(okhttpRequest).enqueue(new Callback() { + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { + try (ResponseBody responseBody = response.body()) { + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + future.complete(new SeedUndiscriminatedUnionsHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, String.class), response)); + return; + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + future.completeExceptionally(new SeedUndiscriminatedUnionsApiException( + "Error with status code " + response.code(), response.code(), errorBody, response)); + return; + } catch (IOException e) { + future.completeExceptionally( + new SeedUndiscriminatedUnionsException("Network error executing HTTP request", e)); + } + } + + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + future.completeExceptionally( + new SeedUndiscriminatedUnionsException("Network error executing HTTP request", e)); + } + }); + return future; + } + public CompletableFuture> getWithBaseProperties( UnionWithBaseProperties request) { return getWithBaseProperties(request, null); diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncUnionClient.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncUnionClient.java index 85bd16316628..a69e3a52192a 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncUnionClient.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/AsyncUnionClient.java @@ -6,10 +6,12 @@ import com.seed.undiscriminatedUnions.core.ClientOptions; import com.seed.undiscriminatedUnions.core.RequestOptions; import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; +import com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion; import com.seed.undiscriminatedUnions.resources.union.types.Key; import com.seed.undiscriminatedUnions.resources.union.types.MetadataUnion; import com.seed.undiscriminatedUnions.resources.union.types.MyUnion; import com.seed.undiscriminatedUnions.resources.union.types.NestedUnionRoot; +import com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion; import com.seed.undiscriminatedUnions.resources.union.types.Request; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithBaseProperties; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithDuplicateTypes; @@ -90,6 +92,22 @@ public CompletableFuture nestedUnions(NestedUnionRoot request, RequestOp return this.rawClient.nestedUnions(request, requestOptions).thenApply(response -> response.body()); } + public CompletableFuture nestedObjectUnions(OuterNestedUnion request) { + return this.rawClient.nestedObjectUnions(request).thenApply(response -> response.body()); + } + + public CompletableFuture nestedObjectUnions(OuterNestedUnion request, RequestOptions requestOptions) { + return this.rawClient.nestedObjectUnions(request, requestOptions).thenApply(response -> response.body()); + } + + public CompletableFuture aliasedObjectUnion(AliasedObjectUnion request) { + return this.rawClient.aliasedObjectUnion(request).thenApply(response -> response.body()); + } + + public CompletableFuture aliasedObjectUnion(AliasedObjectUnion request, RequestOptions requestOptions) { + return this.rawClient.aliasedObjectUnion(request, requestOptions).thenApply(response -> response.body()); + } + public CompletableFuture getWithBaseProperties(UnionWithBaseProperties request) { return this.rawClient.getWithBaseProperties(request).thenApply(response -> response.body()); } diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/RawUnionClient.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/RawUnionClient.java index 6d379c9345fd..4eaf580809d3 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/RawUnionClient.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/RawUnionClient.java @@ -13,10 +13,12 @@ import com.seed.undiscriminatedUnions.core.SeedUndiscriminatedUnionsException; import com.seed.undiscriminatedUnions.core.SeedUndiscriminatedUnionsHttpResponse; import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; +import com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion; import com.seed.undiscriminatedUnions.resources.union.types.Key; import com.seed.undiscriminatedUnions.resources.union.types.MetadataUnion; import com.seed.undiscriminatedUnions.resources.union.types.MyUnion; import com.seed.undiscriminatedUnions.resources.union.types.NestedUnionRoot; +import com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithBaseProperties; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithDuplicateTypes; import java.io.IOException; @@ -337,6 +339,100 @@ public SeedUndiscriminatedUnionsHttpResponse nestedUnions( } } + public SeedUndiscriminatedUnionsHttpResponse nestedObjectUnions(OuterNestedUnion request) { + return nestedObjectUnions(request, null); + } + + public SeedUndiscriminatedUnionsHttpResponse nestedObjectUnions( + OuterNestedUnion request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("nested-objects"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new SeedUndiscriminatedUnionsException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new SeedUndiscriminatedUnionsHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, String.class), response); + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new SeedUndiscriminatedUnionsApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (IOException e) { + throw new SeedUndiscriminatedUnionsException("Network error executing HTTP request", e); + } + } + + public SeedUndiscriminatedUnionsHttpResponse aliasedObjectUnion(AliasedObjectUnion request) { + return aliasedObjectUnion(request, null); + } + + public SeedUndiscriminatedUnionsHttpResponse aliasedObjectUnion( + AliasedObjectUnion request, RequestOptions requestOptions) { + HttpUrl.Builder httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("aliased-object"); + if (requestOptions != null) { + requestOptions.getQueryParameters().forEach((_key, _value) -> { + httpUrl.addQueryParameter(_key, _value); + }); + } + RequestBody body; + try { + body = RequestBody.create( + ObjectMappers.JSON_MAPPER.writeValueAsBytes(request), MediaTypes.APPLICATION_JSON); + } catch (JsonProcessingException e) { + throw new SeedUndiscriminatedUnionsException("Failed to serialize request", e); + } + Request okhttpRequest = new Request.Builder() + .url(httpUrl.build()) + .method("POST", body) + .headers(Headers.of(clientOptions.headers(requestOptions))) + .addHeader("Content-Type", "application/json") + .addHeader("Accept", "application/json") + .build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + if (response.isSuccessful()) { + return new SeedUndiscriminatedUnionsHttpResponse<>( + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, String.class), response); + } + Object errorBody = ObjectMappers.parseErrorBody(responseBodyString); + throw new SeedUndiscriminatedUnionsApiException( + "Error with status code " + response.code(), response.code(), errorBody, response); + } catch (IOException e) { + throw new SeedUndiscriminatedUnionsException("Network error executing HTTP request", e); + } + } + public SeedUndiscriminatedUnionsHttpResponse getWithBaseProperties( UnionWithBaseProperties request) { return getWithBaseProperties(request, null); diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/UnionClient.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/UnionClient.java index 5d8a9a1d8b3e..b63e18151abc 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/UnionClient.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/UnionClient.java @@ -6,10 +6,12 @@ import com.seed.undiscriminatedUnions.core.ClientOptions; import com.seed.undiscriminatedUnions.core.RequestOptions; import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; +import com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion; import com.seed.undiscriminatedUnions.resources.union.types.Key; import com.seed.undiscriminatedUnions.resources.union.types.MetadataUnion; import com.seed.undiscriminatedUnions.resources.union.types.MyUnion; import com.seed.undiscriminatedUnions.resources.union.types.NestedUnionRoot; +import com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion; import com.seed.undiscriminatedUnions.resources.union.types.Request; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithBaseProperties; import com.seed.undiscriminatedUnions.resources.union.types.UnionWithDuplicateTypes; @@ -88,6 +90,22 @@ public String nestedUnions(NestedUnionRoot request, RequestOptions requestOption return this.rawClient.nestedUnions(request, requestOptions).body(); } + public String nestedObjectUnions(OuterNestedUnion request) { + return this.rawClient.nestedObjectUnions(request).body(); + } + + public String nestedObjectUnions(OuterNestedUnion request, RequestOptions requestOptions) { + return this.rawClient.nestedObjectUnions(request, requestOptions).body(); + } + + public String aliasedObjectUnion(AliasedObjectUnion request) { + return this.rawClient.aliasedObjectUnion(request).body(); + } + + public String aliasedObjectUnion(AliasedObjectUnion request, RequestOptions requestOptions) { + return this.rawClient.aliasedObjectUnion(request, requestOptions).body(); + } + public UnionWithBaseProperties getWithBaseProperties(UnionWithBaseProperties request) { return this.rawClient.getWithBaseProperties(request).body(); } diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/AliasedObjectUnion.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/AliasedObjectUnion.java new file mode 100644 index 000000000000..64d692e1cb5d --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/AliasedObjectUnion.java @@ -0,0 +1,102 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.io.IOException; +import java.util.Map; +import java.util.Objects; + +@JsonDeserialize(using = AliasedObjectUnion.Deserializer.class) +public final class AliasedObjectUnion { + private final Object value; + + private final int type; + + private AliasedObjectUnion(Object value, int type) { + this.value = value; + this.type = type; + } + + @JsonValue + public Object get() { + return this.value; + } + + @SuppressWarnings("unchecked") + public T visit(Visitor visitor) { + if (this.type == 0) { + return visitor.visit((LeafObjectA) this.value); + } else if (this.type == 1) { + return visitor.visit((LeafObjectB) this.value); + } + throw new IllegalStateException("Failed to visit value. This should never happen."); + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof AliasedObjectUnion && equalTo((AliasedObjectUnion) other); + } + + private boolean equalTo(AliasedObjectUnion other) { + return value.equals(other.value); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.value); + } + + @java.lang.Override + public String toString() { + return this.value.toString(); + } + + public static AliasedObjectUnion of(LeafObjectA value) { + return new AliasedObjectUnion(value, 0); + } + + public static AliasedObjectUnion of(LeafObjectB value) { + return new AliasedObjectUnion(value, 1); + } + + public interface Visitor { + T visit(LeafObjectA value); + + T visit(LeafObjectB value); + } + + static final class Deserializer extends StdDeserializer { + Deserializer() { + super(AliasedObjectUnion.class); + } + + @java.lang.Override + public AliasedObjectUnion deserialize(JsonParser p, DeserializationContext context) throws IOException { + Object value = p.readValueAs(Object.class); + if (value instanceof Map + && ((Map) value).containsKey("onlyInA") + && ((Map) value).containsKey("sharedNumber")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, LeafObjectA.class)); + } catch (RuntimeException e) { + } + } + if (value instanceof Map && ((Map) value).containsKey("onlyInB")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, LeafObjectB.class)); + } catch (RuntimeException e) { + } + } + throw new JsonParseException(p, "Failed to deserialize"); + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafObjectA.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafObjectA.java new file mode 100644 index 000000000000..1e21e4a442b1 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafObjectA.java @@ -0,0 +1,140 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = LeafObjectA.Builder.class) +public final class LeafObjectA { + private final String onlyInA; + + private final int sharedNumber; + + private final Map additionalProperties; + + private LeafObjectA(String onlyInA, int sharedNumber, Map additionalProperties) { + this.onlyInA = onlyInA; + this.sharedNumber = sharedNumber; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("onlyInA") + public String getOnlyInA() { + return onlyInA; + } + + @JsonProperty("sharedNumber") + public int getSharedNumber() { + return sharedNumber; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof LeafObjectA && equalTo((LeafObjectA) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(LeafObjectA other) { + return onlyInA.equals(other.onlyInA) && sharedNumber == other.sharedNumber; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.onlyInA, this.sharedNumber); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static OnlyInAStage builder() { + return new Builder(); + } + + public interface OnlyInAStage { + SharedNumberStage onlyInA(@NotNull String onlyInA); + + Builder from(LeafObjectA other); + } + + public interface SharedNumberStage { + _FinalStage sharedNumber(int sharedNumber); + } + + public interface _FinalStage { + LeafObjectA build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements OnlyInAStage, SharedNumberStage, _FinalStage { + private String onlyInA; + + private int sharedNumber; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(LeafObjectA other) { + onlyInA(other.getOnlyInA()); + sharedNumber(other.getSharedNumber()); + return this; + } + + @java.lang.Override + @JsonSetter("onlyInA") + public SharedNumberStage onlyInA(@NotNull String onlyInA) { + this.onlyInA = Objects.requireNonNull(onlyInA, "onlyInA must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("sharedNumber") + public _FinalStage sharedNumber(int sharedNumber) { + this.sharedNumber = sharedNumber; + return this; + } + + @java.lang.Override + public LeafObjectA build() { + return new LeafObjectA(onlyInA, sharedNumber, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafObjectB.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafObjectB.java new file mode 100644 index 000000000000..c0e1cec27af1 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafObjectB.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = LeafObjectB.Builder.class) +public final class LeafObjectB { + private final String onlyInB; + + private final Map additionalProperties; + + private LeafObjectB(String onlyInB, Map additionalProperties) { + this.onlyInB = onlyInB; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("onlyInB") + public String getOnlyInB() { + return onlyInB; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof LeafObjectB && equalTo((LeafObjectB) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(LeafObjectB other) { + return onlyInB.equals(other.onlyInB); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.onlyInB); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static OnlyInBStage builder() { + return new Builder(); + } + + public interface OnlyInBStage { + _FinalStage onlyInB(@NotNull String onlyInB); + + Builder from(LeafObjectB other); + } + + public interface _FinalStage { + LeafObjectB build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements OnlyInBStage, _FinalStage { + private String onlyInB; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(LeafObjectB other) { + onlyInB(other.getOnlyInB()); + return this; + } + + @java.lang.Override + @JsonSetter("onlyInB") + public _FinalStage onlyInB(@NotNull String onlyInB) { + this.onlyInB = Objects.requireNonNull(onlyInB, "onlyInB must not be null"); + return this; + } + + @java.lang.Override + public LeafObjectB build() { + return new LeafObjectB(onlyInB, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafTypeA.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafTypeA.java new file mode 100644 index 000000000000..7feb87d8f1bf --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafTypeA.java @@ -0,0 +1,140 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = LeafTypeA.Builder.class) +public final class LeafTypeA { + private final String alpha; + + private final int beta; + + private final Map additionalProperties; + + private LeafTypeA(String alpha, int beta, Map additionalProperties) { + this.alpha = alpha; + this.beta = beta; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("alpha") + public String getAlpha() { + return alpha; + } + + @JsonProperty("beta") + public int getBeta() { + return beta; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof LeafTypeA && equalTo((LeafTypeA) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(LeafTypeA other) { + return alpha.equals(other.alpha) && beta == other.beta; + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.alpha, this.beta); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static AlphaStage builder() { + return new Builder(); + } + + public interface AlphaStage { + BetaStage alpha(@NotNull String alpha); + + Builder from(LeafTypeA other); + } + + public interface BetaStage { + _FinalStage beta(int beta); + } + + public interface _FinalStage { + LeafTypeA build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements AlphaStage, BetaStage, _FinalStage { + private String alpha; + + private int beta; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(LeafTypeA other) { + alpha(other.getAlpha()); + beta(other.getBeta()); + return this; + } + + @java.lang.Override + @JsonSetter("alpha") + public BetaStage alpha(@NotNull String alpha) { + this.alpha = Objects.requireNonNull(alpha, "alpha must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("beta") + public _FinalStage beta(int beta) { + this.beta = beta; + return this; + } + + @java.lang.Override + public LeafTypeA build() { + return new LeafTypeA(alpha, beta, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafTypeB.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafTypeB.java new file mode 100644 index 000000000000..7bcc1f010f91 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/LeafTypeB.java @@ -0,0 +1,118 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = LeafTypeB.Builder.class) +public final class LeafTypeB { + private final String gamma; + + private final Map additionalProperties; + + private LeafTypeB(String gamma, Map additionalProperties) { + this.gamma = gamma; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("gamma") + public String getGamma() { + return gamma; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof LeafTypeB && equalTo((LeafTypeB) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(LeafTypeB other) { + return gamma.equals(other.gamma); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.gamma); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static GammaStage builder() { + return new Builder(); + } + + public interface GammaStage { + _FinalStage gamma(@NotNull String gamma); + + Builder from(LeafTypeB other); + } + + public interface _FinalStage { + LeafTypeB build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements GammaStage, _FinalStage { + private String gamma; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(LeafTypeB other) { + gamma(other.getGamma()); + return this; + } + + @java.lang.Override + @JsonSetter("gamma") + public _FinalStage gamma(@NotNull String gamma) { + this.gamma = Objects.requireNonNull(gamma, "gamma must not be null"); + return this; + } + + @java.lang.Override + public LeafTypeB build() { + return new LeafTypeB(gamma, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/MetadataUnion.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/MetadataUnion.java index d04ac8506111..947c09be8008 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/MetadataUnion.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/MetadataUnion.java @@ -89,9 +89,13 @@ public MetadataUnion deserialize(JsonParser p, DeserializationContext context) t value, new TypeReference>>() {})); } catch (RuntimeException e) { } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, NamedMetadata.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("value")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, NamedMetadata.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/NestedObjectUnion.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/NestedObjectUnion.java new file mode 100644 index 000000000000..91ab410f3ac3 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/NestedObjectUnion.java @@ -0,0 +1,102 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.io.IOException; +import java.util.Map; +import java.util.Objects; + +@JsonDeserialize(using = NestedObjectUnion.Deserializer.class) +public final class NestedObjectUnion { + private final Object value; + + private final int type; + + private NestedObjectUnion(Object value, int type) { + this.value = value; + this.type = type; + } + + @JsonValue + public Object get() { + return this.value; + } + + @SuppressWarnings("unchecked") + public T visit(Visitor visitor) { + if (this.type == 0) { + return visitor.visit((LeafTypeA) this.value); + } else if (this.type == 1) { + return visitor.visit((LeafTypeB) this.value); + } + throw new IllegalStateException("Failed to visit value. This should never happen."); + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof NestedObjectUnion && equalTo((NestedObjectUnion) other); + } + + private boolean equalTo(NestedObjectUnion other) { + return value.equals(other.value); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.value); + } + + @java.lang.Override + public String toString() { + return this.value.toString(); + } + + public static NestedObjectUnion of(LeafTypeA value) { + return new NestedObjectUnion(value, 0); + } + + public static NestedObjectUnion of(LeafTypeB value) { + return new NestedObjectUnion(value, 1); + } + + public interface Visitor { + T visit(LeafTypeA value); + + T visit(LeafTypeB value); + } + + static final class Deserializer extends StdDeserializer { + Deserializer() { + super(NestedObjectUnion.class); + } + + @java.lang.Override + public NestedObjectUnion deserialize(JsonParser p, DeserializationContext context) throws IOException { + Object value = p.readValueAs(Object.class); + if (value instanceof Map + && ((Map) value).containsKey("alpha") + && ((Map) value).containsKey("beta")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, LeafTypeA.class)); + } catch (RuntimeException e) { + } + } + if (value instanceof Map && ((Map) value).containsKey("gamma")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, LeafTypeB.class)); + } catch (RuntimeException e) { + } + } + throw new JsonParseException(p, "Failed to deserialize"); + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/OuterNestedUnion.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/OuterNestedUnion.java new file mode 100644 index 000000000000..fcfda11352f0 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/OuterNestedUnion.java @@ -0,0 +1,100 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.io.IOException; +import java.util.Map; +import java.util.Objects; + +@JsonDeserialize(using = OuterNestedUnion.Deserializer.class) +public final class OuterNestedUnion { + private final Object value; + + private final int type; + + private OuterNestedUnion(Object value, int type) { + this.value = value; + this.type = type; + } + + @JsonValue + public Object get() { + return this.value; + } + + @SuppressWarnings("unchecked") + public T visit(Visitor visitor) { + if (this.type == 0) { + return visitor.visit((String) this.value); + } else if (this.type == 1) { + return visitor.visit((WrapperObject) this.value); + } + throw new IllegalStateException("Failed to visit value. This should never happen."); + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof OuterNestedUnion && equalTo((OuterNestedUnion) other); + } + + private boolean equalTo(OuterNestedUnion other) { + return value.equals(other.value); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.value); + } + + @java.lang.Override + public String toString() { + return this.value.toString(); + } + + public static OuterNestedUnion of(String value) { + return new OuterNestedUnion(value, 0); + } + + public static OuterNestedUnion of(WrapperObject value) { + return new OuterNestedUnion(value, 1); + } + + public interface Visitor { + T visit(String value); + + T visit(WrapperObject value); + } + + static final class Deserializer extends StdDeserializer { + Deserializer() { + super(OuterNestedUnion.class); + } + + @java.lang.Override + public OuterNestedUnion deserialize(JsonParser p, DeserializationContext context) throws IOException { + Object value = p.readValueAs(Object.class); + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, String.class)); + } catch (RuntimeException e) { + } + if (value instanceof Map + && ((Map) value).containsKey("inner") + && ((Map) value).containsKey("label")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, WrapperObject.class)); + } catch (RuntimeException e) { + } + } + throw new JsonParseException(p, "Failed to deserialize"); + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/PaymentMethodUnion.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/PaymentMethodUnion.java index 7c760806bec7..2996c0bab298 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/PaymentMethodUnion.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/PaymentMethodUnion.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.seed.undiscriminatedUnions.core.ObjectMappers; import java.io.IOException; +import java.util.Map; import java.util.Objects; @JsonDeserialize(using = PaymentMethodUnion.Deserializer.class) @@ -81,13 +82,21 @@ static final class Deserializer extends StdDeserializer { @java.lang.Override public PaymentMethodUnion deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, TokenizeCard.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("method") + && ((Map) value).containsKey("cardNumber")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, TokenizeCard.class)); + } catch (RuntimeException e) { + } } - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, ConvertToken.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("method") + && ((Map) value).containsKey("tokenId")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, ConvertToken.class)); + } catch (RuntimeException e) { + } } throw new JsonParseException(p, "Failed to deserialize"); } diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/UnionWithBaseProperties.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/UnionWithBaseProperties.java index e6a1aab5bd23..13d7edac73d9 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/UnionWithBaseProperties.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/UnionWithBaseProperties.java @@ -84,9 +84,13 @@ static final class Deserializer extends StdDeserializer @java.lang.Override public UnionWithBaseProperties deserialize(JsonParser p, DeserializationContext context) throws IOException { Object value = p.readValueAs(Object.class); - try { - return of(ObjectMappers.JSON_MAPPER.convertValue(value, NamedMetadata.class)); - } catch (RuntimeException e) { + if (value instanceof Map + && ((Map) value).containsKey("name") + && ((Map) value).containsKey("value")) { + try { + return of(ObjectMappers.JSON_MAPPER.convertValue(value, NamedMetadata.class)); + } catch (RuntimeException e) { + } } try { return of(ObjectMappers.JSON_MAPPER.convertValue( diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/WrapperObject.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/WrapperObject.java new file mode 100644 index 000000000000..839ec0c3a62c --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/seed/undiscriminatedUnions/resources/union/types/WrapperObject.java @@ -0,0 +1,140 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions.resources.union.types; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = WrapperObject.Builder.class) +public final class WrapperObject { + private final NestedObjectUnion inner; + + private final String label; + + private final Map additionalProperties; + + private WrapperObject(NestedObjectUnion inner, String label, Map additionalProperties) { + this.inner = inner; + this.label = label; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("inner") + public NestedObjectUnion getInner() { + return inner; + } + + @JsonProperty("label") + public String getLabel() { + return label; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof WrapperObject && equalTo((WrapperObject) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(WrapperObject other) { + return inner.equals(other.inner) && label.equals(other.label); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.inner, this.label); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static InnerStage builder() { + return new Builder(); + } + + public interface InnerStage { + LabelStage inner(@NotNull NestedObjectUnion inner); + + Builder from(WrapperObject other); + } + + public interface LabelStage { + _FinalStage label(@NotNull String label); + } + + public interface _FinalStage { + WrapperObject build(); + + _FinalStage additionalProperty(String key, Object value); + + _FinalStage additionalProperties(Map additionalProperties); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements InnerStage, LabelStage, _FinalStage { + private NestedObjectUnion inner; + + private String label; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(WrapperObject other) { + inner(other.getInner()); + label(other.getLabel()); + return this; + } + + @java.lang.Override + @JsonSetter("inner") + public LabelStage inner(@NotNull NestedObjectUnion inner) { + this.inner = Objects.requireNonNull(inner, "inner must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("label") + public _FinalStage label(@NotNull String label) { + this.label = Objects.requireNonNull(label, "label must not be null"); + return this; + } + + @java.lang.Override + public WrapperObject build() { + return new WrapperObject(inner, label, additionalProperties); + } + + @java.lang.Override + public Builder additionalProperty(String key, Object value) { + this.additionalProperties.put(key, value); + return this; + } + + @java.lang.Override + public Builder additionalProperties(Map additionalProperties) { + this.additionalProperties.putAll(additionalProperties); + return this; + } + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example10.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example10.java index 8c7721590462..0db9717bef81 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example10.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example10.java @@ -1,9 +1,8 @@ package com.snippets; import com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient; -import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; -import com.seed.undiscriminatedUnions.resources.union.types.PaymentMethodUnion; -import com.seed.undiscriminatedUnions.resources.union.types.TokenizeCard; +import com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion; +import com.seed.undiscriminatedUnions.resources.union.types.LeafObjectA; public class Example10 { public static void main(String[] args) { @@ -12,11 +11,7 @@ public static void main(String[] args) { .build(); client.union() - .testCamelCaseProperties(PaymentRequest.builder() - .paymentMethod(PaymentMethodUnion.of(TokenizeCard.builder() - .method("card") - .cardNumber("1234567890123456") - .build())) - .build()); + .aliasedObjectUnion(AliasedObjectUnion.of( + LeafObjectA.builder().onlyInA("onlyInA").sharedNumber(1).build())); } } diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example11.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example11.java index 8410746d3ae0..9f432cb91a68 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example11.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example11.java @@ -1,9 +1,9 @@ package com.snippets; import com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient; -import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; -import com.seed.undiscriminatedUnions.resources.union.types.PaymentMethodUnion; -import com.seed.undiscriminatedUnions.resources.union.types.TokenizeCard; +import com.seed.undiscriminatedUnions.resources.union.types.NamedMetadata; +import com.seed.undiscriminatedUnions.resources.union.types.UnionWithBaseProperties; +import java.util.HashMap; public class Example11 { public static void main(String[] args) { @@ -12,11 +12,17 @@ public static void main(String[] args) { .build(); client.union() - .testCamelCaseProperties(PaymentRequest.builder() - .paymentMethod(PaymentMethodUnion.of(TokenizeCard.builder() - .method("method") - .cardNumber("cardNumber") - .build())) - .build()); + .getWithBaseProperties(UnionWithBaseProperties.of(NamedMetadata.builder() + .name("name") + .value(new HashMap() { + { + put("value", new HashMap() { + { + put("key", "value"); + } + }); + } + }) + .build())); } } diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example12.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example12.java new file mode 100644 index 000000000000..3498de340781 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example12.java @@ -0,0 +1,22 @@ +package com.snippets; + +import com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient; +import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; +import com.seed.undiscriminatedUnions.resources.union.types.PaymentMethodUnion; +import com.seed.undiscriminatedUnions.resources.union.types.TokenizeCard; + +public class Example12 { + public static void main(String[] args) { + SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient.builder() + .url("https://api.fern.com") + .build(); + + client.union() + .testCamelCaseProperties(PaymentRequest.builder() + .paymentMethod(PaymentMethodUnion.of(TokenizeCard.builder() + .method("card") + .cardNumber("1234567890123456") + .build())) + .build()); + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example13.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example13.java new file mode 100644 index 000000000000..d23a0ff44b1e --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example13.java @@ -0,0 +1,22 @@ +package com.snippets; + +import com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient; +import com.seed.undiscriminatedUnions.resources.union.requests.PaymentRequest; +import com.seed.undiscriminatedUnions.resources.union.types.PaymentMethodUnion; +import com.seed.undiscriminatedUnions.resources.union.types.TokenizeCard; + +public class Example13 { + public static void main(String[] args) { + SeedUndiscriminatedUnionsClient client = SeedUndiscriminatedUnionsClient.builder() + .url("https://api.fern.com") + .build(); + + client.union() + .testCamelCaseProperties(PaymentRequest.builder() + .paymentMethod(PaymentMethodUnion.of(TokenizeCard.builder() + .method("method") + .cardNumber("cardNumber") + .build())) + .build()); + } +} diff --git a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example9.java b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example9.java index 28c932af3fc2..1671d9a471db 100644 --- a/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example9.java +++ b/seed/java-sdk/undiscriminated-unions/src/main/java/com/snippets/Example9.java @@ -1,9 +1,7 @@ package com.snippets; import com.seed.undiscriminatedUnions.SeedUndiscriminatedUnionsClient; -import com.seed.undiscriminatedUnions.resources.union.types.NamedMetadata; -import com.seed.undiscriminatedUnions.resources.union.types.UnionWithBaseProperties; -import java.util.HashMap; +import com.seed.undiscriminatedUnions.resources.union.types.OuterNestedUnion; public class Example9 { public static void main(String[] args) { @@ -11,18 +9,6 @@ public static void main(String[] args) { .url("https://api.fern.com") .build(); - client.union() - .getWithBaseProperties(UnionWithBaseProperties.of(NamedMetadata.builder() - .name("name") - .value(new HashMap() { - { - put("value", new HashMap() { - { - put("key", "value"); - } - }); - } - }) - .build())); + client.union().nestedObjectUnions(OuterNestedUnion.of("string")); } } diff --git a/seed/java-sdk/undiscriminated-unions/src/test/java/com/seed/undiscriminatedUnions/UndiscriminatedUnionTest.java b/seed/java-sdk/undiscriminated-unions/src/test/java/com/seed/undiscriminatedUnions/UndiscriminatedUnionTest.java new file mode 100644 index 000000000000..1ef5b6100c52 --- /dev/null +++ b/seed/java-sdk/undiscriminated-unions/src/test/java/com/seed/undiscriminatedUnions/UndiscriminatedUnionTest.java @@ -0,0 +1,62 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.undiscriminatedUnions; + +import static org.junit.jupiter.api.Assertions.*; + +import com.seed.undiscriminatedUnions.core.ObjectMappers; +import com.seed.undiscriminatedUnions.resources.union.types.AliasedObjectUnion; +import com.seed.undiscriminatedUnions.resources.union.types.ConvertToken; +import com.seed.undiscriminatedUnions.resources.union.types.LeafObjectA; +import com.seed.undiscriminatedUnions.resources.union.types.LeafObjectB; +import com.seed.undiscriminatedUnions.resources.union.types.LeafTypeA; +import com.seed.undiscriminatedUnions.resources.union.types.LeafTypeB; +import com.seed.undiscriminatedUnions.resources.union.types.NestedObjectUnion; +import com.seed.undiscriminatedUnions.resources.union.types.PaymentMethodUnion; +import com.seed.undiscriminatedUnions.resources.union.types.TokenizeCard; +import org.junit.jupiter.api.Test; + +public final class UndiscriminatedUnionTest { + @Test + public void testPaymentMethodUnion_TokenizeCard() throws Exception { + String json = "{\"method\":\"test\",\"cardNumber\":\"test\"}"; + PaymentMethodUnion union = ObjectMappers.JSON_MAPPER.readValue(json, PaymentMethodUnion.class); + assertTrue(union.get() instanceof TokenizeCard, "Expected TokenizeCard but got different variant"); + } + + @Test + public void testPaymentMethodUnion_ConvertToken() throws Exception { + String json = "{\"method\":\"test\",\"tokenId\":\"test\"}"; + PaymentMethodUnion union = ObjectMappers.JSON_MAPPER.readValue(json, PaymentMethodUnion.class); + assertTrue(union.get() instanceof ConvertToken, "Expected ConvertToken but got different variant"); + } + + @Test + public void testNestedObjectUnion_LeafTypeA() throws Exception { + String json = "{\"alpha\":\"test\",\"beta\":1}"; + NestedObjectUnion union = ObjectMappers.JSON_MAPPER.readValue(json, NestedObjectUnion.class); + assertTrue(union.get() instanceof LeafTypeA, "Expected LeafTypeA but got different variant"); + } + + @Test + public void testNestedObjectUnion_LeafTypeB() throws Exception { + String json = "{\"gamma\":\"test\"}"; + NestedObjectUnion union = ObjectMappers.JSON_MAPPER.readValue(json, NestedObjectUnion.class); + assertTrue(union.get() instanceof LeafTypeB, "Expected LeafTypeB but got different variant"); + } + + @Test + public void testAliasedObjectUnion_LeafObjectA() throws Exception { + String json = "{\"onlyInA\":\"test\",\"sharedNumber\":1}"; + AliasedObjectUnion union = ObjectMappers.JSON_MAPPER.readValue(json, AliasedObjectUnion.class); + assertTrue(union.get() instanceof LeafObjectA, "Expected LeafObjectA but got different variant"); + } + + @Test + public void testAliasedObjectUnion_LeafObjectB() throws Exception { + String json = "{\"onlyInB\":\"test\"}"; + AliasedObjectUnion union = ObjectMappers.JSON_MAPPER.readValue(json, AliasedObjectUnion.class); + assertTrue(union.get() instanceof LeafObjectB, "Expected LeafObjectB but got different variant"); + } +} diff --git a/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtime/websocket/RealtimeWebSocketClient.java b/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtime/websocket/RealtimeWebSocketClient.java index 40042cc57b03..8ea7a1bf4407 100644 --- a/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtime/websocket/RealtimeWebSocketClient.java +++ b/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtime/websocket/RealtimeWebSocketClient.java @@ -345,50 +345,62 @@ private void handleIncomingMessage(String json) { if (node == null || node.isNull()) { throw new IllegalArgumentException("Received null or invalid JSON message"); } - JsonNode typeNode = node.get("type"); - if (typeNode == null || typeNode.isNull()) { - throw new IllegalArgumentException("Message missing 'type' field"); + if (node.has("gamma") && node.has("delta") && node.has("epsilon")) { + ReceiveEvent2 receive2HandlerEvent = null; + try { + receive2HandlerEvent = objectMapper.treeToValue(node, ReceiveEvent2.class); + } catch (Exception e) { + } + if (receive2HandlerEvent != null) { + if (receive2Handler != null) { + receive2Handler.accept(receive2HandlerEvent); + } + return; + } } - String type = typeNode.asText(); - switch (type) { - case "receive": + if (node.has("alpha") && node.has("beta")) { + ReceiveEvent receiveHandlerEvent = null; + try { + receiveHandlerEvent = objectMapper.treeToValue(node, ReceiveEvent.class); + } catch (Exception e) { + } + if (receiveHandlerEvent != null) { if (receiveHandler != null) { - ReceiveEvent event = objectMapper.treeToValue(node, ReceiveEvent.class); - if (event != null) { - receiveHandler.accept(event); - } + receiveHandler.accept(receiveHandlerEvent); } - break; - case "receive_snake_case": + return; + } + } + if (node.has("receive_text") && node.has("receive_int")) { + ReceiveSnakeCase receiveSnakeCaseHandlerEvent = null; + try { + receiveSnakeCaseHandlerEvent = objectMapper.treeToValue(node, ReceiveSnakeCase.class); + } catch (Exception e) { + } + if (receiveSnakeCaseHandlerEvent != null) { if (receiveSnakeCaseHandler != null) { - ReceiveSnakeCase event = objectMapper.treeToValue(node, ReceiveSnakeCase.class); - if (event != null) { - receiveSnakeCaseHandler.accept(event); - } + receiveSnakeCaseHandler.accept(receiveSnakeCaseHandlerEvent); } - break; - case "receive2": - if (receive2Handler != null) { - ReceiveEvent2 event = objectMapper.treeToValue(node, ReceiveEvent2.class); - if (event != null) { - receive2Handler.accept(event); - } - } - break; - case "receive3": + return; + } + } + if (node.has("receiveText3")) { + ReceiveEvent3 receive3HandlerEvent = null; + try { + receive3HandlerEvent = objectMapper.treeToValue(node, ReceiveEvent3.class); + } catch (Exception e) { + } + if (receive3HandlerEvent != null) { if (receive3Handler != null) { - ReceiveEvent3 event = objectMapper.treeToValue(node, ReceiveEvent3.class); - if (event != null) { - receive3Handler.accept(event); - } + receive3Handler.accept(receive3HandlerEvent); } - break; - default: - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException("Unknown WebSocket message type: '" + type - + "'. Update your SDK version to support new message types.")); - } - break; + return; + } + } + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); } } catch (Exception e) { if (onErrorHandler != null) { diff --git a/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtimenoauth/websocket/RealtimeNoAuthWebSocketClient.java b/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtimenoauth/websocket/RealtimeNoAuthWebSocketClient.java index 11f77c500b59..9400fc4846a7 100644 --- a/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtimenoauth/websocket/RealtimeNoAuthWebSocketClient.java +++ b/seed/java-sdk/websocket-bearer-auth/src/main/java/com/seed/websocketBearerAuth/resources/realtimenoauth/websocket/RealtimeNoAuthWebSocketClient.java @@ -288,26 +288,23 @@ private void handleIncomingMessage(String json) { if (node == null || node.isNull()) { throw new IllegalArgumentException("Received null or invalid JSON message"); } - JsonNode typeNode = node.get("type"); - if (typeNode == null || typeNode.isNull()) { - throw new IllegalArgumentException("Message missing 'type' field"); - } - String type = typeNode.asText(); - switch (type) { - case "receive": + if (node.has("response")) { + NoAuthReceiveEvent receiveHandlerEvent = null; + try { + receiveHandlerEvent = objectMapper.treeToValue(node, NoAuthReceiveEvent.class); + } catch (Exception e) { + } + if (receiveHandlerEvent != null) { if (receiveHandler != null) { - NoAuthReceiveEvent event = objectMapper.treeToValue(node, NoAuthReceiveEvent.class); - if (event != null) { - receiveHandler.accept(event); - } - } - break; - default: - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException("Unknown WebSocket message type: '" + type - + "'. Update your SDK version to support new message types.")); + receiveHandler.accept(receiveHandlerEvent); } - break; + return; + } + } + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); } } catch (Exception e) { if (onErrorHandler != null) { diff --git a/seed/java-sdk/websocket-inferred-auth/src/main/java/com/seed/websocketAuth/resources/realtime/websocket/RealtimeWebSocketClient.java b/seed/java-sdk/websocket-inferred-auth/src/main/java/com/seed/websocketAuth/resources/realtime/websocket/RealtimeWebSocketClient.java index 3359af1cffb3..1204c611edbe 100644 --- a/seed/java-sdk/websocket-inferred-auth/src/main/java/com/seed/websocketAuth/resources/realtime/websocket/RealtimeWebSocketClient.java +++ b/seed/java-sdk/websocket-inferred-auth/src/main/java/com/seed/websocketAuth/resources/realtime/websocket/RealtimeWebSocketClient.java @@ -345,50 +345,62 @@ private void handleIncomingMessage(String json) { if (node == null || node.isNull()) { throw new IllegalArgumentException("Received null or invalid JSON message"); } - JsonNode typeNode = node.get("type"); - if (typeNode == null || typeNode.isNull()) { - throw new IllegalArgumentException("Message missing 'type' field"); + if (node.has("gamma") && node.has("delta") && node.has("epsilon")) { + ReceiveEvent2 receive2HandlerEvent = null; + try { + receive2HandlerEvent = objectMapper.treeToValue(node, ReceiveEvent2.class); + } catch (Exception e) { + } + if (receive2HandlerEvent != null) { + if (receive2Handler != null) { + receive2Handler.accept(receive2HandlerEvent); + } + return; + } } - String type = typeNode.asText(); - switch (type) { - case "receive": + if (node.has("alpha") && node.has("beta")) { + ReceiveEvent receiveHandlerEvent = null; + try { + receiveHandlerEvent = objectMapper.treeToValue(node, ReceiveEvent.class); + } catch (Exception e) { + } + if (receiveHandlerEvent != null) { if (receiveHandler != null) { - ReceiveEvent event = objectMapper.treeToValue(node, ReceiveEvent.class); - if (event != null) { - receiveHandler.accept(event); - } + receiveHandler.accept(receiveHandlerEvent); } - break; - case "receive_snake_case": + return; + } + } + if (node.has("receive_text") && node.has("receive_int")) { + ReceiveSnakeCase receiveSnakeCaseHandlerEvent = null; + try { + receiveSnakeCaseHandlerEvent = objectMapper.treeToValue(node, ReceiveSnakeCase.class); + } catch (Exception e) { + } + if (receiveSnakeCaseHandlerEvent != null) { if (receiveSnakeCaseHandler != null) { - ReceiveSnakeCase event = objectMapper.treeToValue(node, ReceiveSnakeCase.class); - if (event != null) { - receiveSnakeCaseHandler.accept(event); - } + receiveSnakeCaseHandler.accept(receiveSnakeCaseHandlerEvent); } - break; - case "receive2": - if (receive2Handler != null) { - ReceiveEvent2 event = objectMapper.treeToValue(node, ReceiveEvent2.class); - if (event != null) { - receive2Handler.accept(event); - } - } - break; - case "receive3": + return; + } + } + if (node.has("receiveText3")) { + ReceiveEvent3 receive3HandlerEvent = null; + try { + receive3HandlerEvent = objectMapper.treeToValue(node, ReceiveEvent3.class); + } catch (Exception e) { + } + if (receive3HandlerEvent != null) { if (receive3Handler != null) { - ReceiveEvent3 event = objectMapper.treeToValue(node, ReceiveEvent3.class); - if (event != null) { - receive3Handler.accept(event); - } + receive3Handler.accept(receive3HandlerEvent); } - break; - default: - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException("Unknown WebSocket message type: '" + type - + "'. Update your SDK version to support new message types.")); - } - break; + return; + } + } + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); } } catch (Exception e) { if (onErrorHandler != null) { diff --git a/seed/java-sdk/websocket-multi-url/src/main/java/com/seed/websocketMultiUrl/resources/realtime/websocket/RealtimeWebSocketClient.java b/seed/java-sdk/websocket-multi-url/src/main/java/com/seed/websocketMultiUrl/resources/realtime/websocket/RealtimeWebSocketClient.java index 2cc7b1d778cf..d1ecd0fdc870 100644 --- a/seed/java-sdk/websocket-multi-url/src/main/java/com/seed/websocketMultiUrl/resources/realtime/websocket/RealtimeWebSocketClient.java +++ b/seed/java-sdk/websocket-multi-url/src/main/java/com/seed/websocketMultiUrl/resources/realtime/websocket/RealtimeWebSocketClient.java @@ -288,26 +288,23 @@ private void handleIncomingMessage(String json) { if (node == null || node.isNull()) { throw new IllegalArgumentException("Received null or invalid JSON message"); } - JsonNode typeNode = node.get("type"); - if (typeNode == null || typeNode.isNull()) { - throw new IllegalArgumentException("Message missing 'type' field"); - } - String type = typeNode.asText(); - switch (type) { - case "receive": + if (node.has("data") && node.has("timestamp")) { + ReceiveEvent receiveHandlerEvent = null; + try { + receiveHandlerEvent = objectMapper.treeToValue(node, ReceiveEvent.class); + } catch (Exception e) { + } + if (receiveHandlerEvent != null) { if (receiveHandler != null) { - ReceiveEvent event = objectMapper.treeToValue(node, ReceiveEvent.class); - if (event != null) { - receiveHandler.accept(event); - } - } - break; - default: - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException("Unknown WebSocket message type: '" + type - + "'. Update your SDK version to support new message types.")); + receiveHandler.accept(receiveHandlerEvent); } - break; + return; + } + } + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); } } catch (Exception e) { if (onErrorHandler != null) { diff --git a/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/empty/emptyrealtime/websocket/EmptyRealtimeWebSocketClient.java b/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/empty/emptyrealtime/websocket/EmptyRealtimeWebSocketClient.java index 2d6ad2e72051..787e3017cd16 100644 --- a/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/empty/emptyrealtime/websocket/EmptyRealtimeWebSocketClient.java +++ b/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/empty/emptyrealtime/websocket/EmptyRealtimeWebSocketClient.java @@ -246,18 +246,10 @@ private void handleIncomingMessage(String json) { if (node == null || node.isNull()) { throw new IllegalArgumentException("Received null or invalid JSON message"); } - JsonNode typeNode = node.get("type"); - if (typeNode == null || typeNode.isNull()) { - throw new IllegalArgumentException("Message missing 'type' field"); - } - String type = typeNode.asText(); - switch (type) { - default: - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException("Unknown WebSocket message type: '" + type - + "'. Update your SDK version to support new message types.")); - } - break; + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); } } catch (Exception e) { if (onErrorHandler != null) { diff --git a/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/realtime/websocket/RealtimeWebSocketClient.java b/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/realtime/websocket/RealtimeWebSocketClient.java index 9bbae56f19db..acae36f048f7 100644 --- a/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/realtime/websocket/RealtimeWebSocketClient.java +++ b/seed/java-sdk/websocket/src/main/java/com/seed/websocket/resources/realtime/websocket/RealtimeWebSocketClient.java @@ -382,74 +382,101 @@ private void handleIncomingMessage(String json) { if (node == null || node.isNull()) { throw new IllegalArgumentException("Received null or invalid JSON message"); } - JsonNode typeNode = node.get("type"); - if (typeNode == null || typeNode.isNull()) { - throw new IllegalArgumentException("Message missing 'type' field"); + if (node.has("gamma") && node.has("delta") && node.has("epsilon")) { + ReceiveEvent2 receive2HandlerEvent = null; + try { + receive2HandlerEvent = objectMapper.treeToValue(node, ReceiveEvent2.class); + } catch (Exception e) { + } + if (receive2HandlerEvent != null) { + if (receive2Handler != null) { + receive2Handler.accept(receive2HandlerEvent); + } + return; + } } - String type = typeNode.asText(); - switch (type) { - case "receive": + if (node.has("alpha") && node.has("beta")) { + ReceiveEvent receiveHandlerEvent = null; + try { + receiveHandlerEvent = objectMapper.treeToValue(node, ReceiveEvent.class); + } catch (Exception e) { + } + if (receiveHandlerEvent != null) { if (receiveHandler != null) { - ReceiveEvent event = objectMapper.treeToValue(node, ReceiveEvent.class); - if (event != null) { - receiveHandler.accept(event); - } + receiveHandler.accept(receiveHandlerEvent); } - break; - case "receive_snake_case": + return; + } + } + if (node.has("receive_text") && node.has("receive_int")) { + ReceiveSnakeCase receiveSnakeCaseHandlerEvent = null; + try { + receiveSnakeCaseHandlerEvent = objectMapper.treeToValue(node, ReceiveSnakeCase.class); + } catch (Exception e) { + } + if (receiveSnakeCaseHandlerEvent != null) { if (receiveSnakeCaseHandler != null) { - ReceiveSnakeCase event = objectMapper.treeToValue(node, ReceiveSnakeCase.class); - if (event != null) { - receiveSnakeCaseHandler.accept(event); - } + receiveSnakeCaseHandler.accept(receiveSnakeCaseHandlerEvent); } - break; - case "receive2": - if (receive2Handler != null) { - ReceiveEvent2 event = objectMapper.treeToValue(node, ReceiveEvent2.class); - if (event != null) { - receive2Handler.accept(event); - } - } - break; - case "receive3": - if (receive3Handler != null) { - ReceiveEvent3 event = objectMapper.treeToValue(node, ReceiveEvent3.class); - if (event != null) { - receive3Handler.accept(event); - } - } - break; - case "transcript": + return; + } + } + if (node.has("data") && "transcript".equals(node.path("type").asText())) { + TranscriptEvent transcriptHandlerEvent = null; + try { + transcriptHandlerEvent = objectMapper.treeToValue(node, TranscriptEvent.class); + } catch (Exception e) { + } + if (transcriptHandlerEvent != null) { if (transcriptHandler != null) { - TranscriptEvent event = objectMapper.treeToValue(node, TranscriptEvent.class); - if (event != null) { - transcriptHandler.accept(event); - } + transcriptHandler.accept(transcriptHandlerEvent); } - break; - case "flushed": - if (flushedHandler != null) { - FlushedEvent event = objectMapper.treeToValue(node, FlushedEvent.class); - if (event != null) { - flushedHandler.accept(event); - } - } - break; - case "error": + return; + } + } + if (node.has("errorCode") && node.has("errorMessage")) { + ErrorEvent errorHandlerEvent = null; + try { + errorHandlerEvent = objectMapper.treeToValue(node, ErrorEvent.class); + } catch (Exception e) { + } + if (errorHandlerEvent != null) { if (errorHandler != null) { - ErrorEvent event = objectMapper.treeToValue(node, ErrorEvent.class); - if (event != null) { - errorHandler.accept(event); - } + errorHandler.accept(errorHandlerEvent); + } + return; + } + } + if (node.has("receiveText3")) { + ReceiveEvent3 receive3HandlerEvent = null; + try { + receive3HandlerEvent = objectMapper.treeToValue(node, ReceiveEvent3.class); + } catch (Exception e) { + } + if (receive3HandlerEvent != null) { + if (receive3Handler != null) { + receive3Handler.accept(receive3HandlerEvent); } - break; - default: - if (onErrorHandler != null) { - onErrorHandler.accept(new RuntimeException("Unknown WebSocket message type: '" + type - + "'. Update your SDK version to support new message types.")); + return; + } + } + if ("flushed".equals(node.path("type").asText())) { + FlushedEvent flushedHandlerEvent = null; + try { + flushedHandlerEvent = objectMapper.treeToValue(node, FlushedEvent.class); + } catch (Exception e) { + } + if (flushedHandlerEvent != null) { + if (flushedHandler != null) { + flushedHandler.accept(flushedHandlerEvent); } - break; + return; + } + } + if (onErrorHandler != null) { + onErrorHandler.accept(new RuntimeException( + "Unrecognized WebSocket message: " + json.substring(0, Math.min(200, json.length())) + + "... Update your SDK version to support new message types.")); } } catch (Exception e) { if (onErrorHandler != null) { diff --git a/seed/openapi/undiscriminated-unions/openapi.yml b/seed/openapi/undiscriminated-unions/openapi.yml index 1fc07d81d0b4..ed2f58b2395f 100644 --- a/seed/openapi/undiscriminated-unions/openapi.yml +++ b/seed/openapi/undiscriminated-unions/openapi.yml @@ -133,6 +133,44 @@ paths: application/json: schema: $ref: '#/components/schemas/NestedUnionRoot' + /nested-objects: + post: + operationId: union_nestedObjectUnions + tags: + - Union + parameters: [] + responses: + '200': + description: Success + content: + application/json: + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/OuterNestedUnion' + /aliased-object: + post: + operationId: union_aliasedObjectUnion + tags: + - Union + parameters: [] + responses: + '200': + description: Success + content: + application/json: + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AliasedObjectUnion' /with-base-properties: post: operationId: union_getWithBaseProperties @@ -396,4 +434,96 @@ components: public static implicit operator UnionWithTypeAliases(string value) => ... public static implicit operator UnionWithTypeAliases(string value) => ... causing CS0557 compiler error. + LeafTypeA: + title: LeafTypeA + type: object + properties: + alpha: + type: string + beta: + type: integer + required: + - alpha + - beta + LeafTypeB: + title: LeafTypeB + type: object + properties: + gamma: + type: string + required: + - gamma + NestedObjectUnion: + title: NestedObjectUnion + oneOf: + - $ref: '#/components/schemas/LeafTypeA' + - $ref: '#/components/schemas/LeafTypeB' + description: >- + Inner union with two object variants that have disjoint required keys. + + Tests that required-key guards work correctly inside nested union + contexts. + WrapperObject: + title: WrapperObject + type: object + properties: + inner: + $ref: '#/components/schemas/NestedObjectUnion' + label: + type: string + required: + - inner + - label + OuterNestedUnion: + title: OuterNestedUnion + oneOf: + - type: string + - $ref: '#/components/schemas/WrapperObject' + description: >- + Outer union where one variant is an object containing a nested union + field. + + Tests that the deserializer correctly handles transitive union + deserialization. + AliasedLeafA: + title: AliasedLeafA + $ref: '#/components/schemas/LeafObjectA' + description: An alias around LeafObjectA. + AliasedLeafB: + title: AliasedLeafB + $ref: '#/components/schemas/AliasToLeafB' + description: >- + An alias around an alias around LeafObjectB, to exercise the alias-walk + loop. + AliasToLeafB: + title: AliasToLeafB + $ref: '#/components/schemas/LeafObjectB' + LeafObjectA: + title: LeafObjectA + type: object + properties: + onlyInA: + type: string + sharedNumber: + type: integer + required: + - onlyInA + - sharedNumber + LeafObjectB: + title: LeafObjectB + type: object + properties: + onlyInB: + type: string + required: + - onlyInB + AliasedObjectUnion: + title: AliasedObjectUnion + oneOf: + - $ref: '#/components/schemas/AliasedLeafA' + - $ref: '#/components/schemas/AliasedLeafB' + description: |- + Undiscriminated union whose members are named aliases of object types + (including an alias-of-alias). Required keys are disjoint, so a correct + deserializer must emit containsKey() guards for each alias variant. securitySchemes: {} diff --git a/seed/php-sdk/undiscriminated-unions/reference.md b/seed/php-sdk/undiscriminated-unions/reference.md index 97b5dc95e140..6052c3900d07 100644 --- a/seed/php-sdk/undiscriminated-unions/reference.md +++ b/seed/php-sdk/undiscriminated-unions/reference.md @@ -241,6 +241,93 @@ $client->union->nestedUnions( + + + + +
$client->union->nestedObjectUnions($request) -> ?string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```php +$client->union->nestedObjectUnions( + 'string', +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**$request:** `string|WrapperObject` + +
+
+
+
+ + +
+
+
+ +
$client->union->aliasedObjectUnion($request) -> ?string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```php +$client->union->aliasedObjectUnion( + new LeafObjectA([ + 'onlyInA' => 'onlyInA', + 'sharedNumber' => 1, + ]), +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**$request:** `LeafObjectA|LeafObjectB` + +
+
+
+
+ +
diff --git a/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafObjectA.php b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafObjectA.php new file mode 100644 index 000000000000..c4312cd1cb17 --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafObjectA.php @@ -0,0 +1,42 @@ +onlyInA = $values['onlyInA']; + $this->sharedNumber = $values['sharedNumber']; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } +} diff --git a/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafObjectB.php b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafObjectB.php new file mode 100644 index 000000000000..ad27945dd39e --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafObjectB.php @@ -0,0 +1,34 @@ +onlyInB = $values['onlyInB']; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } +} diff --git a/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafTypeA.php b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafTypeA.php new file mode 100644 index 000000000000..bc0b0816e315 --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafTypeA.php @@ -0,0 +1,42 @@ +alpha = $values['alpha']; + $this->beta = $values['beta']; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } +} diff --git a/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafTypeB.php b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafTypeB.php new file mode 100644 index 000000000000..1a6776e61b17 --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/Union/Types/LeafTypeB.php @@ -0,0 +1,34 @@ +gamma = $values['gamma']; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } +} diff --git a/seed/php-sdk/undiscriminated-unions/src/Union/Types/WrapperObject.php b/seed/php-sdk/undiscriminated-unions/src/Union/Types/WrapperObject.php new file mode 100644 index 000000000000..2050802b2828 --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/Union/Types/WrapperObject.php @@ -0,0 +1,49 @@ +inner = $values['inner']; + $this->label = $values['label']; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->toJson(); + } +} diff --git a/seed/php-sdk/undiscriminated-unions/src/Union/UnionClient.php b/seed/php-sdk/undiscriminated-unions/src/Union/UnionClient.php index a16f9d27f8d6..1e6b648fe226 100644 --- a/seed/php-sdk/undiscriminated-unions/src/Union/UnionClient.php +++ b/seed/php-sdk/undiscriminated-unions/src/Union/UnionClient.php @@ -16,6 +16,9 @@ use Seed\Union\Types\KeyType; use Seed\Union\Types\NamedMetadata; use Seed\Union\Types\Request; +use Seed\Union\Types\WrapperObject; +use Seed\Union\Types\LeafObjectA; +use Seed\Union\Types\LeafObjectB; use Seed\Union\Requests\PaymentRequest; class UnionClient @@ -366,6 +369,106 @@ public function nestedUnions(string|array|int|bool $request, ?array $options = n ); } + /** + * @param ( + * string + * |WrapperObject + * ) $request + * @param ?array{ + * baseUrl?: string, + * maxRetries?: int, + * timeout?: float, + * headers?: array, + * queryParameters?: array, + * bodyProperties?: array, + * } $options + * @return ?string + * @throws SeedException + * @throws SeedApiException + */ + public function nestedObjectUnions(string|WrapperObject $request, ?array $options = null): ?string + { + $options = array_merge($this->options, $options ?? []); + try { + $response = $this->client->sendRequest( + new JsonApiRequest( + baseUrl: $options['baseUrl'] ?? $this->client->options['baseUrl'] ?? '', + path: "/nested-objects", + method: HttpMethod::POST, + body: JsonSerializer::serializeUnion($request, new Union('string', WrapperObject::class)), + ), + $options, + ); + $statusCode = $response->getStatusCode(); + if ($statusCode >= 200 && $statusCode < 400) { + $json = $response->getBody()->getContents(); + if (empty($json)) { + return null; + } + return JsonDecoder::decodeString($json); + } + } catch (JsonException $e) { + throw new SeedException(message: "Failed to deserialize response: {$e->getMessage()}", previous: $e); + } catch (ClientExceptionInterface $e) { + throw new SeedException(message: $e->getMessage(), previous: $e); + } + throw new SeedApiException( + message: 'API request failed', + statusCode: $statusCode, + body: $response->getBody()->getContents(), + ); + } + + /** + * @param ( + * LeafObjectA + * |LeafObjectB + * ) $request + * @param ?array{ + * baseUrl?: string, + * maxRetries?: int, + * timeout?: float, + * headers?: array, + * queryParameters?: array, + * bodyProperties?: array, + * } $options + * @return ?string + * @throws SeedException + * @throws SeedApiException + */ + public function aliasedObjectUnion(LeafObjectA|LeafObjectB $request, ?array $options = null): ?string + { + $options = array_merge($this->options, $options ?? []); + try { + $response = $this->client->sendRequest( + new JsonApiRequest( + baseUrl: $options['baseUrl'] ?? $this->client->options['baseUrl'] ?? '', + path: "/aliased-object", + method: HttpMethod::POST, + body: JsonSerializer::serializeUnion($request, new Union(LeafObjectA::class, LeafObjectB::class)), + ), + $options, + ); + $statusCode = $response->getStatusCode(); + if ($statusCode >= 200 && $statusCode < 400) { + $json = $response->getBody()->getContents(); + if (empty($json)) { + return null; + } + return JsonDecoder::decodeString($json); + } + } catch (JsonException $e) { + throw new SeedException(message: "Failed to deserialize response: {$e->getMessage()}", previous: $e); + } catch (ClientExceptionInterface $e) { + throw new SeedException(message: $e->getMessage(), previous: $e); + } + throw new SeedApiException( + message: 'API request failed', + statusCode: $statusCode, + body: $response->getBody()->getContents(), + ); + } + /** * @param ( * NamedMetadata diff --git a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example10/snippet.php b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example10/snippet.php index b87643175fb0..ea81dcc348e6 100644 --- a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example10/snippet.php +++ b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example10/snippet.php @@ -3,19 +3,16 @@ namespace Example; use Seed\SeedClient; -use Seed\Union\Requests\PaymentRequest; -use Seed\Union\Types\TokenizeCard; +use Seed\Union\Types\LeafObjectA; $client = new SeedClient( options: [ 'baseUrl' => 'https://api.fern.com', ], ); -$client->union->testCamelCaseProperties( - new PaymentRequest([ - 'paymentMethod' => new TokenizeCard([ - 'method' => 'card', - 'cardNumber' => '1234567890123456', - ]), +$client->union->aliasedObjectUnion( + new LeafObjectA([ + 'onlyInA' => 'onlyInA', + 'sharedNumber' => 1, ]), ); diff --git a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example11/snippet.php b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example11/snippet.php index d387a2d5ac0e..723e8e897e30 100644 --- a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example11/snippet.php +++ b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example11/snippet.php @@ -3,19 +3,20 @@ namespace Example; use Seed\SeedClient; -use Seed\Union\Requests\PaymentRequest; -use Seed\Union\Types\TokenizeCard; +use Seed\Union\Types\NamedMetadata; $client = new SeedClient( options: [ 'baseUrl' => 'https://api.fern.com', ], ); -$client->union->testCamelCaseProperties( - new PaymentRequest([ - 'paymentMethod' => new TokenizeCard([ - 'method' => 'method', - 'cardNumber' => 'cardNumber', - ]), +$client->union->getWithBaseProperties( + new NamedMetadata([ + 'name' => 'name', + 'value' => [ + 'value' => [ + 'key' => "value", + ], + ], ]), ); diff --git a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example12/snippet.php b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example12/snippet.php new file mode 100644 index 000000000000..b87643175fb0 --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example12/snippet.php @@ -0,0 +1,21 @@ + 'https://api.fern.com', + ], +); +$client->union->testCamelCaseProperties( + new PaymentRequest([ + 'paymentMethod' => new TokenizeCard([ + 'method' => 'card', + 'cardNumber' => '1234567890123456', + ]), + ]), +); diff --git a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example13/snippet.php b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example13/snippet.php new file mode 100644 index 000000000000..d387a2d5ac0e --- /dev/null +++ b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example13/snippet.php @@ -0,0 +1,21 @@ + 'https://api.fern.com', + ], +); +$client->union->testCamelCaseProperties( + new PaymentRequest([ + 'paymentMethod' => new TokenizeCard([ + 'method' => 'method', + 'cardNumber' => 'cardNumber', + ]), + ]), +); diff --git a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example9/snippet.php b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example9/snippet.php index 723e8e897e30..269c69c529e6 100644 --- a/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example9/snippet.php +++ b/seed/php-sdk/undiscriminated-unions/src/dynamic-snippets/example9/snippet.php @@ -3,20 +3,12 @@ namespace Example; use Seed\SeedClient; -use Seed\Union\Types\NamedMetadata; $client = new SeedClient( options: [ 'baseUrl' => 'https://api.fern.com', ], ); -$client->union->getWithBaseProperties( - new NamedMetadata([ - 'name' => 'name', - 'value' => [ - 'value' => [ - 'key' => "value", - ], - ], - ]), +$client->union->nestedObjectUnions( + 'string', ); diff --git a/seed/python-sdk/basic-auth-pw-omitted/README.md b/seed/python-sdk/basic-auth-pw-omitted/README.md index 161f5d1a88f4..33476dbac63f 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/README.md +++ b/seed/python-sdk/basic-auth-pw-omitted/README.md @@ -38,7 +38,6 @@ from seed import SeedBasicAuthPwOmitted client = SeedBasicAuthPwOmitted( username="", - password="", base_url="https://yourhost.com/path/to/api", ) @@ -58,7 +57,6 @@ from seed import AsyncSeedBasicAuthPwOmitted client = AsyncSeedBasicAuthPwOmitted( username="", - password="", base_url="https://yourhost.com/path/to/api", ) diff --git a/seed/python-sdk/basic-auth-pw-omitted/reference.md b/seed/python-sdk/basic-auth-pw-omitted/reference.md index 29a37f6bea43..f63dc17b0378 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/reference.md +++ b/seed/python-sdk/basic-auth-pw-omitted/reference.md @@ -31,7 +31,6 @@ from seed import SeedBasicAuthPwOmitted client = SeedBasicAuthPwOmitted( username="", - password="", base_url="https://yourhost.com/path/to/api", ) @@ -94,7 +93,6 @@ from seed import SeedBasicAuthPwOmitted client = SeedBasicAuthPwOmitted( username="", - password="", base_url="https://yourhost.com/path/to/api", ) diff --git a/seed/python-sdk/basic-auth-pw-omitted/snippet.json b/seed/python-sdk/basic-auth-pw-omitted/snippet.json index 4287155ce181..0d3ccd66b2e0 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/snippet.json +++ b/seed/python-sdk/basic-auth-pw-omitted/snippet.json @@ -9,8 +9,8 @@ "identifier_override": "endpoint_basic-auth.getWithBasicAuth" }, "snippet": { - "sync_client": "from seed import SeedBasicAuthPwOmitted\n\nclient = SeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n password=\"YOUR_PASSWORD\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.basic_auth.get_with_basic_auth()\n", - "async_client": "import asyncio\n\nfrom seed import AsyncSeedBasicAuthPwOmitted\n\nclient = AsyncSeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n password=\"YOUR_PASSWORD\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.basic_auth.get_with_basic_auth()\n\n\nasyncio.run(main())\n", + "sync_client": "from seed import SeedBasicAuthPwOmitted\n\nclient = SeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.basic_auth.get_with_basic_auth()\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedBasicAuthPwOmitted\n\nclient = AsyncSeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.basic_auth.get_with_basic_auth()\n\n\nasyncio.run(main())\n", "type": "python" } }, @@ -22,10 +22,10 @@ "identifier_override": "endpoint_basic-auth.postWithBasicAuth" }, "snippet": { - "sync_client": "from seed import SeedBasicAuthPwOmitted\n\nclient = SeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n password=\"YOUR_PASSWORD\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.basic_auth.post_with_basic_auth(\n request={\"key\": \"value\"},\n)\n", - "async_client": "import asyncio\n\nfrom seed import AsyncSeedBasicAuthPwOmitted\n\nclient = AsyncSeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n password=\"YOUR_PASSWORD\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.basic_auth.post_with_basic_auth(\n request={\"key\": \"value\"},\n )\n\n\nasyncio.run(main())\n", + "sync_client": "from seed import SeedBasicAuthPwOmitted\n\nclient = SeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.basic_auth.post_with_basic_auth(\n request={\"key\": \"value\"},\n)\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedBasicAuthPwOmitted\n\nclient = AsyncSeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.basic_auth.post_with_basic_auth(\n request={\"key\": \"value\"},\n )\n\n\nasyncio.run(main())\n", "type": "python" } } ] -} \ No newline at end of file +} diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/conftest.py b/seed/python-sdk/basic-auth-pw-omitted/tests/conftest.py deleted file mode 100644 index 25710dbe6278..000000000000 --- a/seed/python-sdk/basic-auth-pw-omitted/tests/conftest.py +++ /dev/null @@ -1,21 +0,0 @@ -import pytest - - -def _has_httpx_aiohttp() -> bool: - """Check if httpx_aiohttp is importable.""" - try: - import httpx_aiohttp # type: ignore[import-not-found] # noqa: F401 - - return True - except ImportError: - return False - - -def pytest_collection_modifyitems(config: pytest.Config, items: list) -> None: - """Auto-skip @pytest.mark.aiohttp tests when httpx_aiohttp is not installed.""" - if _has_httpx_aiohttp(): - return - skip_aiohttp = pytest.mark.skip(reason="httpx_aiohttp not installed") - for item in items: - if "aiohttp" in item.keywords: - item.add_marker(skip_aiohttp) diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.fern/metadata.json b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.fern/metadata.json new file mode 100644 index 000000000000..2a49c5f592ee --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.fern/metadata.json @@ -0,0 +1,13 @@ +{ + "cliVersion": "DUMMY", + "generatorName": "fernapi/fern-python-sdk", + "generatorVersion": "local", + "generatorConfig": { + "enable_wire_tests": true + }, + "originGitCommit": "DUMMY", + "invokedBy": "ci", + "requestedVersion": "0.0.1", + "ciProvider": "github", + "sdkVersion": "0.0.1" +} \ No newline at end of file diff --git a/seed/python-sdk/basic-auth-pw-omitted/.github/workflows/ci.yml b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.github/workflows/ci.yml similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/.github/workflows/ci.yml rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.github/workflows/ci.yml diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.gitignore b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.gitignore new file mode 100644 index 000000000000..d2e4ca808d21 --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/.gitignore @@ -0,0 +1,5 @@ +.mypy_cache/ +.ruff_cache/ +__pycache__/ +dist/ +poetry.toml diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/README.md b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/README.md new file mode 100644 index 000000000000..33476dbac63f --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/README.md @@ -0,0 +1,166 @@ +# Seed Python Library + +[![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=Seed%2FPython) +[![pypi](https://img.shields.io/pypi/v/fern_basic-auth-pw-omitted)](https://pypi.python.org/pypi/fern_basic-auth-pw-omitted) + +The Seed Python library provides convenient access to the Seed APIs from Python. + +## Table of Contents + +- [Installation](#installation) +- [Reference](#reference) +- [Usage](#usage) +- [Async Client](#async-client) +- [Exception Handling](#exception-handling) +- [Advanced](#advanced) + - [Access Raw Response Data](#access-raw-response-data) + - [Retries](#retries) + - [Timeouts](#timeouts) + - [Custom Client](#custom-client) +- [Contributing](#contributing) + +## Installation + +```sh +pip install fern_basic-auth-pw-omitted +``` + +## Reference + +A full reference for this library is available [here](./reference.md). + +## Usage + +Instantiate and use the client with the following: + +```python +from seed import SeedBasicAuthPwOmitted + +client = SeedBasicAuthPwOmitted( + username="", + base_url="https://yourhost.com/path/to/api", +) + +client.basic_auth.post_with_basic_auth( + request={"key": "value"}, +) +``` + +## Async Client + +The SDK also exports an `async` client so that you can make non-blocking calls to our API. Note that if you are constructing an Async httpx client class to pass into this client, use `httpx.AsyncClient()` instead of `httpx.Client()` (e.g. for the `httpx_client` parameter of this client). + +```python +import asyncio + +from seed import AsyncSeedBasicAuthPwOmitted + +client = AsyncSeedBasicAuthPwOmitted( + username="", + base_url="https://yourhost.com/path/to/api", +) + + +async def main() -> None: + await client.basic_auth.post_with_basic_auth( + request={"key": "value"}, + ) + + +asyncio.run(main()) +``` + +## Exception Handling + +When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error +will be thrown. + +```python +from seed.core.api_error import ApiError + +try: + client.basic_auth.post_with_basic_auth(...) +except ApiError as e: + print(e.status_code) + print(e.body) +``` + +## Advanced + +### Access Raw Response Data + +The SDK provides access to raw response data, including headers, through the `.with_raw_response` property. +The `.with_raw_response` property returns a "raw" client that can be used to access the `.headers` and `.data` attributes. + +```python +from seed import SeedBasicAuthPwOmitted + +client = SeedBasicAuthPwOmitted(...) +response = client.basic_auth.with_raw_response.post_with_basic_auth(...) +print(response.headers) # access the response headers +print(response.status_code) # access the response status code +print(response.data) # access the underlying object +``` + +### Retries + +The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long +as the request is deemed retryable and the number of retry attempts has not grown larger than the configured +retry limit (default: 2). + +A request is deemed retryable when any of the following HTTP status codes is returned: + +- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) +- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) +- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) (Internal Server Errors) + +Use the `max_retries` request option to configure this behavior. + +```python +client.basic_auth.post_with_basic_auth(..., request_options={ + "max_retries": 1 +}) +``` + +### Timeouts + +The SDK defaults to a 60 second timeout. You can configure this with a timeout option at the client or request level. + +```python +from seed import SeedBasicAuthPwOmitted + +client = SeedBasicAuthPwOmitted(..., timeout=20.0) + +# Override timeout for a specific method +client.basic_auth.post_with_basic_auth(..., request_options={ + "timeout_in_seconds": 1 +}) +``` + +### Custom Client + +You can override the `httpx` client to customize it for your use-case. Some common use-cases include support for proxies +and transports. + +```python +import httpx +from seed import SeedBasicAuthPwOmitted + +client = SeedBasicAuthPwOmitted( + ..., + httpx_client=httpx.Client( + proxy="http://my.test.proxy.example.com", + transport=httpx.HTTPTransport(local_address="0.0.0.0"), + ), +) +``` + +## Contributing + +While we value open-source contributions to this SDK, this library is generated programmatically. +Additions made directly to this library would have to be moved over to our generation code, +otherwise they would be overwritten upon the next generated release. Feel free to open a PR as +a proof of concept, but know that we will not be able to merge it as-is. We suggest opening +an issue first to discuss with us! + +On the other hand, contributions to the README are always very welcome! diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/poetry.lock b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/poetry.lock new file mode 100644 index 000000000000..5f03244c4d84 --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/poetry.lock @@ -0,0 +1,1614 @@ +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +description = "Happy Eyeballs for asyncio" +optional = true +python-versions = ">=3.9" +files = [ + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, +] + +[[package]] +name = "aiohttp" +version = "3.13.5" +description = "Async http client/server framework (asyncio)" +optional = true +python-versions = ">=3.9" +files = [ + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:02222e7e233295f40e011c1b00e3b0bd451f22cf853a0304c3595633ee47da4b"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bace460460ed20614fa6bc8cb09966c0b8517b8c58ad8046828c6078d25333b5"}, + {file = "aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f546a4dc1e6a5edbb9fd1fd6ad18134550e096a5a43f4ad74acfbd834fc6670"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c86969d012e51b8e415a8c6ce96f7857d6a87d6207303ab02d5d11ef0cad2274"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b6f6cd1560c5fa427e3b6074bb24d2c64e225afbb7165008903bd42e4e33e28a"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:636bc362f0c5bbc7372bc3ae49737f9e3030dbce469f0f422c8f38079780363d"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6a7cbeb06d1070f1d14895eeeed4dac5913b22d7b456f2eb969f11f4b3993796"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca9ef7517fd7874a1a08970ae88f497bf5c984610caa0bf40bd7e8450852b95"}, + {file = "aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:019a67772e034a0e6b9b17c13d0a8fe56ad9fb150fc724b7f3ffd3724288d9e5"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f34ecee82858e41dd217734f0c41a532bd066bcaab636ad830f03a30b2a96f2a"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4eac02d9af4813ee289cd63a361576da36dba57f5a1ab36377bc2600db0cbb73"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4beac52e9fe46d6abf98b0176a88154b742e878fdf209d2248e99fcdf73cd297"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c180f480207a9b2475f2b8d8bd7204e47aec952d084b2a2be58a782ffcf96074"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2837fb92951564d6339cedae4a7231692aa9f73cbc4fb2e04263b96844e03b4e"}, + {file = "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d9010032a0b9710f58012a1e9c222528763d860ba2ee1422c03473eab47703e7"}, + {file = "aiohttp-3.13.5-cp310-cp310-win32.whl", hash = "sha256:7c4b6668b2b2b9027f209ddf647f2a4407784b5d88b8be4efcc72036f365baf9"}, + {file = "aiohttp-3.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:cd3db5927bf9167d5a6157ddb2f036f6b6b0ad001ac82355d43e97a4bde76d76"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ab7229b6f9b5c1ba4910d6c41a9eb11f543eadb3f384df1b4c293f4e73d44d6"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8f14c50708bb156b3a3ca7230b3d820199d56a48e3af76fa21c2d6087190fe3d"}, + {file = "aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7d2f8616f0ff60bd332022279011776c3ac0faa0f1b463f7bb12326fbc97a1c"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc"}, + {file = "aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac"}, + {file = "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3"}, + {file = "aiohttp-3.13.5-cp311-cp311-win32.whl", hash = "sha256:77dfa48c9f8013271011e51c00f8ada19851f013cde2c48fca1ba5e0caf5bb06"}, + {file = "aiohttp-3.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:d3a4834f221061624b8887090637db9ad4f61752001eae37d56c52fddade2dc8"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:023ecba036ddd840b0b19bf195bfae970083fd7024ce1ac22e9bba90464620e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15c933ad7920b7d9a20de151efcd05a6e38302cbf0e10c9b2acb9a42210a2416"}, + {file = "aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab2899f9fa2f9f741896ebb6fa07c4c883bfa5c7f2ddd8cf2aafa86fa981b2d2"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a60eaa2d440cd4707696b52e40ed3e2b0f73f65be07fd0ef23b6b539c9c0b0b4"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:55b3bdd3292283295774ab585160c4004f4f2f203946997f49aac032c84649e9"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2b2355dc094e5f7d45a7bb262fe7207aa0460b37a0d87027dcf21b5d890e7d5"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b38765950832f7d728297689ad78f5f2cf79ff82487131c4d26fe6ceecdc5f8e"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b18f31b80d5a33661e08c89e202edabf1986e9b49c42b4504371daeaa11b47c1"}, + {file = "aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:33add2463dde55c4f2d9635c6ab33ce154e5ecf322bd26d09af95c5f81cfa286"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:327cc432fdf1356fb4fbc6fe833ad4e9f6aacb71a8acaa5f1855e4b25910e4a9"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7c35b0bf0b48a70b4cb4fc5d7bed9b932532728e124874355de1a0af8ec4bc88"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:df23d57718f24badef8656c49743e11a89fd6f5358fa8a7b96e728fda2abf7d3"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:02e048037a6501a5ec1f6fc9736135aec6eb8a004ce48838cb951c515f32c80b"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31cebae8b26f8a615d2b546fee45d5ffb76852ae6450e2a03f42c9102260d6fe"}, + {file = "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:888e78eb5ca55a615d285c3c09a7a91b42e9dd6fc699b166ebd5dee87c9ccf14"}, + {file = "aiohttp-3.13.5-cp312-cp312-win32.whl", hash = "sha256:8bd3ec6376e68a41f9f95f5ed170e2fcf22d4eb27a1f8cb361d0508f6e0557f3"}, + {file = "aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5029cc80718bbd545123cd8fe5d15025eccaaaace5d0eeec6bd556ad6163d61"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4bb6bf5811620003614076bdc807ef3b5e38244f9d25ca5fe888eaccea2a9832"}, + {file = "aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a84792f8631bf5a94e52d9cc881c0b824ab42717165a5579c760b830d9392ac9"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57653eac22c6a4c13eb22ecf4d673d64a12f266e72785ab1c8b8e5940d0e8090"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5e5f7debc7a57af53fdf5c5009f9391d9f4c12867049d509bf7bb164a6e295b"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c719f65bebcdf6716f10e9eff80d27567f7892d8988c06de12bbbd39307c6e3a"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d97f93fdae594d886c5a866636397e2bcab146fd7a132fd6bb9ce182224452f8"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df334e39d4c2f899a914f1dba283c1aadc311790733f705182998c6f7cae665"}, + {file = "aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe6970addfea9e5e081401bcbadf865d2b6da045472f58af08427e108d618540"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7becdf835feff2f4f335d7477f121af787e3504b48b449ff737afb35869ba7bb"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:676e5651705ad5d8a70aeb8eb6936c436d8ebbd56e63436cb7dd9bb36d2a9a46"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9b16c653d38eb1a611cc898c41e76859ca27f119d25b53c12875fd0474ae31a8"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:999802d5fa0389f58decd24b537c54aa63c01c3219ce17d1214cbda3c2b22d2d"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec707059ee75732b1ba130ed5f9580fe10ff75180c812bc267ded039db5128c6"}, + {file = "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d6d44a5b48132053c2f6cd5c8cb14bc67e99a63594e336b0f2af81e94d5530c"}, + {file = "aiohttp-3.13.5-cp313-cp313-win32.whl", hash = "sha256:329f292ed14d38a6c4c435e465f48bebb47479fd676a0411936cc371643225cc"}, + {file = "aiohttp-3.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:69f571de7500e0557801c0b51f4780482c0ec5fe2ac851af5a92cfce1af1cb83"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be"}, + {file = "aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b"}, + {file = "aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1"}, + {file = "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b"}, + {file = "aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3"}, + {file = "aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254"}, + {file = "aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a"}, + {file = "aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500"}, + {file = "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8"}, + {file = "aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:347542f0ea3f95b2a955ee6656461fa1c776e401ac50ebce055a6c38454a0adf"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:178c7b5e62b454c2bc790786e6058c3cc968613b4419251b478c153a4aec32b1"}, + {file = "aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af545c2cffdb0967a96b6249e6f5f7b0d92cdfd267f9d5238d5b9ca63e8edb10"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:206b7b3ef96e4ce211754f0cd003feb28b7d81f0ad26b8d077a5d5161436067f"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ee5e86776273de1795947d17bddd6bb19e0365fd2af4289c0d2c5454b6b1d36b"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95d14ca7abefde230f7639ec136ade282655431fd5db03c343b19dda72dd1643"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:912d4b6af530ddb1338a66229dac3a25ff11d4448be3ec3d6340583995f56031"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e999f0c88a458c836d5fb521814e92ed2172c649200336a6df514987c1488258"}, + {file = "aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39380e12bd1f2fdab4285b6e055ad48efbaed5c836433b142ed4f5b9be71036a"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9efcc0f11d850cefcafdd9275b9576ad3bfb539bed96807663b32ad99c4d4b88"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:147b4f501d0292077f29d5268c16bb7c864a1f054d7001c4c1812c0421ea1ed0"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d147004fede1b12f6013a6dbb2a26a986a671a03c6ea740ddc76500e5f1c399f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9277145d36a01653863899c665243871434694bcc3431922c3b35c978061bdb8"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4e704c52438f66fdd89588346183d898bb42167cf88f8b7ff1c0f9fc957c348f"}, + {file = "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8a4d3427e8de1312ddf309cc482186466c79895b3a139fed3259fc01dfa9a5b"}, + {file = "aiohttp-3.13.5-cp39-cp39-win32.whl", hash = "sha256:6f497a6876aa4b1a102b04996ce4c1170c7040d83faa9387dd921c16e30d5c83"}, + {file = "aiohttp-3.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:cb979826071c0986a5f08333a36104153478ce6018c58cba7f9caddaf63d5d67"}, + {file = "aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.5.0" +aiosignal = ">=1.4.0" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli (>=1.2)", "aiodns (>=3.3.0)", "backports.zstd", "brotlicffi (>=1.2)"] + +[[package]] +name = "aiosignal" +version = "1.4.0" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = true +python-versions = ">=3.9" +files = [ + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" +typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.13.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.10" +files = [ + {file = "anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708"}, + {file = "anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.32.0)"] + +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = true +python-versions = ">=3.8" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[[package]] +name = "attrs" +version = "26.1.0" +description = "Classes Without Boilerplate" +optional = true +python-versions = ">=3.9" +files = [ + {file = "attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, + {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, +] + +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +description = "Backport of asyncio.Runner, a context manager that controls event loop life cycle." +optional = false +python-versions = "<3.11,>=3.8" +files = [ + {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, + {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, +] + +[[package]] +name = "certifi" +version = "2026.4.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +files = [ + {file = "certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a"}, + {file = "certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"}, + {file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"}, + {file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"}, + {file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"}, + {file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"}, + {file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"}, + {file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"}, + {file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"}, + {file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"}, + {file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"}, + {file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "execnet" +version = "2.1.2" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +files = [ + {file = "execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec"}, + {file = "execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + +[[package]] +name = "frozenlist" +version = "1.8.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = true +python-versions = ">=3.9" +files = [ + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, + {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, + {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, + {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, + {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, + {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, + {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, + {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, + {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, +] + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "httpx-aiohttp" +version = "0.1.8" +description = "Aiohttp transport for HTTPX" +optional = true +python-versions = ">=3.8" +files = [ + {file = "httpx_aiohttp-0.1.8-py3-none-any.whl", hash = "sha256:b7bd958d1331f3759a38a0ba22ad29832cb63ca69498c17735228055bf78fa7e"}, + {file = "httpx_aiohttp-0.1.8.tar.gz", hash = "sha256:756c5e74cdb568c3248ba63fe82bfe8bbe64b928728720f7eaac64b3cf46f308"}, +] + +[package.dependencies] +aiohttp = ">=3.10.0,<4" +httpx = ">=0.27.0" + +[[package]] +name = "idna" +version = "3.13" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3"}, + {file = "idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242"}, +] + +[package.extras] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.3.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.10" +files = [ + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, +] + +[[package]] +name = "multidict" +version = "6.7.1" +description = "multidict implementation" +optional = true +python-versions = ">=3.9" +files = [ + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"}, + {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"}, + {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"}, + {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"}, + {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"}, + {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"}, + {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, + {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, + {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, + {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, + {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, + {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, + {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, + {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, + {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, + {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, + {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, + {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, + {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, + {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, + {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, + {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"}, + {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"}, + {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"}, + {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"}, + {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, + {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "mypy" +version = "1.13.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "packaging" +version = "26.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "propcache" +version = "0.4.1" +description = "Accelerated property cache" +optional = true +python-versions = ">=3.9" +files = [ + {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c"}, + {file = "propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb"}, + {file = "propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37"}, + {file = "propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f"}, + {file = "propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1"}, + {file = "propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6"}, + {file = "propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75"}, + {file = "propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8"}, + {file = "propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db"}, + {file = "propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66"}, + {file = "propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81"}, + {file = "propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e"}, + {file = "propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1"}, + {file = "propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717"}, + {file = "propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37"}, + {file = "propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144"}, + {file = "propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f"}, + {file = "propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153"}, + {file = "propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455"}, + {file = "propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85"}, + {file = "propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1"}, + {file = "propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183"}, + {file = "propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19"}, + {file = "propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f"}, + {file = "propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938"}, + {file = "propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237"}, + {file = "propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d"}, +] + +[[package]] +name = "pydantic" +version = "2.12.5" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, + {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.41.5" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"}, + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"}, + {file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" + +[[package]] +name = "pygments" +version = "2.20.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pytest" +version = "9.0.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "1.3.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5"}, + {file = "pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5"}, +] + +[package.dependencies] +backports-asyncio-runner = {version = ">=1.1,<2", markers = "python_version < \"3.11\""} +pytest = ">=8.2,<10" +typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""} + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, + {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "requests" +version = "2.33.1" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.10" +files = [ + {file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"}, + {file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"}, +] + +[package.dependencies] +certifi = ">=2023.5.7" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.26,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] + +[[package]] +name = "ruff" +version = "0.11.5" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.11.5-py3-none-linux_armv6l.whl", hash = "sha256:2561294e108eb648e50f210671cc56aee590fb6167b594144401532138c66c7b"}, + {file = "ruff-0.11.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac12884b9e005c12d0bd121f56ccf8033e1614f736f766c118ad60780882a077"}, + {file = "ruff-0.11.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4bfd80a6ec559a5eeb96c33f832418bf0fb96752de0539905cf7b0cc1d31d779"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0947c0a1afa75dcb5db4b34b070ec2bccee869d40e6cc8ab25aca11a7d527794"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad871ff74b5ec9caa66cb725b85d4ef89b53f8170f47c3406e32ef040400b038"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6cf918390cfe46d240732d4d72fa6e18e528ca1f60e318a10835cf2fa3dc19f"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:56145ee1478582f61c08f21076dc59153310d606ad663acc00ea3ab5b2125f82"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5f66f8f1e8c9fc594cbd66fbc5f246a8d91f916cb9667e80208663ec3728304"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80b4df4d335a80315ab9afc81ed1cff62be112bd165e162b5eed8ac55bfc8470"}, + {file = "ruff-0.11.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3068befab73620b8a0cc2431bd46b3cd619bc17d6f7695a3e1bb166b652c382a"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5da2e710a9641828e09aa98b92c9ebbc60518fdf3921241326ca3e8f8e55b8b"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ef39f19cb8ec98cbc762344921e216f3857a06c47412030374fffd413fb8fd3a"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b2a7cedf47244f431fd11aa5a7e2806dda2e0c365873bda7834e8f7d785ae159"}, + {file = "ruff-0.11.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:81be52e7519f3d1a0beadcf8e974715b2dfc808ae8ec729ecfc79bddf8dbb783"}, + {file = "ruff-0.11.5-py3-none-win32.whl", hash = "sha256:e268da7b40f56e3eca571508a7e567e794f9bfcc0f412c4b607931d3af9c4afe"}, + {file = "ruff-0.11.5-py3-none-win_amd64.whl", hash = "sha256:6c6dc38af3cfe2863213ea25b6dc616d679205732dc0fb673356c2d69608f800"}, + {file = "ruff-0.11.5-py3-none-win_arm64.whl", hash = "sha256:67e241b4314f4eacf14a601d586026a962f4002a475aa702c69980a38087aa4e"}, + {file = "ruff-0.11.5.tar.gz", hash = "sha256:cae2e2439cb88853e421901ec040a758960b576126dab520fa08e9de431d1bef"}, +] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "tomli" +version = "2.4.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, +] + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20260408" +description = "Typing stubs for python-dateutil" +optional = false +python-versions = ">=3.10" +files = [ + {file = "types_python_dateutil-2.9.0.20260408-py3-none-any.whl", hash = "sha256:473139d514a71c9d1fbd8bb328974bedcb1cc3dba57aad04ffa4157f483c216f"}, + {file = "types_python_dateutil-2.9.0.20260408.tar.gz", hash = "sha256:8b056ec01568674235f64ecbcef928972a5fac412f5aab09c516dfa2acfbb582"}, +] + +[[package]] +name = "types-requests" +version = "2.33.0.20260408" +description = "Typing stubs for requests" +optional = false +python-versions = ">=3.10" +files = [ + {file = "types_requests-2.33.0.20260408-py3-none-any.whl", hash = "sha256:81f31d5ea4acb39f03be7bc8bed569ba6d5a9c5d97e89f45ac43d819b68ca50f"}, + {file = "types_requests-2.33.0.20260408.tar.gz", hash = "sha256:95b9a86376807a216b2fb412b47617b202091c3ea7c078f47cc358d5528ccb7b"}, +] + +[package.dependencies] +urllib3 = ">=2" + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "urllib3" +version = "2.6.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +files = [ + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, +] + +[package.extras] +brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["backports-zstd (>=1.0.0)"] + +[[package]] +name = "yarl" +version = "1.23.0" +description = "Yet another URL library" +optional = true +python-versions = ">=3.10" +files = [ + {file = "yarl-1.23.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107"}, + {file = "yarl-1.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d"}, + {file = "yarl-1.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6"}, + {file = "yarl-1.23.0-cp310-cp310-win32.whl", hash = "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d"}, + {file = "yarl-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb"}, + {file = "yarl-1.23.0-cp310-cp310-win_arm64.whl", hash = "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220"}, + {file = "yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99"}, + {file = "yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c"}, + {file = "yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2"}, + {file = "yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5"}, + {file = "yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46"}, + {file = "yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928"}, + {file = "yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860"}, + {file = "yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069"}, + {file = "yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34"}, + {file = "yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d"}, + {file = "yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e"}, + {file = "yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9"}, + {file = "yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e"}, + {file = "yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5"}, + {file = "yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543"}, + {file = "yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957"}, + {file = "yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3"}, + {file = "yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3"}, + {file = "yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa"}, + {file = "yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120"}, + {file = "yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5"}, + {file = "yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595"}, + {file = "yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090"}, + {file = "yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144"}, + {file = "yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912"}, + {file = "yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474"}, + {file = "yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe"}, + {file = "yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169"}, + {file = "yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70"}, + {file = "yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e"}, + {file = "yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679"}, + {file = "yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412"}, + {file = "yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4"}, + {file = "yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4"}, + {file = "yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2"}, + {file = "yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25"}, + {file = "yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f"}, + {file = "yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.1" + +[extras] +aiohttp = ["aiohttp", "httpx-aiohttp"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "e2541afd91bc09d4197eeb20ce689552c2fba7835992ac58b76873446bec8411" diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/pyproject.toml b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/pyproject.toml new file mode 100644 index 000000000000..fb36c920eeb4 --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/pyproject.toml @@ -0,0 +1,103 @@ +[project] +name = "fern_basic-auth-pw-omitted" +dynamic = ["version"] + +[tool.poetry] +name = "fern_basic-auth-pw-omitted" +version = "0.0.1" +description = "" +readme = "README.md" +authors = [] +keywords = [ + "fern", + "test" +] + +classifiers = [ + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", + "Operating System :: OS Independent", + "Operating System :: POSIX", + "Operating System :: MacOS", + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Topic :: Software Development :: Libraries :: Python Modules", + "Typing :: Typed" +] +packages = [ + { include = "seed", from = "src"} +] + +[tool.poetry.urls] +Documentation = 'https://buildwithfern.com/learn' +Homepage = 'https://buildwithfern.com/' +Repository = 'https://github.com/basic-auth-pw-omitted/fern' + +[tool.poetry.dependencies] +python = "^3.10" +aiohttp = { version = ">=3.13.4,<4", optional = true, python = ">=3.9"} +httpx = ">=0.21.2" +httpx-aiohttp = { version = "0.1.8", optional = true, python = ">=3.9"} +pydantic = ">= 1.9.2" +pydantic-core = ">=2.18.2,<2.44.0" +typing_extensions = ">= 4.0.0" + +[tool.poetry.group.dev.dependencies] +mypy = "==1.13.0" +pytest = "^9.0.3" +pytest-asyncio = "^1.0.0" +pytest-xdist = "^3.6.1" +python-dateutil = "^2.9.0" +types-python-dateutil = "^2.9.0.20240316" +urllib3 = ">=1.26.19,<2.0.0 || >=2.2.2,<3.0.0" +requests = "^2.33.0" +types-requests = "^2.33.0" +ruff = "==0.11.5" + +[tool.pytest.ini_options] +testpaths = [ "tests" ] +asyncio_mode = "auto" +markers = [ + "aiohttp: tests that require httpx_aiohttp to be installed", +] + +[tool.mypy] +plugins = ["pydantic.mypy"] + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = [ + "E", # pycodestyle errors + "F", # pyflakes + "I", # isort +] +ignore = [ + "E402", # Module level import not at top of file + "E501", # Line too long + "E711", # Comparison to `None` should be `cond is not None` + "E712", # Avoid equality comparisons to `True`; use `if ...:` checks + "E721", # Use `is` and `is not` for type comparisons, or `isinstance()` for insinstance checks + "E722", # Do not use bare `except` + "E731", # Do not assign a `lambda` expression, use a `def` + "F821", # Undefined name + "F841" # Local variable ... is assigned to but never used +] + +[tool.ruff.lint.isort] +section-order = ["future", "standard-library", "third-party", "first-party"] + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.extras] +aiohttp=["aiohttp", "httpx-aiohttp"] diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/reference.md b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/reference.md new file mode 100644 index 000000000000..f63dc17b0378 --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/reference.md @@ -0,0 +1,136 @@ +# Reference +## BasicAuth +
client.basic_auth.get_with_basic_auth() -> bool +
+
+ +#### 📝 Description + +
+
+ +
+
+ +GET request with basic auth scheme +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from seed import SeedBasicAuthPwOmitted + +client = SeedBasicAuthPwOmitted( + username="", + base_url="https://yourhost.com/path/to/api", +) + +client.basic_auth.get_with_basic_auth() + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.basic_auth.post_with_basic_auth(...) -> bool +
+
+ +#### 📝 Description + +
+
+ +
+
+ +POST request with basic auth scheme +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from seed import SeedBasicAuthPwOmitted + +client = SeedBasicAuthPwOmitted( + username="", + base_url="https://yourhost.com/path/to/api", +) + +client.basic_auth.post_with_basic_auth( + request={"key": "value"}, +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `typing.Any` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/requirements.txt b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/requirements.txt new file mode 100644 index 000000000000..0141a1a5014b --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/requirements.txt @@ -0,0 +1,4 @@ +httpx>=0.21.2 +pydantic>= 1.9.2 +pydantic-core>=2.18.2,<2.44.0 +typing_extensions>= 4.0.0 diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/snippet.json b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/snippet.json new file mode 100644 index 000000000000..fc6352271c8c --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/snippet.json @@ -0,0 +1,31 @@ +{ + "types": {}, + "endpoints": [ + { + "example_identifier": "default", + "id": { + "path": "/basic-auth", + "method": "GET", + "identifier_override": "endpoint_basic-auth.getWithBasicAuth" + }, + "snippet": { + "sync_client": "from seed import SeedBasicAuthPwOmitted\n\nclient = SeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.basic_auth.get_with_basic_auth()\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedBasicAuthPwOmitted\n\nclient = AsyncSeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.basic_auth.get_with_basic_auth()\n\n\nasyncio.run(main())\n", + "type": "python" + } + }, + { + "example_identifier": "default", + "id": { + "path": "/basic-auth", + "method": "POST", + "identifier_override": "endpoint_basic-auth.postWithBasicAuth" + }, + "snippet": { + "sync_client": "from seed import SeedBasicAuthPwOmitted\n\nclient = SeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.basic_auth.post_with_basic_auth(\n request={\"key\": \"value\"},\n)\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedBasicAuthPwOmitted\n\nclient = AsyncSeedBasicAuthPwOmitted(\n username=\"YOUR_USERNAME\",\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.basic_auth.post_with_basic_auth(\n request={\"key\": \"value\"},\n )\n\n\nasyncio.run(main())\n", + "type": "python" + } + } + ] +} \ No newline at end of file diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/_default_clients.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/_default_clients.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/_default_clients.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/_default_clients.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/client.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/client.py similarity index 96% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/client.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/client.py index e9dfdd0fb5cb..8d0866b7d80b 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/client.py +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/client.py @@ -44,7 +44,6 @@ def get_with_basic_auth(self, *, request_options: typing.Optional[RequestOptions client = SeedBasicAuthPwOmitted( username="YOUR_USERNAME", - password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) client.basic_auth.get_with_basic_auth() @@ -75,7 +74,6 @@ def post_with_basic_auth( client = SeedBasicAuthPwOmitted( username="YOUR_USERNAME", - password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) client.basic_auth.post_with_basic_auth( @@ -122,7 +120,6 @@ async def get_with_basic_auth(self, *, request_options: typing.Optional[RequestO client = AsyncSeedBasicAuthPwOmitted( username="YOUR_USERNAME", - password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) @@ -161,7 +158,6 @@ async def post_with_basic_auth( client = AsyncSeedBasicAuthPwOmitted( username="YOUR_USERNAME", - password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/raw_client.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/raw_client.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/basic_auth/raw_client.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/basic_auth/raw_client.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/client.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/client.py similarity index 94% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/client.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/client.py index 45141156dd72..4cd51a30dd51 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/src/seed/client.py +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/client.py @@ -22,7 +22,6 @@ class SeedBasicAuthPwOmitted: The base url to use for requests from the client. username : typing.Union[str, typing.Callable[[], str]] - password : typing.Union[str, typing.Callable[[], str]] headers : typing.Optional[typing.Dict[str, str]] Additional headers to send with every request. @@ -44,7 +43,6 @@ class SeedBasicAuthPwOmitted: client = SeedBasicAuthPwOmitted( username="YOUR_USERNAME", - password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) """ @@ -54,7 +52,6 @@ def __init__( *, base_url: str, username: typing.Union[str, typing.Callable[[], str]], - password: typing.Union[str, typing.Callable[[], str]], headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, @@ -67,7 +64,6 @@ def __init__( self._client_wrapper = SyncClientWrapper( base_url=base_url, username=username, - password=password, headers=headers, httpx_client=httpx_client if httpx_client is not None @@ -116,7 +112,6 @@ class AsyncSeedBasicAuthPwOmitted: The base url to use for requests from the client. username : typing.Union[str, typing.Callable[[], str]] - password : typing.Union[str, typing.Callable[[], str]] headers : typing.Optional[typing.Dict[str, str]] Additional headers to send with every request. @@ -138,7 +133,6 @@ class AsyncSeedBasicAuthPwOmitted: client = AsyncSeedBasicAuthPwOmitted( username="YOUR_USERNAME", - password="YOUR_PASSWORD", base_url="https://yourhost.com/path/to/api", ) """ @@ -148,7 +142,6 @@ def __init__( *, base_url: str, username: typing.Union[str, typing.Callable[[], str]], - password: typing.Union[str, typing.Callable[[], str]], headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, @@ -161,7 +154,6 @@ def __init__( self._client_wrapper = AsyncClientWrapper( base_url=base_url, username=username, - password=password, headers=headers, httpx_client=httpx_client if httpx_client is not None diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/api_error.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/api_error.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/api_error.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/api_error.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/client_wrapper.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/client_wrapper.py similarity index 82% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/client_wrapper.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/client_wrapper.py index 8778a3f34646..405757a5b6ef 100644 --- a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/client_wrapper.py +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/client_wrapper.py @@ -12,14 +12,12 @@ def __init__( self, *, username: typing.Union[str, typing.Callable[[], str]], - password: typing.Union[str, typing.Callable[[], str]], headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, ): self._username = username - self._password = password self._headers = headers self._base_url = base_url self._timeout = timeout @@ -37,7 +35,7 @@ def get_headers(self) -> typing.Dict[str, str]: "X-Fern-SDK-Version": "0.0.1", **(self.get_custom_headers() or {}), } - headers["Authorization"] = httpx.BasicAuth(self._get_username(), self._get_password())._auth_header + headers["Authorization"] = httpx.BasicAuth(self._get_username(), "")._auth_header return headers def _get_username(self) -> str: @@ -46,12 +44,6 @@ def _get_username(self) -> str: else: return self._username() - def _get_password(self) -> str: - if isinstance(self._password, str): - return self._password - else: - return self._password() - def get_custom_headers(self) -> typing.Optional[typing.Dict[str, str]]: return self._headers @@ -67,16 +59,13 @@ def __init__( self, *, username: typing.Union[str, typing.Callable[[], str]], - password: typing.Union[str, typing.Callable[[], str]], headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, logging: typing.Optional[typing.Union[LogConfig, Logger]] = None, httpx_client: httpx.Client, ): - super().__init__( - username=username, password=password, headers=headers, base_url=base_url, timeout=timeout, logging=logging - ) + super().__init__(username=username, headers=headers, base_url=base_url, timeout=timeout, logging=logging) self.httpx_client = HttpClient( httpx_client=httpx_client, base_headers=self.get_headers, @@ -91,7 +80,6 @@ def __init__( self, *, username: typing.Union[str, typing.Callable[[], str]], - password: typing.Union[str, typing.Callable[[], str]], headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, @@ -99,9 +87,7 @@ def __init__( async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None, httpx_client: httpx.AsyncClient, ): - super().__init__( - username=username, password=password, headers=headers, base_url=base_url, timeout=timeout, logging=logging - ) + super().__init__(username=username, headers=headers, base_url=base_url, timeout=timeout, logging=logging) self._async_token = async_token self.httpx_client = AsyncHttpClient( httpx_client=httpx_client, diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/datetime_utils.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/datetime_utils.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/datetime_utils.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/datetime_utils.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/file.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/file.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/file.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/file.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/force_multipart.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/force_multipart.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/force_multipart.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/force_multipart.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_client.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_client.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_client.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_client.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_response.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_response.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_response.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_response.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_api.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_api.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_api.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_api.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_decoders.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_decoders.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_decoders.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_decoders.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_exceptions.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_exceptions.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_exceptions.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_exceptions.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_models.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_models.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/http_sse/_models.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/http_sse/_models.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/jsonable_encoder.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/jsonable_encoder.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/jsonable_encoder.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/jsonable_encoder.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/logging.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/logging.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/logging.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/logging.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/parse_error.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/parse_error.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/parse_error.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/parse_error.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/pydantic_utilities.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/pydantic_utilities.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/pydantic_utilities.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/pydantic_utilities.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/query_encoder.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/query_encoder.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/query_encoder.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/query_encoder.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/remove_none_from_dict.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/remove_none_from_dict.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/remove_none_from_dict.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/remove_none_from_dict.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/request_options.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/request_options.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/request_options.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/request_options.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/core/serialization.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/serialization.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/core/serialization.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/core/serialization.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/errors/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/errors/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/errors/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/errors/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/errors/bad_request.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/errors/bad_request.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/errors/bad_request.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/errors/bad_request.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/errors/unauthorized_request.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/errors/unauthorized_request.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/errors/unauthorized_request.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/errors/unauthorized_request.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/types/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/types/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/types/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/types/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/types/unauthorized_request_error_body.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/types/unauthorized_request_error_body.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/errors/types/unauthorized_request_error_body.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/errors/types/unauthorized_request_error_body.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/py.typed b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/seed/python-sdk/basic-auth-pw-omitted/src/seed/version.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/version.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/src/seed/version.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/src/seed/version.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/conftest.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/conftest.py new file mode 100644 index 000000000000..0614fab9fe1b --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/conftest.py @@ -0,0 +1,147 @@ +""" +Pytest plugin that manages the WireMock container lifecycle for wire tests. + +This plugin is loaded globally for the test suite and is responsible for +starting and stopping the WireMock container exactly once per test run, +including when running with pytest-xdist over the entire project. + +It lives under tests/ (as tests/conftest.py) and is discovered automatically +by pytest's normal test collection rules. +""" + +import os +import subprocess + +import pytest + +_STARTED: bool = False +_EXTERNAL: bool = False # True when using an external WireMock instance (skip container lifecycle) +_WIREMOCK_URL: str = "http://localhost:8080" # Default, will be updated after container starts +_PROJECT_NAME: str = "seed-basic-auth-pw-omitted" + +# This file lives at tests/conftest.py, so the project root is one level up. +_PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +_COMPOSE_FILE = os.path.join(_PROJECT_ROOT, "wiremock", "docker-compose.test.yml") + + +def _get_wiremock_port() -> str: + """Gets the dynamically assigned port for the WireMock container.""" + try: + result = subprocess.run( + ["docker", "compose", "-f", _COMPOSE_FILE, "-p", _PROJECT_NAME, "port", "wiremock", "8080"], + check=True, + capture_output=True, + text=True, + ) + # Output is like "0.0.0.0:32768" or "[::]:32768" + port = result.stdout.strip().split(":")[-1] + return port + except subprocess.CalledProcessError: + return "8080" # Fallback to default + + +def _start_wiremock() -> None: + """Starts the WireMock container using docker-compose.""" + global _STARTED, _EXTERNAL, _WIREMOCK_URL + if _STARTED: + return + + # If WIREMOCK_URL is already set (e.g., by CI/CD pipeline), skip container management + existing_url = os.environ.get("WIREMOCK_URL") + if existing_url: + _WIREMOCK_URL = existing_url + _EXTERNAL = True + _STARTED = True + print(f"\nUsing external WireMock at {_WIREMOCK_URL} (container management skipped)") + return + + print(f"\nStarting WireMock container (project: {_PROJECT_NAME})...") + try: + subprocess.run( + ["docker", "compose", "-f", _COMPOSE_FILE, "-p", _PROJECT_NAME, "up", "-d", "--wait"], + check=True, + capture_output=True, + text=True, + ) + _WIREMOCK_PORT = _get_wiremock_port() + _WIREMOCK_URL = f"http://localhost:{_WIREMOCK_PORT}" + os.environ["WIREMOCK_URL"] = _WIREMOCK_URL + print(f"WireMock container is ready at {_WIREMOCK_URL}") + _STARTED = True + except subprocess.CalledProcessError as e: + print(f"Failed to start WireMock: {e.stderr}") + raise + + +def _stop_wiremock() -> None: + """Stops and removes the WireMock container.""" + if _EXTERNAL: + # Container is managed externally; nothing to tear down. + return + + print("\nStopping WireMock container...") + subprocess.run( + ["docker", "compose", "-f", _COMPOSE_FILE, "-p", _PROJECT_NAME, "down", "-v"], + check=False, + capture_output=True, + ) + + +def _is_xdist_worker(config: pytest.Config) -> bool: + """ + Determines if the current process is an xdist worker. + + In pytest-xdist, worker processes have a 'workerinput' attribute + on the config object, while the controller process does not. + """ + return hasattr(config, "workerinput") + + +def _has_httpx_aiohttp() -> bool: + """Check if httpx_aiohttp is importable.""" + try: + import httpx_aiohttp # type: ignore[import-not-found] # noqa: F401 + + return True + except ImportError: + return False + + +def pytest_collection_modifyitems(config: pytest.Config, items: list) -> None: + """Auto-skip @pytest.mark.aiohttp tests when httpx_aiohttp is not installed.""" + if _has_httpx_aiohttp(): + return + skip_aiohttp = pytest.mark.skip(reason="httpx_aiohttp not installed") + for item in items: + if "aiohttp" in item.keywords: + item.add_marker(skip_aiohttp) + + +def pytest_configure(config: pytest.Config) -> None: + """ + Pytest hook that runs during test session setup. + + Starts WireMock container only from the controller process (xdist) + or the single process (non-xdist). This ensures only one container + is started regardless of the number of worker processes. + """ + if _is_xdist_worker(config): + # Workers never manage the container lifecycle. + return + + _start_wiremock() + + +def pytest_unconfigure(config: pytest.Config) -> None: + """ + Pytest hook that runs during test session teardown. + + Stops WireMock container only from the controller process (xdist) + or the single process (non-xdist). This ensures the container is + cleaned up after all workers have finished. + """ + if _is_xdist_worker(config): + # Workers never manage the container lifecycle. + return + + _stop_wiremock() diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/custom/test_client.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/custom/test_client.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/custom/test_client.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/custom/test_client.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/test_aiohttp_autodetect.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/test_aiohttp_autodetect.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/test_aiohttp_autodetect.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/test_aiohttp_autodetect.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/__init__.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/__init__.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/__init__.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/circle.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/circle.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/circle.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/circle.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/color.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/color.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/color.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/color.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/object_with_defaults.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/object_with_defaults.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/object_with_defaults.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/object_with_defaults.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/object_with_optional_field.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/object_with_optional_field.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/object_with_optional_field.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/object_with_optional_field.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/shape.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/shape.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/shape.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/shape.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/square.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/square.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/square.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/square.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/undiscriminated_shape.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/undiscriminated_shape.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/assets/models/undiscriminated_shape.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/assets/models/undiscriminated_shape.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/test_http_client.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/test_http_client.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/test_http_client.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/test_http_client.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/test_query_encoding.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/test_query_encoding.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/test_query_encoding.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/test_query_encoding.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/tests/utils/test_serialization.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/test_serialization.py similarity index 100% rename from seed/python-sdk/basic-auth-pw-omitted/tests/utils/test_serialization.py rename to seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/utils/test_serialization.py diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/__init__.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/conftest.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/conftest.py new file mode 100644 index 000000000000..82a3eb67f157 --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/conftest.py @@ -0,0 +1,85 @@ +""" +Pytest configuration for wire tests. + +This module provides helpers for creating a configured client that talks to +WireMock and for verifying requests in WireMock. + +The WireMock container lifecycle itself is managed by a top-level pytest +plugin (tests/conftest.py) so that the container is started exactly once +per test run, even when using pytest-xdist. +""" + +import inspect +import os +from typing import Any, Dict, Optional + +import httpx + +from seed.client import SeedBasicAuthPwOmitted + +# Check once at import time whether the client constructor accepts a headers kwarg. +try: + _CLIENT_SUPPORTS_HEADERS: bool = "headers" in inspect.signature(SeedBasicAuthPwOmitted).parameters +except (TypeError, ValueError): + _CLIENT_SUPPORTS_HEADERS = False + + +def _get_wiremock_base_url() -> str: + """Returns the WireMock base URL from the WIREMOCK_URL environment variable.""" + return os.environ.get("WIREMOCK_URL", "http://localhost:8080") + + +def get_client(test_id: str) -> SeedBasicAuthPwOmitted: + """ + Creates a configured client instance for wire tests. + + Args: + test_id: Unique identifier for the test, used for request tracking. + + Returns: + A configured client instance with all required auth parameters. + """ + test_headers = {"X-Test-Id": test_id} + base_url = _get_wiremock_base_url() + + if _CLIENT_SUPPORTS_HEADERS: + return SeedBasicAuthPwOmitted( + base_url=base_url, + headers=test_headers, + username="test-username", + ) + + return SeedBasicAuthPwOmitted( + base_url=base_url, + httpx_client=httpx.Client(headers=test_headers), + username="test-username", + ) + + +def verify_request_count( + test_id: str, + method: str, + url_path: str, + query_params: Optional[Dict[str, Any]], + expected: int, +) -> None: + """Verifies the number of requests made to WireMock filtered by test ID for concurrency safety.""" + wiremock_admin_url = f"{_get_wiremock_base_url()}/__admin" + request_body: Dict[str, Any] = { + "method": method, + "urlPath": url_path, + "headers": {"X-Test-Id": {"equalTo": test_id}}, + } + if query_params: + query_parameters = {} + for k, v in query_params.items(): + if isinstance(v, list): + query_parameters[k] = {"hasExactly": [{"equalTo": item} for item in v]} + else: + query_parameters[k] = {"equalTo": v} + request_body["queryParameters"] = query_parameters + response = httpx.post(f"{wiremock_admin_url}/requests/find", json=request_body) + assert response.status_code == 200, "Failed to query WireMock requests" + result = response.json() + requests_found = len(result.get("requests", [])) + assert requests_found == expected, f"Expected {expected} requests, found {requests_found}" diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/test_basicAuth.py b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/test_basicAuth.py new file mode 100644 index 000000000000..0fa78f88f881 --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/tests/wire/test_basicAuth.py @@ -0,0 +1,19 @@ +from .conftest import get_client, verify_request_count + + +def test_basicAuth_get_with_basic_auth() -> None: + """Test getWithBasicAuth endpoint with WireMock""" + test_id = "basic_auth.get_with_basic_auth.0" + client = get_client(test_id) + client.basic_auth.get_with_basic_auth() + verify_request_count(test_id, "GET", "/basic-auth", None, 1) + + +def test_basicAuth_post_with_basic_auth() -> None: + """Test postWithBasicAuth endpoint with WireMock""" + test_id = "basic_auth.post_with_basic_auth.0" + client = get_client(test_id) + client.basic_auth.post_with_basic_auth( + request={"key": "value"}, + ) + verify_request_count(test_id, "POST", "/basic-auth", None, 1) diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/wiremock/docker-compose.test.yml b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/wiremock/docker-compose.test.yml new file mode 100644 index 000000000000..58747d54a46b --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/wiremock/docker-compose.test.yml @@ -0,0 +1,14 @@ +services: + wiremock: + image: wiremock/wiremock:3.9.1 + ports: + - "0:8080" # Use dynamic port to avoid conflicts with concurrent tests + volumes: + - ./wiremock-mappings.json:/home/wiremock/mappings/wiremock-mappings.json + command: ["--global-response-templating", "--verbose"] + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/__admin/health"] + interval: 2s + timeout: 5s + retries: 15 + start_period: 5s diff --git a/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/wiremock/wiremock-mappings.json b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/wiremock/wiremock-mappings.json new file mode 100644 index 000000000000..8a3e7dd565af --- /dev/null +++ b/seed/python-sdk/basic-auth-pw-omitted/with-wire-tests/wiremock/wiremock-mappings.json @@ -0,0 +1,70 @@ +{ + "mappings": [ + { + "id": "ce59c023-78fc-4d8d-8e8c-95f5e1a6204a", + "name": "getWithBasicAuth - default", + "request": { + "urlPathTemplate": "/basic-auth", + "method": "GET", + "headers": { + "Authorization": { + "equalTo": "Basic dGVzdC11c2VybmFtZTo=" + } + } + }, + "response": { + "status": 200, + "body": "true", + "headers": { + "Content-Type": "application/json" + } + }, + "uuid": "ce59c023-78fc-4d8d-8e8c-95f5e1a6204a", + "persistent": true, + "priority": 3, + "metadata": { + "mocklab": { + "created": { + "at": "2020-01-01T00:00:00.000Z", + "via": "SYSTEM" + } + } + }, + "postServeActions": [] + }, + { + "id": "9cf6385c-29ea-4710-8792-fd2e00adc7c7", + "name": "postWithBasicAuth - default", + "request": { + "urlPathTemplate": "/basic-auth", + "method": "POST", + "headers": { + "Authorization": { + "equalTo": "Basic dGVzdC11c2VybmFtZTo=" + } + } + }, + "response": { + "status": 200, + "body": "true", + "headers": { + "Content-Type": "application/json" + } + }, + "uuid": "9cf6385c-29ea-4710-8792-fd2e00adc7c7", + "persistent": true, + "priority": 3, + "metadata": { + "mocklab": { + "created": { + "at": "2020-01-01T00:00:00.000Z", + "via": "SYSTEM" + } + } + } + } + ], + "meta": { + "total": 2 + } +} \ No newline at end of file diff --git a/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock b/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock index 6edca2a115b4..1d20382bbd7f 100644 --- a/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock +++ b/seed/python-sdk/exhaustive/deps_with_min_python_version/poetry.lock @@ -1030,13 +1030,13 @@ orjson = ">=3.11.5" [[package]] name = "langsmith" -version = "0.7.36" +version = "0.7.37" description = "Client library to connect to the LangSmith Observability and Evaluation Platform." optional = false python-versions = ">=3.10" files = [ - {file = "langsmith-0.7.36-py3-none-any.whl", hash = "sha256:e1657a795f3f1982bb8d34c98b143b630ca3eee9de2c10e670c9105233b54654"}, - {file = "langsmith-0.7.36.tar.gz", hash = "sha256:d18ef34819e0a252cf52c74ce6e9bd5de6deea4f85a3aef50abc9f48d8c5f8b8"}, + {file = "langsmith-0.7.37-py3-none-any.whl", hash = "sha256:64fc5fbf223fcdcc6ee44b08a5df4b2ab8a55e4d968e850c86b6b69fe0c258e3"}, + {file = "langsmith-0.7.37.tar.gz", hash = "sha256:e15ab27f5febbcfbaec4e6fa74ab71f0284f4c5965249cc732fe9344844290cb"}, ] [package.dependencies] diff --git a/seed/python-sdk/seed.yml b/seed/python-sdk/seed.yml index e444e8763fdd..78755a05c56f 100644 --- a/seed/python-sdk/seed.yml +++ b/seed/python-sdk/seed.yml @@ -56,6 +56,10 @@ fixtures: - customConfig: use_inheritance_for_extended_models: false outputFolder: no-inheritance-for-extended-models + basic-auth-pw-omitted: + - customConfig: + enable_wire_tests: true + outputFolder: with-wire-tests allof: - outputFolder: no-custom-config customConfig: diff --git a/seed/python-sdk/undiscriminated-unions/reference.md b/seed/python-sdk/undiscriminated-unions/reference.md index e84cc4cfc525..b464555cf371 100644 --- a/seed/python-sdk/undiscriminated-unions/reference.md +++ b/seed/python-sdk/undiscriminated-unions/reference.md @@ -332,6 +332,124 @@ client.union.nested_unions( + + + + +
client.union.nested_object_unions(...) -> str +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from seed import SeedUndiscriminatedUnions + +client = SeedUndiscriminatedUnions( + base_url="https://yourhost.com/path/to/api", +) + +client.union.nested_object_unions( + request="string", +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `OuterNestedUnion` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ +
client.union.aliased_object_union(...) -> str +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from seed import SeedUndiscriminatedUnions +from seed.union import LeafObjectA + +client = SeedUndiscriminatedUnions( + base_url="https://yourhost.com/path/to/api", +) + +client.union.aliased_object_union( + request=LeafObjectA( + only_in_a="onlyInA", + shared_number=1, + ), +) + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `AliasedObjectUnion` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ +
diff --git a/seed/python-sdk/undiscriminated-unions/snippet.json b/seed/python-sdk/undiscriminated-unions/snippet.json index b1d0d0d6dfbe..79ebb9fd8b4e 100644 --- a/seed/python-sdk/undiscriminated-unions/snippet.json +++ b/seed/python-sdk/undiscriminated-unions/snippet.json @@ -81,6 +81,32 @@ "type": "python" } }, + { + "example_identifier": "default", + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "sync_client": "from seed import SeedUndiscriminatedUnions\n\nclient = SeedUndiscriminatedUnions(\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.union.nested_object_unions(\n request=\"string\",\n)\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedUndiscriminatedUnions\n\nclient = AsyncSeedUndiscriminatedUnions(\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.union.nested_object_unions(\n request=\"string\",\n )\n\n\nasyncio.run(main())\n", + "type": "python" + } + }, + { + "example_identifier": "default", + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "sync_client": "from seed import SeedUndiscriminatedUnions\nfrom seed.union import LeafObjectA\n\nclient = SeedUndiscriminatedUnions(\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.union.aliased_object_union(\n request=LeafObjectA(\n only_in_a=\"onlyInA\",\n shared_number=1,\n ),\n)\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedUndiscriminatedUnions\nfrom seed.union import LeafObjectA\n\nclient = AsyncSeedUndiscriminatedUnions(\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.union.aliased_object_union(\n request=LeafObjectA(\n only_in_a=\"onlyInA\",\n shared_number=1,\n ),\n )\n\n\nasyncio.run(main())\n", + "type": "python" + } + }, { "example_identifier": "default", "id": { diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/__init__.py b/seed/python-sdk/undiscriminated-unions/src/seed/__init__.py index db88f5c29cd4..ac66cb1c3942 100644 --- a/seed/python-sdk/undiscriminated-unions/src/seed/__init__.py +++ b/seed/python-sdk/undiscriminated-unions/src/seed/__init__.py @@ -10,18 +10,28 @@ from ._default_clients import DefaultAioHttpClient, DefaultAsyncHttpxClient from .client import AsyncSeedUndiscriminatedUnions, SeedUndiscriminatedUnions from .union import ( + AliasToLeafB, + AliasedLeafA, + AliasedLeafB, + AliasedObjectUnion, ConvertToken, Key, KeyType, + LeafObjectA, + LeafObjectB, + LeafTypeA, + LeafTypeB, Metadata, MetadataUnion, MyUnion, Name, NamedMetadata, + NestedObjectUnion, NestedUnionL1, NestedUnionL2, NestedUnionRoot, OptionalMetadata, + OuterNestedUnion, PaymentMethodUnion, Request, TokenizeCard, @@ -33,24 +43,35 @@ UnionWithReservedNames, UnionWithTypeAliases, UserId, + WrapperObject, ) from .version import __version__ _dynamic_imports: typing.Dict[str, str] = { + "AliasToLeafB": ".union", + "AliasedLeafA": ".union", + "AliasedLeafB": ".union", + "AliasedObjectUnion": ".union", "AsyncSeedUndiscriminatedUnions": ".client", "ConvertToken": ".union", "DefaultAioHttpClient": "._default_clients", "DefaultAsyncHttpxClient": "._default_clients", "Key": ".union", "KeyType": ".union", + "LeafObjectA": ".union", + "LeafObjectB": ".union", + "LeafTypeA": ".union", + "LeafTypeB": ".union", "Metadata": ".union", "MetadataUnion": ".union", "MyUnion": ".union", "Name": ".union", "NamedMetadata": ".union", + "NestedObjectUnion": ".union", "NestedUnionL1": ".union", "NestedUnionL2": ".union", "NestedUnionRoot": ".union", "OptionalMetadata": ".union", + "OuterNestedUnion": ".union", "PaymentMethodUnion": ".union", "Request": ".union", "SeedUndiscriminatedUnions": ".client", @@ -63,6 +84,7 @@ "UnionWithReservedNames": ".union", "UnionWithTypeAliases": ".union", "UserId": ".union", + "WrapperObject": ".union", "__version__": ".version", "union": ".union", } @@ -90,21 +112,31 @@ def __dir__(): __all__ = [ + "AliasToLeafB", + "AliasedLeafA", + "AliasedLeafB", + "AliasedObjectUnion", "AsyncSeedUndiscriminatedUnions", "ConvertToken", "DefaultAioHttpClient", "DefaultAsyncHttpxClient", "Key", "KeyType", + "LeafObjectA", + "LeafObjectB", + "LeafTypeA", + "LeafTypeB", "Metadata", "MetadataUnion", "MyUnion", "Name", "NamedMetadata", + "NestedObjectUnion", "NestedUnionL1", "NestedUnionL2", "NestedUnionRoot", "OptionalMetadata", + "OuterNestedUnion", "PaymentMethodUnion", "Request", "SeedUndiscriminatedUnions", @@ -117,6 +149,7 @@ def __dir__(): "UnionWithReservedNames", "UnionWithTypeAliases", "UserId", + "WrapperObject", "__version__", "union", ] diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/__init__.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/__init__.py index b5cc9dff05d7..e7a205cb2341 100644 --- a/seed/python-sdk/undiscriminated-unions/src/seed/union/__init__.py +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/__init__.py @@ -7,18 +7,28 @@ if typing.TYPE_CHECKING: from .types import ( + AliasToLeafB, + AliasedLeafA, + AliasedLeafB, + AliasedObjectUnion, ConvertToken, Key, KeyType, + LeafObjectA, + LeafObjectB, + LeafTypeA, + LeafTypeB, Metadata, MetadataUnion, MyUnion, Name, NamedMetadata, + NestedObjectUnion, NestedUnionL1, NestedUnionL2, NestedUnionRoot, OptionalMetadata, + OuterNestedUnion, PaymentMethodUnion, Request, TokenizeCard, @@ -30,20 +40,31 @@ UnionWithReservedNames, UnionWithTypeAliases, UserId, + WrapperObject, ) _dynamic_imports: typing.Dict[str, str] = { + "AliasToLeafB": ".types", + "AliasedLeafA": ".types", + "AliasedLeafB": ".types", + "AliasedObjectUnion": ".types", "ConvertToken": ".types", "Key": ".types", "KeyType": ".types", + "LeafObjectA": ".types", + "LeafObjectB": ".types", + "LeafTypeA": ".types", + "LeafTypeB": ".types", "Metadata": ".types", "MetadataUnion": ".types", "MyUnion": ".types", "Name": ".types", "NamedMetadata": ".types", + "NestedObjectUnion": ".types", "NestedUnionL1": ".types", "NestedUnionL2": ".types", "NestedUnionRoot": ".types", "OptionalMetadata": ".types", + "OuterNestedUnion": ".types", "PaymentMethodUnion": ".types", "Request": ".types", "TokenizeCard": ".types", @@ -55,6 +76,7 @@ "UnionWithReservedNames": ".types", "UnionWithTypeAliases": ".types", "UserId": ".types", + "WrapperObject": ".types", } @@ -80,18 +102,28 @@ def __dir__(): __all__ = [ + "AliasToLeafB", + "AliasedLeafA", + "AliasedLeafB", + "AliasedObjectUnion", "ConvertToken", "Key", "KeyType", + "LeafObjectA", + "LeafObjectB", + "LeafTypeA", + "LeafTypeB", "Metadata", "MetadataUnion", "MyUnion", "Name", "NamedMetadata", + "NestedObjectUnion", "NestedUnionL1", "NestedUnionL2", "NestedUnionRoot", "OptionalMetadata", + "OuterNestedUnion", "PaymentMethodUnion", "Request", "TokenizeCard", @@ -103,4 +135,5 @@ def __dir__(): "UnionWithReservedNames", "UnionWithTypeAliases", "UserId", + "WrapperObject", ] diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/client.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/client.py index 7df59fe7251f..e7b1a48ad20d 100644 --- a/seed/python-sdk/undiscriminated-unions/src/seed/union/client.py +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/client.py @@ -5,10 +5,12 @@ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from ..core.request_options import RequestOptions from .raw_client import AsyncRawUnionClient, RawUnionClient +from .types.aliased_object_union import AliasedObjectUnion from .types.metadata import Metadata from .types.metadata_union import MetadataUnion from .types.my_union import MyUnion from .types.nested_union_root import NestedUnionRoot +from .types.outer_nested_union import OuterNestedUnion from .types.payment_method_union import PaymentMethodUnion from .types.union_with_base_properties import UnionWithBaseProperties from .types.union_with_duplicate_types import UnionWithDuplicateTypes @@ -198,6 +200,68 @@ def nested_unions( _response = self._raw_client.nested_unions(request=request, request_options=request_options) return _response.data + def nested_object_unions( + self, *, request: OuterNestedUnion, request_options: typing.Optional[RequestOptions] = None + ) -> str: + """ + Parameters + ---------- + request : OuterNestedUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + str + + Examples + -------- + from seed import SeedUndiscriminatedUnions + + client = SeedUndiscriminatedUnions( + base_url="https://yourhost.com/path/to/api", + ) + client.union.nested_object_unions( + request="string", + ) + """ + _response = self._raw_client.nested_object_unions(request=request, request_options=request_options) + return _response.data + + def aliased_object_union( + self, *, request: AliasedObjectUnion, request_options: typing.Optional[RequestOptions] = None + ) -> str: + """ + Parameters + ---------- + request : AliasedObjectUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + str + + Examples + -------- + from seed import SeedUndiscriminatedUnions + from seed.union import LeafObjectA + + client = SeedUndiscriminatedUnions( + base_url="https://yourhost.com/path/to/api", + ) + client.union.aliased_object_union( + request=LeafObjectA( + only_in_a="onlyInA", + shared_number=1, + ), + ) + """ + _response = self._raw_client.aliased_object_union(request=request, request_options=request_options) + return _response.data + def get_with_base_properties( self, *, request: UnionWithBaseProperties, request_options: typing.Optional[RequestOptions] = None ) -> UnionWithBaseProperties: @@ -496,6 +560,84 @@ async def main() -> None: _response = await self._raw_client.nested_unions(request=request, request_options=request_options) return _response.data + async def nested_object_unions( + self, *, request: OuterNestedUnion, request_options: typing.Optional[RequestOptions] = None + ) -> str: + """ + Parameters + ---------- + request : OuterNestedUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + str + + Examples + -------- + import asyncio + + from seed import AsyncSeedUndiscriminatedUnions + + client = AsyncSeedUndiscriminatedUnions( + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.union.nested_object_unions( + request="string", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.nested_object_unions(request=request, request_options=request_options) + return _response.data + + async def aliased_object_union( + self, *, request: AliasedObjectUnion, request_options: typing.Optional[RequestOptions] = None + ) -> str: + """ + Parameters + ---------- + request : AliasedObjectUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + str + + Examples + -------- + import asyncio + + from seed import AsyncSeedUndiscriminatedUnions + from seed.union import LeafObjectA + + client = AsyncSeedUndiscriminatedUnions( + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.union.aliased_object_union( + request=LeafObjectA( + only_in_a="onlyInA", + shared_number=1, + ), + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.aliased_object_union(request=request, request_options=request_options) + return _response.data + async def get_with_base_properties( self, *, request: UnionWithBaseProperties, request_options: typing.Optional[RequestOptions] = None ) -> UnionWithBaseProperties: diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/raw_client.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/raw_client.py index 83c613d22a57..ebe2b48922d4 100644 --- a/seed/python-sdk/undiscriminated-unions/src/seed/union/raw_client.py +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/raw_client.py @@ -10,10 +10,12 @@ from ..core.pydantic_utilities import parse_obj_as from ..core.request_options import RequestOptions from ..core.serialization import convert_and_respect_annotation_metadata +from .types.aliased_object_union import AliasedObjectUnion from .types.metadata import Metadata from .types.metadata_union import MetadataUnion from .types.my_union import MyUnion from .types.nested_union_root import NestedUnionRoot +from .types.outer_nested_union import OuterNestedUnion from .types.payment_method_union import PaymentMethodUnion from .types.union_with_base_properties import UnionWithBaseProperties from .types.union_with_duplicate_types import UnionWithDuplicateTypes @@ -274,6 +276,92 @@ def nested_unions( ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + def nested_object_unions( + self, *, request: OuterNestedUnion, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[str]: + """ + Parameters + ---------- + request : OuterNestedUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[str] + """ + _response = self._client_wrapper.httpx_client.request( + "nested-objects", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=OuterNestedUnion, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + str, + parse_obj_as( + type_=str, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + def aliased_object_union( + self, *, request: AliasedObjectUnion, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[str]: + """ + Parameters + ---------- + request : AliasedObjectUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[str] + """ + _response = self._client_wrapper.httpx_client.request( + "aliased-object", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=AliasedObjectUnion, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + str, + parse_obj_as( + type_=str, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + def get_with_base_properties( self, *, request: UnionWithBaseProperties, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[UnionWithBaseProperties]: @@ -616,6 +704,92 @@ async def nested_unions( ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + async def nested_object_unions( + self, *, request: OuterNestedUnion, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[str]: + """ + Parameters + ---------- + request : OuterNestedUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[str] + """ + _response = await self._client_wrapper.httpx_client.request( + "nested-objects", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=OuterNestedUnion, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + str, + parse_obj_as( + type_=str, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def aliased_object_union( + self, *, request: AliasedObjectUnion, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[str]: + """ + Parameters + ---------- + request : AliasedObjectUnion + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[str] + """ + _response = await self._client_wrapper.httpx_client.request( + "aliased-object", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=AliasedObjectUnion, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + str, + parse_obj_as( + type_=str, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + async def get_with_base_properties( self, *, request: UnionWithBaseProperties, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[UnionWithBaseProperties]: diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/__init__.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/__init__.py index 11e283ecb216..d52e7d164741 100644 --- a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/__init__.py +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/__init__.py @@ -6,18 +6,28 @@ from importlib import import_module if typing.TYPE_CHECKING: + from .alias_to_leaf_b import AliasToLeafB + from .aliased_leaf_a import AliasedLeafA + from .aliased_leaf_b import AliasedLeafB + from .aliased_object_union import AliasedObjectUnion from .convert_token import ConvertToken from .key import Key from .key_type import KeyType + from .leaf_object_a import LeafObjectA + from .leaf_object_b import LeafObjectB + from .leaf_type_a import LeafTypeA + from .leaf_type_b import LeafTypeB from .metadata import Metadata from .metadata_union import MetadataUnion from .my_union import MyUnion from .name import Name from .named_metadata import NamedMetadata + from .nested_object_union import NestedObjectUnion from .nested_union_l1 import NestedUnionL1 from .nested_union_l2 import NestedUnionL2 from .nested_union_root import NestedUnionRoot from .optional_metadata import OptionalMetadata + from .outer_nested_union import OuterNestedUnion from .payment_method_union import PaymentMethodUnion from .request import Request from .tokenize_card import TokenizeCard @@ -29,19 +39,30 @@ from .union_with_reserved_names import UnionWithReservedNames from .union_with_type_aliases import UnionWithTypeAliases from .user_id import UserId + from .wrapper_object import WrapperObject _dynamic_imports: typing.Dict[str, str] = { + "AliasToLeafB": ".alias_to_leaf_b", + "AliasedLeafA": ".aliased_leaf_a", + "AliasedLeafB": ".aliased_leaf_b", + "AliasedObjectUnion": ".aliased_object_union", "ConvertToken": ".convert_token", "Key": ".key", "KeyType": ".key_type", + "LeafObjectA": ".leaf_object_a", + "LeafObjectB": ".leaf_object_b", + "LeafTypeA": ".leaf_type_a", + "LeafTypeB": ".leaf_type_b", "Metadata": ".metadata", "MetadataUnion": ".metadata_union", "MyUnion": ".my_union", "Name": ".name", "NamedMetadata": ".named_metadata", + "NestedObjectUnion": ".nested_object_union", "NestedUnionL1": ".nested_union_l1", "NestedUnionL2": ".nested_union_l2", "NestedUnionRoot": ".nested_union_root", "OptionalMetadata": ".optional_metadata", + "OuterNestedUnion": ".outer_nested_union", "PaymentMethodUnion": ".payment_method_union", "Request": ".request", "TokenizeCard": ".tokenize_card", @@ -53,6 +74,7 @@ "UnionWithReservedNames": ".union_with_reserved_names", "UnionWithTypeAliases": ".union_with_type_aliases", "UserId": ".user_id", + "WrapperObject": ".wrapper_object", } @@ -78,18 +100,28 @@ def __dir__(): __all__ = [ + "AliasToLeafB", + "AliasedLeafA", + "AliasedLeafB", + "AliasedObjectUnion", "ConvertToken", "Key", "KeyType", + "LeafObjectA", + "LeafObjectB", + "LeafTypeA", + "LeafTypeB", "Metadata", "MetadataUnion", "MyUnion", "Name", "NamedMetadata", + "NestedObjectUnion", "NestedUnionL1", "NestedUnionL2", "NestedUnionRoot", "OptionalMetadata", + "OuterNestedUnion", "PaymentMethodUnion", "Request", "TokenizeCard", @@ -101,4 +133,5 @@ def __dir__(): "UnionWithReservedNames", "UnionWithTypeAliases", "UserId", + "WrapperObject", ] diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/alias_to_leaf_b.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/alias_to_leaf_b.py new file mode 100644 index 000000000000..cd51328b3ef1 --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/alias_to_leaf_b.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +from .leaf_object_b import LeafObjectB + +AliasToLeafB = LeafObjectB diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_leaf_a.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_leaf_a.py new file mode 100644 index 000000000000..3b873a3613a5 --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_leaf_a.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +from .leaf_object_a import LeafObjectA + +AliasedLeafA = LeafObjectA +""" +An alias around LeafObjectA. +""" diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_leaf_b.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_leaf_b.py new file mode 100644 index 000000000000..7ef24996d876 --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_leaf_b.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +from .alias_to_leaf_b import AliasToLeafB + +AliasedLeafB = AliasToLeafB +""" +An alias around an alias around LeafObjectB, to exercise the alias-walk loop. +""" diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_object_union.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_object_union.py new file mode 100644 index 000000000000..35cbefbe17ff --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/aliased_object_union.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from .aliased_leaf_a import AliasedLeafA +from .aliased_leaf_b import AliasedLeafB + +AliasedObjectUnion = typing.Union[AliasedLeafA, AliasedLeafB] diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_object_a.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_object_a.py new file mode 100644 index 000000000000..900d5d7e7f5e --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_object_a.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class LeafObjectA(UniversalBaseModel): + only_in_a: typing_extensions.Annotated[str, FieldMetadata(alias="onlyInA"), pydantic.Field(alias="onlyInA")] + shared_number: typing_extensions.Annotated[ + int, FieldMetadata(alias="sharedNumber"), pydantic.Field(alias="sharedNumber") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_object_b.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_object_b.py new file mode 100644 index 000000000000..47465e89dc2f --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_object_b.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class LeafObjectB(UniversalBaseModel): + only_in_b: typing_extensions.Annotated[str, FieldMetadata(alias="onlyInB"), pydantic.Field(alias="onlyInB")] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_type_a.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_type_a.py new file mode 100644 index 000000000000..53ed0fb211c4 --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_type_a.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class LeafTypeA(UniversalBaseModel): + alpha: str + beta: int + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_type_b.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_type_b.py new file mode 100644 index 000000000000..5c19ba5ca72d --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/leaf_type_b.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class LeafTypeB(UniversalBaseModel): + gamma: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/nested_object_union.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/nested_object_union.py new file mode 100644 index 000000000000..fa34ae1d4a2e --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/nested_object_union.py @@ -0,0 +1,8 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from .leaf_type_a import LeafTypeA +from .leaf_type_b import LeafTypeB + +NestedObjectUnion = typing.Union[LeafTypeA, LeafTypeB] diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/outer_nested_union.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/outer_nested_union.py new file mode 100644 index 000000000000..c0ad93c35fd2 --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/outer_nested_union.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from .wrapper_object import WrapperObject + +OuterNestedUnion = typing.Union[str, WrapperObject] diff --git a/seed/python-sdk/undiscriminated-unions/src/seed/union/types/wrapper_object.py b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/wrapper_object.py new file mode 100644 index 000000000000..4e8d3fed9846 --- /dev/null +++ b/seed/python-sdk/undiscriminated-unions/src/seed/union/types/wrapper_object.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .nested_object_union import NestedObjectUnion + + +class WrapperObject(UniversalBaseModel): + inner: NestedObjectUnion + label: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example10/snippet.rb b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example10/snippet.rb index f21b41a55c1a..ab098df1d8d4 100644 --- a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example10/snippet.rb +++ b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example10/snippet.rb @@ -2,7 +2,7 @@ client = Seed::Client.new(base_url: "https://api.fern.com") -client.union.test_camel_case_properties(payment_method: { - method_: "card", - card_number: "1234567890123456" +client.union.aliased_object_union(request: { + only_in_a: "onlyInA", + shared_number: 1 }) diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example11/snippet.rb b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example11/snippet.rb index 0ba6bd369c48..d35bb509984c 100644 --- a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example11/snippet.rb +++ b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example11/snippet.rb @@ -2,7 +2,7 @@ client = Seed::Client.new(base_url: "https://api.fern.com") -client.union.test_camel_case_properties(payment_method: { - method_: "method", - card_number: "cardNumber" -}) +client.union.get_with_base_properties( + name: "name", + value: {} +) diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example12/snippet.rb b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example12/snippet.rb new file mode 100644 index 000000000000..f21b41a55c1a --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example12/snippet.rb @@ -0,0 +1,8 @@ +require "seed" + +client = Seed::Client.new(base_url: "https://api.fern.com") + +client.union.test_camel_case_properties(payment_method: { + method_: "card", + card_number: "1234567890123456" +}) diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example13/snippet.rb b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example13/snippet.rb new file mode 100644 index 000000000000..0ba6bd369c48 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example13/snippet.rb @@ -0,0 +1,8 @@ +require "seed" + +client = Seed::Client.new(base_url: "https://api.fern.com") + +client.union.test_camel_case_properties(payment_method: { + method_: "method", + card_number: "cardNumber" +}) diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example9/snippet.rb b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example9/snippet.rb index d35bb509984c..0fafec05f46e 100644 --- a/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example9/snippet.rb +++ b/seed/ruby-sdk-v2/undiscriminated-unions/dynamic-snippets/example9/snippet.rb @@ -2,7 +2,4 @@ client = Seed::Client.new(base_url: "https://api.fern.com") -client.union.get_with_base_properties( - name: "name", - value: {} -) +client.union.nested_object_unions(request: "string") diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed.rb index 09d77c58bf1e..8c46fc27e815 100644 --- a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed.rb +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed.rb @@ -58,6 +58,17 @@ require_relative "seed/union/types/user_id" require_relative "seed/union/types/name" require_relative "seed/union/types/union_with_type_aliases" +require_relative "seed/union/types/leaf_type_a" +require_relative "seed/union/types/leaf_type_b" +require_relative "seed/union/types/nested_object_union" +require_relative "seed/union/types/wrapper_object" +require_relative "seed/union/types/outer_nested_union" +require_relative "seed/union/types/leaf_object_a" +require_relative "seed/union/types/aliased_leaf_a" +require_relative "seed/union/types/leaf_object_b" +require_relative "seed/union/types/alias_to_leaf_b" +require_relative "seed/union/types/aliased_leaf_b" +require_relative "seed/union/types/aliased_object_union" require_relative "seed/client" require_relative "seed/union/client" require_relative "seed/union/types/payment_request" diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/client.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/client.rb index 221535c41630..9cb7cc12d79c 100644 --- a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/client.rb +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/client.rb @@ -195,6 +195,66 @@ def nested_unions(request_options: {}, **params) raise error_class.new(response.body, code: code) end + # @param request_options [Hash] + # @param params [Seed::Union::Types::OuterNestedUnion] + # @option request_options [String] :base_url + # @option request_options [Hash{String => Object}] :additional_headers + # @option request_options [Hash{String => Object}] :additional_query_parameters + # @option request_options [Hash{String => Object}] :additional_body_parameters + # @option request_options [Integer] :timeout_in_seconds + # + # @return [String] + def nested_object_unions(request_options: {}, **params) + params = Seed::Internal::Types::Utils.normalize_keys(params) + request = Seed::Internal::JSON::Request.new( + base_url: request_options[:base_url], + method: "POST", + path: "/nested-objects", + body: Seed::Union::Types::OuterNestedUnion.new(params).to_h, + request_options: request_options + ) + begin + response = @client.send(request) + rescue Net::HTTPRequestTimeout + raise Seed::Errors::TimeoutError + end + code = response.code.to_i + return if code.between?(200, 299) + + error_class = Seed::Errors::ResponseError.subclass_for_code(code) + raise error_class.new(response.body, code: code) + end + + # @param request_options [Hash] + # @param params [Seed::Union::Types::AliasedObjectUnion] + # @option request_options [String] :base_url + # @option request_options [Hash{String => Object}] :additional_headers + # @option request_options [Hash{String => Object}] :additional_query_parameters + # @option request_options [Hash{String => Object}] :additional_body_parameters + # @option request_options [Integer] :timeout_in_seconds + # + # @return [String] + def aliased_object_union(request_options: {}, **params) + params = Seed::Internal::Types::Utils.normalize_keys(params) + request = Seed::Internal::JSON::Request.new( + base_url: request_options[:base_url], + method: "POST", + path: "/aliased-object", + body: Seed::Union::Types::AliasedObjectUnion.new(params).to_h, + request_options: request_options + ) + begin + response = @client.send(request) + rescue Net::HTTPRequestTimeout + raise Seed::Errors::TimeoutError + end + code = response.code.to_i + return if code.between?(200, 299) + + error_class = Seed::Errors::ResponseError.subclass_for_code(code) + raise error_class.new(response.body, code: code) + end + # @param request_options [Hash] # @param params [Seed::Union::Types::UnionWithBaseProperties] # @option request_options [String] :base_url diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/alias_to_leaf_b.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/alias_to_leaf_b.rb new file mode 100644 index 000000000000..313c5b2765e9 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/alias_to_leaf_b.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + module AliasToLeafB + # AliasToLeafB is an alias for LeafObjectB + + # @option str [String] + # + # @return [untyped] + def self.load(str) + ::JSON.parse(str) + end + + # @option value [untyped] + # + # @return [String] + def self.dump(value) + ::JSON.generate(value) + end + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_leaf_a.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_leaf_a.rb new file mode 100644 index 000000000000..cfece888f106 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_leaf_a.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + module AliasedLeafA + # AliasedLeafA is an alias for LeafObjectA + + # @option str [String] + # + # @return [untyped] + def self.load(str) + ::JSON.parse(str) + end + + # @option value [untyped] + # + # @return [String] + def self.dump(value) + ::JSON.generate(value) + end + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_leaf_b.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_leaf_b.rb new file mode 100644 index 000000000000..cfe5c4a1a432 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_leaf_b.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + module AliasedLeafB + # AliasedLeafB is an alias for AliasToLeafB + + # @option str [String] + # + # @return [untyped] + def self.load(str) + ::JSON.parse(str) + end + + # @option value [untyped] + # + # @return [String] + def self.dump(value) + ::JSON.generate(value) + end + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_object_union.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_object_union.rb new file mode 100644 index 000000000000..e4d1cb138547 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/aliased_object_union.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + # Undiscriminated union whose members are named aliases of object types + # (including an alias-of-alias). Required keys are disjoint, so a correct + # deserializer must emit containsKey() guards for each alias variant. + class AliasedObjectUnion < Internal::Types::Model + extend Seed::Internal::Types::Union + + member -> { Seed::Union::Types::LeafObjectA } + member -> { Seed::Union::Types::LeafObjectB } + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_object_a.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_object_a.rb new file mode 100644 index 000000000000..e007e33327b3 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_object_a.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + class LeafObjectA < Internal::Types::Model + field :only_in_a, -> { String }, optional: false, nullable: false, api_name: "onlyInA" + field :shared_number, -> { Integer }, optional: false, nullable: false, api_name: "sharedNumber" + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_object_b.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_object_b.rb new file mode 100644 index 000000000000..d32a605387f0 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_object_b.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + class LeafObjectB < Internal::Types::Model + field :only_in_b, -> { String }, optional: false, nullable: false, api_name: "onlyInB" + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_type_a.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_type_a.rb new file mode 100644 index 000000000000..1b49d96af1bc --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_type_a.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + class LeafTypeA < Internal::Types::Model + field :alpha, -> { String }, optional: false, nullable: false + field :beta, -> { Integer }, optional: false, nullable: false + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_type_b.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_type_b.rb new file mode 100644 index 000000000000..c91cdbae9a70 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/leaf_type_b.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + class LeafTypeB < Internal::Types::Model + field :gamma, -> { String }, optional: false, nullable: false + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/nested_object_union.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/nested_object_union.rb new file mode 100644 index 000000000000..6f6998868d5a --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/nested_object_union.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + # Inner union with two object variants that have disjoint required keys. + # Tests that required-key guards work correctly inside nested union contexts. + class NestedObjectUnion < Internal::Types::Model + extend Seed::Internal::Types::Union + + member -> { Seed::Union::Types::LeafTypeA } + member -> { Seed::Union::Types::LeafTypeB } + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/outer_nested_union.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/outer_nested_union.rb new file mode 100644 index 000000000000..ca57c8fb1c66 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/outer_nested_union.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + # Outer union where one variant is an object containing a nested union field. + # Tests that the deserializer correctly handles transitive union deserialization. + class OuterNestedUnion < Internal::Types::Model + extend Seed::Internal::Types::Union + + member -> { String } + member -> { Seed::Union::Types::WrapperObject } + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/wrapper_object.rb b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/wrapper_object.rb new file mode 100644 index 000000000000..dea3f2f5e0f4 --- /dev/null +++ b/seed/ruby-sdk-v2/undiscriminated-unions/lib/seed/union/types/wrapper_object.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Seed + module Union + module Types + class WrapperObject < Internal::Types::Model + field :inner, -> { Seed::Union::Types::NestedObjectUnion }, optional: false, nullable: false + field :label, -> { String }, optional: false, nullable: false + end + end + end +end diff --git a/seed/ruby-sdk-v2/undiscriminated-unions/reference.md b/seed/ruby-sdk-v2/undiscriminated-unions/reference.md index 631d53560584..68b6affc437b 100644 --- a/seed/ruby-sdk-v2/undiscriminated-unions/reference.md +++ b/seed/ruby-sdk-v2/undiscriminated-unions/reference.md @@ -276,6 +276,105 @@ client.union.nested_unions(request: "string") + + + + +
client.union.nested_object_unions(request) -> String +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```ruby +client.union.nested_object_unions(request: "string") +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Seed::Union::Types::OuterNestedUnion` + +
+
+ +
+
+ +**request_options:** `Seed::Union::RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.union.aliased_object_union(request) -> String +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```ruby +client.union.aliased_object_union(request: { + only_in_a: "onlyInA", + shared_number: 1 +}) +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `Seed::Union::Types::AliasedObjectUnion` + +
+
+ +
+
+ +**request_options:** `Seed::Union::RequestOptions` + +
+
+
+
+ +
diff --git a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example10.rs b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example10.rs index 6877eba6052e..c41585cd723f 100644 --- a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example10.rs +++ b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example10.rs @@ -9,14 +9,12 @@ async fn main() { let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); client .union_ - .test_camel_case_properties( - &PaymentRequest { - payment_method: PaymentMethodUnion::TokenizeCard(TokenizeCard { - method: "card".to_string(), - card_number: "1234567890123456".to_string(), - ..Default::default() - }), - }, + .aliased_object_union( + &AliasedObjectUnion::AliasedLeafA(AliasedLeafA(LeafObjectA { + only_in_a: "onlyInA".to_string(), + shared_number: 1, + ..Default::default() + })), None, ) .await; diff --git a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example11.rs b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example11.rs index ce63fef72927..e175d0f0c111 100644 --- a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example11.rs +++ b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example11.rs @@ -9,14 +9,12 @@ async fn main() { let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); client .union_ - .test_camel_case_properties( - &PaymentRequest { - payment_method: PaymentMethodUnion::TokenizeCard(TokenizeCard { - method: "method".to_string(), - card_number: "cardNumber".to_string(), - ..Default::default() - }), - }, + .get_with_base_properties( + &UnionWithBaseProperties::NamedMetadata(NamedMetadata { + name: "name".to_string(), + value: HashMap::from([("value".to_string(), serde_json::json!({"key":"value"}))]), + ..Default::default() + }), None, ) .await; diff --git a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example12.rs b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example12.rs new file mode 100644 index 000000000000..6877eba6052e --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example12.rs @@ -0,0 +1,23 @@ +use seed_undiscriminated_unions::prelude::*; + +#[tokio::main] +async fn main() { + let config = ClientConfig { + base_url: "https://api.fern.com".to_string(), + ..Default::default() + }; + let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); + client + .union_ + .test_camel_case_properties( + &PaymentRequest { + payment_method: PaymentMethodUnion::TokenizeCard(TokenizeCard { + method: "card".to_string(), + card_number: "1234567890123456".to_string(), + ..Default::default() + }), + }, + None, + ) + .await; +} diff --git a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example13.rs b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example13.rs new file mode 100644 index 000000000000..ce63fef72927 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example13.rs @@ -0,0 +1,23 @@ +use seed_undiscriminated_unions::prelude::*; + +#[tokio::main] +async fn main() { + let config = ClientConfig { + base_url: "https://api.fern.com".to_string(), + ..Default::default() + }; + let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); + client + .union_ + .test_camel_case_properties( + &PaymentRequest { + payment_method: PaymentMethodUnion::TokenizeCard(TokenizeCard { + method: "method".to_string(), + card_number: "cardNumber".to_string(), + ..Default::default() + }), + }, + None, + ) + .await; +} diff --git a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example9.rs b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example9.rs index e175d0f0c111..d5815750f91e 100644 --- a/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example9.rs +++ b/seed/rust-sdk/undiscriminated-unions/dynamic-snippets/example9.rs @@ -9,13 +9,6 @@ async fn main() { let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); client .union_ - .get_with_base_properties( - &UnionWithBaseProperties::NamedMetadata(NamedMetadata { - name: "name".to_string(), - value: HashMap::from([("value".to_string(), serde_json::json!({"key":"value"}))]), - ..Default::default() - }), - None, - ) + .nested_object_unions(&OuterNestedUnion::String("string".to_string()), None) .await; } diff --git a/seed/rust-sdk/undiscriminated-unions/reference.md b/seed/rust-sdk/undiscriminated-unions/reference.md index 0c0a7080ba52..571faecc4028 100644 --- a/seed/rust-sdk/undiscriminated-unions/reference.md +++ b/seed/rust-sdk/undiscriminated-unions/reference.md @@ -229,6 +229,87 @@ async fn main() { + + + + +
client.union_.nested_object_unions(request: OuterNestedUnion) -> Result<String, ApiError> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```rust +use seed_undiscriminated_unions::prelude::*; + +#[tokio::main] +async fn main() { + let config = ClientConfig { + ..Default::default() + }; + let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); + client + .union_ + .nested_object_unions(&OuterNestedUnion::String("string".to_string()), None) + .await; +} +``` +
+
+
+
+ + +
+
+
+ +
client.union_.aliased_object_union(request: AliasedObjectUnion) -> Result<String, ApiError> +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```rust +use seed_undiscriminated_unions::prelude::*; + +#[tokio::main] +async fn main() { + let config = ClientConfig { + ..Default::default() + }; + let client = UndiscriminatedUnionsClient::new(config).expect("Failed to build client"); + client + .union_ + .aliased_object_union( + &AliasedObjectUnion::AliasedLeafA(AliasedLeafA(LeafObjectA { + only_in_a: "onlyInA".to_string(), + shared_number: 1, + ..Default::default() + })), + None, + ) + .await; +} +``` +
+
+
+
+ +
diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/resources/union_/union_.rs b/seed/rust-sdk/undiscriminated-unions/src/api/resources/union_/union_.rs index 64342fa7605f..f0f403625d9e 100644 --- a/seed/rust-sdk/undiscriminated-unions/src/api/resources/union_/union_.rs +++ b/seed/rust-sdk/undiscriminated-unions/src/api/resources/union_/union_.rs @@ -102,6 +102,38 @@ impl UnionClient { .await } + pub async fn nested_object_unions( + &self, + request: &OuterNestedUnion, + options: Option, + ) -> Result { + self.http_client + .execute_request( + Method::POST, + "/nested-objects", + Some(serde_json::to_value(request).map_err(ApiError::Serialization)?), + None, + options, + ) + .await + } + + pub async fn aliased_object_union( + &self, + request: &AliasedObjectUnion, + options: Option, + ) -> Result { + self.http_client + .execute_request( + Method::POST, + "/aliased-object", + Some(serde_json::to_value(request).map_err(ApiError::Serialization)?), + None, + options, + ) + .await + } + pub async fn get_with_base_properties( &self, request: &UnionWithBaseProperties, diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/mod.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/mod.rs index 99c8ca1829cc..10b7a1df9c8b 100644 --- a/seed/rust-sdk/undiscriminated-unions/src/api/types/mod.rs +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/mod.rs @@ -1,16 +1,26 @@ pub mod payment_request; +pub mod union_alias_to_leaf_b; +pub mod union_aliased_leaf_a; +pub mod union_aliased_leaf_b; +pub mod union_aliased_object_union; pub mod union_convert_token; pub mod union_key; pub mod union_key_type; +pub mod union_leaf_object_a; +pub mod union_leaf_object_b; +pub mod union_leaf_type_a; +pub mod union_leaf_type_b; pub mod union_metadata; pub mod union_metadata_union; pub mod union_my_union; pub mod union_name; pub mod union_named_metadata; +pub mod union_nested_object_union; pub mod union_nested_union_l_1; pub mod union_nested_union_l_2; pub mod union_nested_union_root; pub mod union_optional_metadata; +pub mod union_outer_nested_union; pub mod union_payment_method_union; pub mod union_request; pub mod union_tokenize_card; @@ -22,20 +32,31 @@ pub mod union_union_with_identical_strings; pub mod union_union_with_reserved_names; pub mod union_union_with_type_aliases; pub mod union_user_id; +pub mod union_wrapper_object; pub use payment_request::PaymentRequest; +pub use union_alias_to_leaf_b::AliasToLeafB; +pub use union_aliased_leaf_a::AliasedLeafA; +pub use union_aliased_leaf_b::AliasedLeafB; +pub use union_aliased_object_union::AliasedObjectUnion; pub use union_convert_token::ConvertToken; pub use union_key::Key; pub use union_key_type::KeyType; +pub use union_leaf_object_a::LeafObjectA; +pub use union_leaf_object_b::LeafObjectB; +pub use union_leaf_type_a::LeafTypeA; +pub use union_leaf_type_b::LeafTypeB; pub use union_metadata::Metadata; pub use union_metadata_union::MetadataUnion; pub use union_my_union::MyUnion; pub use union_name::Name; pub use union_named_metadata::NamedMetadata; +pub use union_nested_object_union::NestedObjectUnion; pub use union_nested_union_l_1::NestedUnionL1; pub use union_nested_union_l_2::NestedUnionL2; pub use union_nested_union_root::NestedUnionRoot; pub use union_optional_metadata::OptionalMetadata; +pub use union_outer_nested_union::OuterNestedUnion; pub use union_payment_method_union::PaymentMethodUnion; pub use union_request::Request; pub use union_tokenize_card::TokenizeCard; @@ -47,3 +68,4 @@ pub use union_union_with_identical_strings::UnionWithIdenticalStrings; pub use union_union_with_reserved_names::UnionWithReservedNames; pub use union_union_with_type_aliases::UnionWithTypeAliases; pub use union_user_id::UserId; +pub use union_wrapper_object::WrapperObject; diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_alias_to_leaf_b.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_alias_to_leaf_b.rs new file mode 100644 index 000000000000..e95b863bde29 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_alias_to_leaf_b.rs @@ -0,0 +1,4 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Default)] +pub struct AliasToLeafB(pub LeafObjectB); diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_leaf_a.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_leaf_a.rs new file mode 100644 index 000000000000..00847b0c43dd --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_leaf_a.rs @@ -0,0 +1,4 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Default)] +pub struct AliasedLeafA(pub LeafObjectA); diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_leaf_b.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_leaf_b.rs new file mode 100644 index 000000000000..9819535517d5 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_leaf_b.rs @@ -0,0 +1,4 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Default)] +pub struct AliasedLeafB(pub AliasToLeafB); diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_object_union.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_object_union.rs new file mode 100644 index 000000000000..80815e71a71c --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_aliased_object_union.rs @@ -0,0 +1,64 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum AliasedObjectUnion { + AliasedLeafA(AliasedLeafA), + + AliasedLeafB(AliasedLeafB), +} + +impl AliasedObjectUnion { + pub fn is_aliased_leaf_a(&self) -> bool { + matches!(self, Self::AliasedLeafA(_)) + } + + pub fn is_aliased_leaf_b(&self) -> bool { + matches!(self, Self::AliasedLeafB(_)) + } + + pub fn as_aliased_leaf_a(&self) -> Option<&AliasedLeafA> { + match self { + Self::AliasedLeafA(value) => Some(value), + _ => None, + } + } + + pub fn into_aliased_leaf_a(self) -> Option { + match self { + Self::AliasedLeafA(value) => Some(value), + _ => None, + } + } + + pub fn as_aliased_leaf_b(&self) -> Option<&AliasedLeafB> { + match self { + Self::AliasedLeafB(value) => Some(value), + _ => None, + } + } + + pub fn into_aliased_leaf_b(self) -> Option { + match self { + Self::AliasedLeafB(value) => Some(value), + _ => None, + } + } +} + +impl fmt::Display for AliasedObjectUnion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::AliasedLeafA(value) => write!( + f, + "{}", + serde_json::to_string(value).unwrap_or_else(|_| format!("{:?}", value)) + ), + Self::AliasedLeafB(value) => write!( + f, + "{}", + serde_json::to_string(value).unwrap_or_else(|_| format!("{:?}", value)) + ), + } + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_object_a.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_object_a.rs new file mode 100644 index 000000000000..ce2c0e3b7790 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_object_a.rs @@ -0,0 +1,51 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +pub struct LeafObjectA { + #[serde(rename = "onlyInA")] + #[serde(default)] + pub only_in_a: String, + #[serde(rename = "sharedNumber")] + #[serde(default)] + pub shared_number: i64, +} + +impl LeafObjectA { + pub fn builder() -> LeafObjectABuilder { + ::default() + } +} + +#[derive(Clone, PartialEq, Default, Debug)] +#[non_exhaustive] +pub struct LeafObjectABuilder { + only_in_a: Option, + shared_number: Option, +} + +impl LeafObjectABuilder { + pub fn only_in_a(mut self, value: impl Into) -> Self { + self.only_in_a = Some(value.into()); + self + } + + pub fn shared_number(mut self, value: i64) -> Self { + self.shared_number = Some(value); + self + } + + /// Consumes the builder and constructs a [`LeafObjectA`]. + /// This method will fail if any of the following fields are not set: + /// - [`only_in_a`](LeafObjectABuilder::only_in_a) + /// - [`shared_number`](LeafObjectABuilder::shared_number) + pub fn build(self) -> Result { + Ok(LeafObjectA { + only_in_a: self + .only_in_a + .ok_or_else(|| BuildError::missing_field("only_in_a"))?, + shared_number: self + .shared_number + .ok_or_else(|| BuildError::missing_field("shared_number"))?, + }) + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_object_b.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_object_b.rs new file mode 100644 index 000000000000..5592206dcc27 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_object_b.rs @@ -0,0 +1,38 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +pub struct LeafObjectB { + #[serde(rename = "onlyInB")] + #[serde(default)] + pub only_in_b: String, +} + +impl LeafObjectB { + pub fn builder() -> LeafObjectBBuilder { + ::default() + } +} + +#[derive(Clone, PartialEq, Default, Debug)] +#[non_exhaustive] +pub struct LeafObjectBBuilder { + only_in_b: Option, +} + +impl LeafObjectBBuilder { + pub fn only_in_b(mut self, value: impl Into) -> Self { + self.only_in_b = Some(value.into()); + self + } + + /// Consumes the builder and constructs a [`LeafObjectB`]. + /// This method will fail if any of the following fields are not set: + /// - [`only_in_b`](LeafObjectBBuilder::only_in_b) + pub fn build(self) -> Result { + Ok(LeafObjectB { + only_in_b: self + .only_in_b + .ok_or_else(|| BuildError::missing_field("only_in_b"))?, + }) + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_type_a.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_type_a.rs new file mode 100644 index 000000000000..b29fedaa9d64 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_type_a.rs @@ -0,0 +1,47 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +pub struct LeafTypeA { + #[serde(default)] + pub alpha: String, + #[serde(default)] + pub beta: i64, +} + +impl LeafTypeA { + pub fn builder() -> LeafTypeABuilder { + ::default() + } +} + +#[derive(Clone, PartialEq, Default, Debug)] +#[non_exhaustive] +pub struct LeafTypeABuilder { + alpha: Option, + beta: Option, +} + +impl LeafTypeABuilder { + pub fn alpha(mut self, value: impl Into) -> Self { + self.alpha = Some(value.into()); + self + } + + pub fn beta(mut self, value: i64) -> Self { + self.beta = Some(value); + self + } + + /// Consumes the builder and constructs a [`LeafTypeA`]. + /// This method will fail if any of the following fields are not set: + /// - [`alpha`](LeafTypeABuilder::alpha) + /// - [`beta`](LeafTypeABuilder::beta) + pub fn build(self) -> Result { + Ok(LeafTypeA { + alpha: self + .alpha + .ok_or_else(|| BuildError::missing_field("alpha"))?, + beta: self.beta.ok_or_else(|| BuildError::missing_field("beta"))?, + }) + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_type_b.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_type_b.rs new file mode 100644 index 000000000000..0df3c85bbdb2 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_leaf_type_b.rs @@ -0,0 +1,37 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +#[serde(transparent)] +pub struct LeafTypeB { + pub gamma: String, +} + +impl LeafTypeB { + pub fn builder() -> LeafTypeBBuilder { + ::default() + } +} + +#[derive(Clone, PartialEq, Default, Debug)] +#[non_exhaustive] +pub struct LeafTypeBBuilder { + gamma: Option, +} + +impl LeafTypeBBuilder { + pub fn gamma(mut self, value: impl Into) -> Self { + self.gamma = Some(value.into()); + self + } + + /// Consumes the builder and constructs a [`LeafTypeB`]. + /// This method will fail if any of the following fields are not set: + /// - [`gamma`](LeafTypeBBuilder::gamma) + pub fn build(self) -> Result { + Ok(LeafTypeB { + gamma: self + .gamma + .ok_or_else(|| BuildError::missing_field("gamma"))?, + }) + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_nested_object_union.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_nested_object_union.rs new file mode 100644 index 000000000000..37fc2323f727 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_nested_object_union.rs @@ -0,0 +1,64 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum NestedObjectUnion { + LeafTypeA(LeafTypeA), + + LeafTypeB(LeafTypeB), +} + +impl NestedObjectUnion { + pub fn is_leaf_type_a(&self) -> bool { + matches!(self, Self::LeafTypeA(_)) + } + + pub fn is_leaf_type_b(&self) -> bool { + matches!(self, Self::LeafTypeB(_)) + } + + pub fn as_leaf_type_a(&self) -> Option<&LeafTypeA> { + match self { + Self::LeafTypeA(value) => Some(value), + _ => None, + } + } + + pub fn into_leaf_type_a(self) -> Option { + match self { + Self::LeafTypeA(value) => Some(value), + _ => None, + } + } + + pub fn as_leaf_type_b(&self) -> Option<&LeafTypeB> { + match self { + Self::LeafTypeB(value) => Some(value), + _ => None, + } + } + + pub fn into_leaf_type_b(self) -> Option { + match self { + Self::LeafTypeB(value) => Some(value), + _ => None, + } + } +} + +impl fmt::Display for NestedObjectUnion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::LeafTypeA(value) => write!( + f, + "{}", + serde_json::to_string(value).unwrap_or_else(|_| format!("{:?}", value)) + ), + Self::LeafTypeB(value) => write!( + f, + "{}", + serde_json::to_string(value).unwrap_or_else(|_| format!("{:?}", value)) + ), + } + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_outer_nested_union.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_outer_nested_union.rs new file mode 100644 index 000000000000..719e787c5943 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_outer_nested_union.rs @@ -0,0 +1,60 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum OuterNestedUnion { + String(String), + + WrapperObject(WrapperObject), +} + +impl OuterNestedUnion { + pub fn is_string(&self) -> bool { + matches!(self, Self::String(_)) + } + + pub fn is_wrapper_object(&self) -> bool { + matches!(self, Self::WrapperObject(_)) + } + + pub fn as_string(&self) -> Option<&str> { + match self { + Self::String(value) => Some(value), + _ => None, + } + } + + pub fn into_string(self) -> Option { + match self { + Self::String(value) => Some(value), + _ => None, + } + } + + pub fn as_wrapper_object(&self) -> Option<&WrapperObject> { + match self { + Self::WrapperObject(value) => Some(value), + _ => None, + } + } + + pub fn into_wrapper_object(self) -> Option { + match self { + Self::WrapperObject(value) => Some(value), + _ => None, + } + } +} + +impl fmt::Display for OuterNestedUnion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::String(value) => write!(f, "{}", value), + Self::WrapperObject(value) => write!( + f, + "{}", + serde_json::to_string(value).unwrap_or_else(|_| format!("{:?}", value)) + ), + } + } +} diff --git a/seed/rust-sdk/undiscriminated-unions/src/api/types/union_wrapper_object.rs b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_wrapper_object.rs new file mode 100644 index 000000000000..44a375be5631 --- /dev/null +++ b/seed/rust-sdk/undiscriminated-unions/src/api/types/union_wrapper_object.rs @@ -0,0 +1,48 @@ +pub use crate::prelude::*; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] +pub struct WrapperObject { + pub inner: NestedObjectUnion, + #[serde(default)] + pub label: String, +} + +impl WrapperObject { + pub fn builder() -> WrapperObjectBuilder { + ::default() + } +} + +#[derive(Clone, PartialEq, Default, Debug)] +#[non_exhaustive] +pub struct WrapperObjectBuilder { + inner: Option, + label: Option, +} + +impl WrapperObjectBuilder { + pub fn inner(mut self, value: NestedObjectUnion) -> Self { + self.inner = Some(value); + self + } + + pub fn label(mut self, value: impl Into) -> Self { + self.label = Some(value.into()); + self + } + + /// Consumes the builder and constructs a [`WrapperObject`]. + /// This method will fail if any of the following fields are not set: + /// - [`inner`](WrapperObjectBuilder::inner) + /// - [`label`](WrapperObjectBuilder::label) + pub fn build(self) -> Result { + Ok(WrapperObject { + inner: self + .inner + .ok_or_else(|| BuildError::missing_field("inner"))?, + label: self + .label + .ok_or_else(|| BuildError::missing_field("label"))?, + }) + } +} diff --git a/seed/swift-sdk/undiscriminated-unions/Snippets/Example10.swift b/seed/swift-sdk/undiscriminated-unions/Snippets/Example10.swift index f6d2c24e67c9..75b399fd07e6 100644 --- a/seed/swift-sdk/undiscriminated-unions/Snippets/Example10.swift +++ b/seed/swift-sdk/undiscriminated-unions/Snippets/Example10.swift @@ -4,12 +4,12 @@ import UndiscriminatedUnions private func main() async throws { let client = UndiscriminatedUnionsClient(baseURL: "https://api.fern.com") - _ = try await client.union.testCamelCaseProperties(request: .init(paymentMethod: PaymentMethodUnion.tokenizeCard( - TokenizeCard( - method: "card", - cardNumber: "1234567890123456" + _ = try await client.union.aliasedObjectUnion(request: AliasedObjectUnion.aliasedLeafA( + LeafObjectA( + onlyInA: "onlyInA", + sharedNumber: 1 ) - ))) + )) } try await main() diff --git a/seed/swift-sdk/undiscriminated-unions/Snippets/Example11.swift b/seed/swift-sdk/undiscriminated-unions/Snippets/Example11.swift index 69bda5d29717..3d02ab8065e9 100644 --- a/seed/swift-sdk/undiscriminated-unions/Snippets/Example11.swift +++ b/seed/swift-sdk/undiscriminated-unions/Snippets/Example11.swift @@ -4,12 +4,16 @@ import UndiscriminatedUnions private func main() async throws { let client = UndiscriminatedUnionsClient(baseURL: "https://api.fern.com") - _ = try await client.union.testCamelCaseProperties(request: .init(paymentMethod: PaymentMethodUnion.tokenizeCard( - TokenizeCard( - method: "method", - cardNumber: "cardNumber" + _ = try await client.union.getWithBaseProperties(request: UnionWithBaseProperties.namedMetadata( + NamedMetadata( + name: "name", + value: [ + "value": .object([ + "key": .string("value") + ]) + ] ) - ))) + )) } try await main() diff --git a/seed/swift-sdk/undiscriminated-unions/Snippets/Example12.swift b/seed/swift-sdk/undiscriminated-unions/Snippets/Example12.swift new file mode 100644 index 000000000000..f6d2c24e67c9 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Snippets/Example12.swift @@ -0,0 +1,15 @@ +import Foundation +import UndiscriminatedUnions + +private func main() async throws { + let client = UndiscriminatedUnionsClient(baseURL: "https://api.fern.com") + + _ = try await client.union.testCamelCaseProperties(request: .init(paymentMethod: PaymentMethodUnion.tokenizeCard( + TokenizeCard( + method: "card", + cardNumber: "1234567890123456" + ) + ))) +} + +try await main() diff --git a/seed/swift-sdk/undiscriminated-unions/Snippets/Example13.swift b/seed/swift-sdk/undiscriminated-unions/Snippets/Example13.swift new file mode 100644 index 000000000000..69bda5d29717 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Snippets/Example13.swift @@ -0,0 +1,15 @@ +import Foundation +import UndiscriminatedUnions + +private func main() async throws { + let client = UndiscriminatedUnionsClient(baseURL: "https://api.fern.com") + + _ = try await client.union.testCamelCaseProperties(request: .init(paymentMethod: PaymentMethodUnion.tokenizeCard( + TokenizeCard( + method: "method", + cardNumber: "cardNumber" + ) + ))) +} + +try await main() diff --git a/seed/swift-sdk/undiscriminated-unions/Snippets/Example9.swift b/seed/swift-sdk/undiscriminated-unions/Snippets/Example9.swift index 3d02ab8065e9..9de0cdbbf029 100644 --- a/seed/swift-sdk/undiscriminated-unions/Snippets/Example9.swift +++ b/seed/swift-sdk/undiscriminated-unions/Snippets/Example9.swift @@ -4,15 +4,8 @@ import UndiscriminatedUnions private func main() async throws { let client = UndiscriminatedUnionsClient(baseURL: "https://api.fern.com") - _ = try await client.union.getWithBaseProperties(request: UnionWithBaseProperties.namedMetadata( - NamedMetadata( - name: "name", - value: [ - "value": .object([ - "key": .string("value") - ]) - ] - ) + _ = try await client.union.nestedObjectUnions(request: OuterNestedUnion.string( + "string" )) } diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Resources/Union/UnionClient.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Resources/Union/UnionClient.swift index 243c70f5c56d..667174b2ef4c 100644 --- a/seed/swift-sdk/undiscriminated-unions/Sources/Resources/Union/UnionClient.swift +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Resources/Union/UnionClient.swift @@ -66,6 +66,26 @@ public final class UnionClient: Sendable { ) } + public func nestedObjectUnions(request: OuterNestedUnion, requestOptions: RequestOptions? = nil) async throws -> String { + return try await httpClient.performRequest( + method: .post, + path: "/nested-objects", + body: request, + requestOptions: requestOptions, + responseType: String.self + ) + } + + public func aliasedObjectUnion(request: AliasedObjectUnion, requestOptions: RequestOptions? = nil) async throws -> String { + return try await httpClient.performRequest( + method: .post, + path: "/aliased-object", + body: request, + requestOptions: requestOptions, + responseType: String.self + ) + } + public func getWithBaseProperties(request: UnionWithBaseProperties, requestOptions: RequestOptions? = nil) async throws -> UnionWithBaseProperties { return try await httpClient.performRequest( method: .post, diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasToLeafB.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasToLeafB.swift new file mode 100644 index 000000000000..bf7e8565bd06 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasToLeafB.swift @@ -0,0 +1,3 @@ +import Foundation + +public typealias AliasToLeafB = LeafObjectB diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedLeafA.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedLeafA.swift new file mode 100644 index 000000000000..80445800ed64 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedLeafA.swift @@ -0,0 +1,4 @@ +import Foundation + +/// An alias around LeafObjectA. +public typealias AliasedLeafA = LeafObjectA diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedLeafB.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedLeafB.swift new file mode 100644 index 000000000000..eeb68490fa93 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedLeafB.swift @@ -0,0 +1,4 @@ +import Foundation + +/// An alias around an alias around LeafObjectB, to exercise the alias-walk loop. +public typealias AliasedLeafB = AliasToLeafB diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedObjectUnion.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedObjectUnion.swift new file mode 100644 index 000000000000..1e1f21a02b3e --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/AliasedObjectUnion.swift @@ -0,0 +1,33 @@ +import Foundation + +/// Undiscriminated union whose members are named aliases of object types +/// (including an alias-of-alias). Required keys are disjoint, so a correct +/// deserializer must emit containsKey() guards for each alias variant. +public enum AliasedObjectUnion: Codable, Hashable, Sendable { + case aliasedLeafA(AliasedLeafA) + case aliasedLeafB(AliasedLeafB) + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if let value = try? container.decode(AliasedLeafA.self) { + self = .aliasedLeafA(value) + } else if let value = try? container.decode(AliasedLeafB.self) { + self = .aliasedLeafB(value) + } else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Unexpected value." + ) + } + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.singleValueContainer() + switch self { + case .aliasedLeafA(let value): + try container.encode(value) + case .aliasedLeafB(let value): + try container.encode(value) + } + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafObjectA.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafObjectA.swift new file mode 100644 index 000000000000..7a188608f60b --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafObjectA.swift @@ -0,0 +1,38 @@ +import Foundation + +public struct LeafObjectA: Codable, Hashable, Sendable { + public let onlyInA: String + public let sharedNumber: Int + /// Additional properties that are not explicitly defined in the schema + public let additionalProperties: [String: JSONValue] + + public init( + onlyInA: String, + sharedNumber: Int, + additionalProperties: [String: JSONValue] = .init() + ) { + self.onlyInA = onlyInA + self.sharedNumber = sharedNumber + self.additionalProperties = additionalProperties + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.onlyInA = try container.decode(String.self, forKey: .onlyInA) + self.sharedNumber = try container.decode(Int.self, forKey: .sharedNumber) + self.additionalProperties = try decoder.decodeAdditionalProperties(using: CodingKeys.self) + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.container(keyedBy: CodingKeys.self) + try encoder.encodeAdditionalProperties(self.additionalProperties) + try container.encode(self.onlyInA, forKey: .onlyInA) + try container.encode(self.sharedNumber, forKey: .sharedNumber) + } + + /// Keys for encoding/decoding struct properties. + enum CodingKeys: String, CodingKey, CaseIterable { + case onlyInA + case sharedNumber + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafObjectB.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafObjectB.swift new file mode 100644 index 000000000000..64670e4efb4f --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafObjectB.swift @@ -0,0 +1,32 @@ +import Foundation + +public struct LeafObjectB: Codable, Hashable, Sendable { + public let onlyInB: String + /// Additional properties that are not explicitly defined in the schema + public let additionalProperties: [String: JSONValue] + + public init( + onlyInB: String, + additionalProperties: [String: JSONValue] = .init() + ) { + self.onlyInB = onlyInB + self.additionalProperties = additionalProperties + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.onlyInB = try container.decode(String.self, forKey: .onlyInB) + self.additionalProperties = try decoder.decodeAdditionalProperties(using: CodingKeys.self) + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.container(keyedBy: CodingKeys.self) + try encoder.encodeAdditionalProperties(self.additionalProperties) + try container.encode(self.onlyInB, forKey: .onlyInB) + } + + /// Keys for encoding/decoding struct properties. + enum CodingKeys: String, CodingKey, CaseIterable { + case onlyInB + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafTypeA.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafTypeA.swift new file mode 100644 index 000000000000..0faba170c5c6 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafTypeA.swift @@ -0,0 +1,38 @@ +import Foundation + +public struct LeafTypeA: Codable, Hashable, Sendable { + public let alpha: String + public let beta: Int + /// Additional properties that are not explicitly defined in the schema + public let additionalProperties: [String: JSONValue] + + public init( + alpha: String, + beta: Int, + additionalProperties: [String: JSONValue] = .init() + ) { + self.alpha = alpha + self.beta = beta + self.additionalProperties = additionalProperties + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.alpha = try container.decode(String.self, forKey: .alpha) + self.beta = try container.decode(Int.self, forKey: .beta) + self.additionalProperties = try decoder.decodeAdditionalProperties(using: CodingKeys.self) + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.container(keyedBy: CodingKeys.self) + try encoder.encodeAdditionalProperties(self.additionalProperties) + try container.encode(self.alpha, forKey: .alpha) + try container.encode(self.beta, forKey: .beta) + } + + /// Keys for encoding/decoding struct properties. + enum CodingKeys: String, CodingKey, CaseIterable { + case alpha + case beta + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafTypeB.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafTypeB.swift new file mode 100644 index 000000000000..0866a2cd0433 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/LeafTypeB.swift @@ -0,0 +1,32 @@ +import Foundation + +public struct LeafTypeB: Codable, Hashable, Sendable { + public let gamma: String + /// Additional properties that are not explicitly defined in the schema + public let additionalProperties: [String: JSONValue] + + public init( + gamma: String, + additionalProperties: [String: JSONValue] = .init() + ) { + self.gamma = gamma + self.additionalProperties = additionalProperties + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.gamma = try container.decode(String.self, forKey: .gamma) + self.additionalProperties = try decoder.decodeAdditionalProperties(using: CodingKeys.self) + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.container(keyedBy: CodingKeys.self) + try encoder.encodeAdditionalProperties(self.additionalProperties) + try container.encode(self.gamma, forKey: .gamma) + } + + /// Keys for encoding/decoding struct properties. + enum CodingKeys: String, CodingKey, CaseIterable { + case gamma + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/NestedObjectUnion.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/NestedObjectUnion.swift new file mode 100644 index 000000000000..c835c14a1111 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/NestedObjectUnion.swift @@ -0,0 +1,32 @@ +import Foundation + +/// Inner union with two object variants that have disjoint required keys. +/// Tests that required-key guards work correctly inside nested union contexts. +public enum NestedObjectUnion: Codable, Hashable, Sendable { + case leafTypeA(LeafTypeA) + case leafTypeB(LeafTypeB) + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if let value = try? container.decode(LeafTypeA.self) { + self = .leafTypeA(value) + } else if let value = try? container.decode(LeafTypeB.self) { + self = .leafTypeB(value) + } else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Unexpected value." + ) + } + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.singleValueContainer() + switch self { + case .leafTypeA(let value): + try container.encode(value) + case .leafTypeB(let value): + try container.encode(value) + } + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/OuterNestedUnion.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/OuterNestedUnion.swift new file mode 100644 index 000000000000..d1bd338687f9 --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/OuterNestedUnion.swift @@ -0,0 +1,32 @@ +import Foundation + +/// Outer union where one variant is an object containing a nested union field. +/// Tests that the deserializer correctly handles transitive union deserialization. +public enum OuterNestedUnion: Codable, Hashable, Sendable { + case string(String) + case wrapperObject(WrapperObject) + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if let value = try? container.decode(String.self) { + self = .string(value) + } else if let value = try? container.decode(WrapperObject.self) { + self = .wrapperObject(value) + } else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Unexpected value." + ) + } + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.singleValueContainer() + switch self { + case .string(let value): + try container.encode(value) + case .wrapperObject(let value): + try container.encode(value) + } + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/WrapperObject.swift b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/WrapperObject.swift new file mode 100644 index 000000000000..12ed15347aab --- /dev/null +++ b/seed/swift-sdk/undiscriminated-unions/Sources/Schemas/WrapperObject.swift @@ -0,0 +1,38 @@ +import Foundation + +public struct WrapperObject: Codable, Hashable, Sendable { + public let inner: NestedObjectUnion + public let label: String + /// Additional properties that are not explicitly defined in the schema + public let additionalProperties: [String: JSONValue] + + public init( + inner: NestedObjectUnion, + label: String, + additionalProperties: [String: JSONValue] = .init() + ) { + self.inner = inner + self.label = label + self.additionalProperties = additionalProperties + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.inner = try container.decode(NestedObjectUnion.self, forKey: .inner) + self.label = try container.decode(String.self, forKey: .label) + self.additionalProperties = try decoder.decodeAdditionalProperties(using: CodingKeys.self) + } + + public func encode(to encoder: Encoder) throws -> Void { + var container = encoder.container(keyedBy: CodingKeys.self) + try encoder.encodeAdditionalProperties(self.additionalProperties) + try container.encode(self.inner, forKey: .inner) + try container.encode(self.label, forKey: .label) + } + + /// Keys for encoding/decoding struct properties. + enum CodingKeys: String, CodingKey, CaseIterable { + case inner + case label + } +} \ No newline at end of file diff --git a/seed/swift-sdk/undiscriminated-unions/Tests/Wire/Resources/Union/UnionClientWireTests.swift b/seed/swift-sdk/undiscriminated-unions/Tests/Wire/Resources/Union/UnionClientWireTests.swift index 9bbfccd9a993..ed88eb138279 100644 --- a/seed/swift-sdk/undiscriminated-unions/Tests/Wire/Resources/Union/UnionClientWireTests.swift +++ b/seed/swift-sdk/undiscriminated-unions/Tests/Wire/Resources/Union/UnionClientWireTests.swift @@ -244,6 +244,55 @@ import UndiscriminatedUnions try #require(response == expectedResponse) } + @Test func nestedObjectUnions1() async throws -> Void { + let stub = HTTPStub() + stub.setResponse( + body: Data( + """ + string + """.utf8 + ) + ) + let client = UndiscriminatedUnionsClient( + baseURL: "https://api.fern.com", + urlSession: stub.urlSession + ) + let expectedResponse = "string" + let response = try await client.union.nestedObjectUnions( + request: OuterNestedUnion.string( + "string" + ), + requestOptions: RequestOptions(additionalHeaders: stub.headers) + ) + try #require(response == expectedResponse) + } + + @Test func aliasedObjectUnion1() async throws -> Void { + let stub = HTTPStub() + stub.setResponse( + body: Data( + """ + string + """.utf8 + ) + ) + let client = UndiscriminatedUnionsClient( + baseURL: "https://api.fern.com", + urlSession: stub.urlSession + ) + let expectedResponse = "string" + let response = try await client.union.aliasedObjectUnion( + request: AliasedObjectUnion.aliasedLeafA( + LeafObjectA( + onlyInA: "onlyInA", + sharedNumber: 1 + ) + ), + requestOptions: RequestOptions(additionalHeaders: stub.headers) + ) + try #require(response == expectedResponse) + } + @Test func getWithBaseProperties1() async throws -> Void { let stub = HTTPStub() stub.setResponse( diff --git a/seed/swift-sdk/undiscriminated-unions/reference.md b/seed/swift-sdk/undiscriminated-unions/reference.md index 0406d73a4681..8f59314e6cea 100644 --- a/seed/swift-sdk/undiscriminated-unions/reference.md +++ b/seed/swift-sdk/undiscriminated-unions/reference.md @@ -350,6 +350,127 @@ try await main() + + + + +
client.union.nestedObjectUnions(request: OuterNestedUnion, requestOptions: RequestOptions?) -> String +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```swift +import Foundation +import UndiscriminatedUnions + +private func main() async throws { + let client = UndiscriminatedUnionsClient() + + _ = try await client.union.nestedObjectUnions(request: OuterNestedUnion.string( + "string" + )) +} + +try await main() +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `OuterNestedUnion` + +
+
+ +
+
+ +**requestOptions:** `RequestOptions?` — Additional options for configuring the request, such as custom headers or timeout settings. + +
+
+
+
+ + +
+
+
+ +
client.union.aliasedObjectUnion(request: AliasedObjectUnion, requestOptions: RequestOptions?) -> String +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```swift +import Foundation +import UndiscriminatedUnions + +private func main() async throws { + let client = UndiscriminatedUnionsClient() + + _ = try await client.union.aliasedObjectUnion(request: AliasedObjectUnion.aliasedLeafA( + LeafObjectA( + onlyInA: "onlyInA", + sharedNumber: 1 + ) + )) +} + +try await main() +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `AliasedObjectUnion` + +
+
+ +
+
+ +**requestOptions:** `RequestOptions?` — Additional options for configuring the request, such as custom headers or timeout settings. + +
+
+
+
+ +
diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/reference.md b/seed/ts-sdk/undiscriminated-unions/no-custom-config/reference.md index 459152962633..1df04e71eeef 100644 --- a/seed/ts-sdk/undiscriminated-unions/no-custom-config/reference.md +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/reference.md @@ -292,6 +292,107 @@ await client.union.nestedUnions("string"); + + + + +
client.union.nestedObjectUnions({ ...params }) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.union.nestedObjectUnions("string"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `SeedUndiscriminatedUnions.OuterNestedUnion` + +
+
+ +
+
+ +**requestOptions:** `UnionClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.union.aliasedObjectUnion({ ...params }) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.union.aliasedObjectUnion({ + onlyInA: "onlyInA", + sharedNumber: 1 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `SeedUndiscriminatedUnions.AliasedObjectUnion` + +
+
+ +
+
+ +**requestOptions:** `UnionClient.RequestOptions` + +
+
+
+
+ +
diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/snippet.json b/seed/ts-sdk/undiscriminated-unions/no-custom-config/snippet.json index f21551ff30f0..ee71276b9f7a 100644 --- a/seed/ts-sdk/undiscriminated-unions/no-custom-config/snippet.json +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/snippet.json @@ -66,6 +66,28 @@ "client": "import { SeedUndiscriminatedUnionsClient } from \"@fern/undiscriminated-unions\";\n\nconst client = new SeedUndiscriminatedUnionsClient({ environment: \"YOUR_BASE_URL\" });\nawait client.union.nestedUnions(\"string\");\n" } }, + { + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "typescript", + "client": "import { SeedUndiscriminatedUnionsClient } from \"@fern/undiscriminated-unions\";\n\nconst client = new SeedUndiscriminatedUnionsClient({ environment: \"YOUR_BASE_URL\" });\nawait client.union.nestedObjectUnions(\"string\");\n" + } + }, + { + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "typescript", + "client": "import { SeedUndiscriminatedUnionsClient } from \"@fern/undiscriminated-unions\";\n\nconst client = new SeedUndiscriminatedUnionsClient({ environment: \"YOUR_BASE_URL\" });\nawait client.union.aliasedObjectUnion({\n onlyInA: \"onlyInA\",\n sharedNumber: 1\n});\n" + } + }, { "id": { "path": "/with-base-properties", diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/client/Client.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/client/Client.ts index d3406a6f952e..d1317322b5ce 100644 --- a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/client/Client.ts +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/client/Client.ts @@ -338,6 +338,113 @@ export class UnionClient { return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/nested"); } + /** + * @param {SeedUndiscriminatedUnions.OuterNestedUnion} request + * @param {UnionClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @example + * await client.union.nestedObjectUnions("string") + */ + public nestedObjectUnions( + request: SeedUndiscriminatedUnions.OuterNestedUnion, + requestOptions?: UnionClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__nestedObjectUnions(request, requestOptions)); + } + + private async __nestedObjectUnions( + request: SeedUndiscriminatedUnions.OuterNestedUnion, + requestOptions?: UnionClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders(this._options?.headers, requestOptions?.headers); + const _response = await core.fetcher({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)), + "/nested-objects", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as string, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + throw new errors.SeedUndiscriminatedUnionsError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/nested-objects"); + } + + /** + * @param {SeedUndiscriminatedUnions.AliasedObjectUnion} request + * @param {UnionClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @example + * await client.union.aliasedObjectUnion({ + * onlyInA: "onlyInA", + * sharedNumber: 1 + * }) + */ + public aliasedObjectUnion( + request: SeedUndiscriminatedUnions.AliasedObjectUnion, + requestOptions?: UnionClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__aliasedObjectUnion(request, requestOptions)); + } + + private async __aliasedObjectUnion( + request: SeedUndiscriminatedUnions.AliasedObjectUnion, + requestOptions?: UnionClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders(this._options?.headers, requestOptions?.headers); + const _response = await core.fetcher({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)), + "/aliased-object", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as string, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + throw new errors.SeedUndiscriminatedUnionsError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/aliased-object"); + } + /** * @param {SeedUndiscriminatedUnions.UnionWithBaseProperties} request * @param {UnionClient.RequestOptions} requestOptions - Request-specific configuration. diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasToLeafB.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasToLeafB.ts new file mode 100644 index 000000000000..628a3657db20 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasToLeafB.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +export type AliasToLeafB = SeedUndiscriminatedUnions.LeafObjectB; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedLeafA.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedLeafA.ts new file mode 100644 index 000000000000..e4cb213a3b31 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedLeafA.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * An alias around LeafObjectA. + */ +export type AliasedLeafA = SeedUndiscriminatedUnions.LeafObjectA; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedLeafB.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedLeafB.ts new file mode 100644 index 000000000000..1590b56f9fc4 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedLeafB.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * An alias around an alias around LeafObjectB, to exercise the alias-walk loop. + */ +export type AliasedLeafB = SeedUndiscriminatedUnions.AliasToLeafB; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedObjectUnion.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedObjectUnion.ts new file mode 100644 index 000000000000..393611819287 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/AliasedObjectUnion.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * Undiscriminated union whose members are named aliases of object types + * (including an alias-of-alias). Required keys are disjoint, so a correct + * deserializer must emit containsKey() guards for each alias variant. + */ +export type AliasedObjectUnion = SeedUndiscriminatedUnions.AliasedLeafA | SeedUndiscriminatedUnions.AliasedLeafB; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafObjectA.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafObjectA.ts new file mode 100644 index 000000000000..488559de60e4 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafObjectA.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafObjectA { + onlyInA: string; + sharedNumber: number; +} diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafObjectB.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafObjectB.ts new file mode 100644 index 000000000000..5b1e3e2faef2 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafObjectB.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafObjectB { + onlyInB: string; +} diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafTypeA.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafTypeA.ts new file mode 100644 index 000000000000..98988c041ea7 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafTypeA.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafTypeA { + alpha: string; + beta: number; +} diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafTypeB.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafTypeB.ts new file mode 100644 index 000000000000..634346bc69ba --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/LeafTypeB.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafTypeB { + gamma: string; +} diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/NestedObjectUnion.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/NestedObjectUnion.ts new file mode 100644 index 000000000000..2f68d6e96a4b --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/NestedObjectUnion.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * Inner union with two object variants that have disjoint required keys. + * Tests that required-key guards work correctly inside nested union contexts. + */ +export type NestedObjectUnion = SeedUndiscriminatedUnions.LeafTypeA | SeedUndiscriminatedUnions.LeafTypeB; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/OuterNestedUnion.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/OuterNestedUnion.ts new file mode 100644 index 000000000000..dd430a3024c9 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/OuterNestedUnion.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * Outer union where one variant is an object containing a nested union field. + * Tests that the deserializer correctly handles transitive union deserialization. + */ +export type OuterNestedUnion = string | SeedUndiscriminatedUnions.WrapperObject; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/WrapperObject.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/WrapperObject.ts new file mode 100644 index 000000000000..2048bae4ca48 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/WrapperObject.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +export interface WrapperObject { + inner: SeedUndiscriminatedUnions.NestedObjectUnion; + label: string; +} diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/index.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/index.ts index aa01df0fe275..bdd2c7cfc99f 100644 --- a/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/index.ts +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/src/api/resources/union/types/index.ts @@ -1,15 +1,25 @@ +export * from "./AliasedLeafA.js"; +export * from "./AliasedLeafB.js"; +export * from "./AliasedObjectUnion.js"; +export * from "./AliasToLeafB.js"; export * from "./ConvertToken.js"; export * from "./Key.js"; export * from "./KeyType.js"; +export * from "./LeafObjectA.js"; +export * from "./LeafObjectB.js"; +export * from "./LeafTypeA.js"; +export * from "./LeafTypeB.js"; export * from "./Metadata.js"; export * from "./MetadataUnion.js"; export * from "./MyUnion.js"; export * from "./Name.js"; export * from "./NamedMetadata.js"; +export * from "./NestedObjectUnion.js"; export * from "./NestedUnionL1.js"; export * from "./NestedUnionL2.js"; export * from "./NestedUnionRoot.js"; export * from "./OptionalMetadata.js"; +export * from "./OuterNestedUnion.js"; export * from "./PaymentMethodUnion.js"; export * from "./Request.js"; export * from "./TokenizeCard.js"; @@ -21,3 +31,4 @@ export * from "./UnionWithIdenticalStrings.js"; export * from "./UnionWithReservedNames.js"; export * from "./UnionWithTypeAliases.js"; export * from "./UserId.js"; +export * from "./WrapperObject.js"; diff --git a/seed/ts-sdk/undiscriminated-unions/no-custom-config/tests/wire/union.test.ts b/seed/ts-sdk/undiscriminated-unions/no-custom-config/tests/wire/union.test.ts index 18c38f89f24a..e0c08e39e2df 100644 --- a/seed/ts-sdk/undiscriminated-unions/no-custom-config/tests/wire/union.test.ts +++ b/seed/ts-sdk/undiscriminated-unions/no-custom-config/tests/wire/union.test.ts @@ -121,6 +121,47 @@ describe("UnionClient", () => { expect(response).toEqual(rawResponseBody); }); + test("nestedObjectUnions", async () => { + const server = mockServerPool.createServer(); + const client = new SeedUndiscriminatedUnionsClient({ maxRetries: 0, environment: server.baseUrl }); + const rawRequestBody = "string"; + const rawResponseBody = "string"; + + server + .mockEndpoint() + .post("/nested-objects") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.union.nestedObjectUnions("string"); + expect(response).toEqual(rawResponseBody); + }); + + test("aliasedObjectUnion", async () => { + const server = mockServerPool.createServer(); + const client = new SeedUndiscriminatedUnionsClient({ maxRetries: 0, environment: server.baseUrl }); + const rawRequestBody = { onlyInA: "onlyInA", sharedNumber: 1 }; + const rawResponseBody = "string"; + + server + .mockEndpoint() + .post("/aliased-object") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.union.aliasedObjectUnion({ + onlyInA: "onlyInA", + sharedNumber: 1, + }); + expect(response).toEqual(rawResponseBody); + }); + test("getWithBaseProperties", async () => { const server = mockServerPool.createServer(); const client = new SeedUndiscriminatedUnionsClient({ maxRetries: 0, environment: server.baseUrl }); diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/reference.md b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/reference.md index 459152962633..1df04e71eeef 100644 --- a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/reference.md +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/reference.md @@ -292,6 +292,107 @@ await client.union.nestedUnions("string"); + + + + +
client.union.nestedObjectUnions({ ...params }) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.union.nestedObjectUnions("string"); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `SeedUndiscriminatedUnions.OuterNestedUnion` + +
+
+ +
+
+ +**requestOptions:** `UnionClient.RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.union.aliasedObjectUnion({ ...params }) -> string +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.union.aliasedObjectUnion({ + onlyInA: "onlyInA", + sharedNumber: 1 +}); + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `SeedUndiscriminatedUnions.AliasedObjectUnion` + +
+
+ +
+
+ +**requestOptions:** `UnionClient.RequestOptions` + +
+
+
+
+ +
diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/snippet.json b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/snippet.json index f21551ff30f0..ee71276b9f7a 100644 --- a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/snippet.json +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/snippet.json @@ -66,6 +66,28 @@ "client": "import { SeedUndiscriminatedUnionsClient } from \"@fern/undiscriminated-unions\";\n\nconst client = new SeedUndiscriminatedUnionsClient({ environment: \"YOUR_BASE_URL\" });\nawait client.union.nestedUnions(\"string\");\n" } }, + { + "id": { + "path": "/nested-objects", + "method": "POST", + "identifier_override": "endpoint_union.nestedObjectUnions" + }, + "snippet": { + "type": "typescript", + "client": "import { SeedUndiscriminatedUnionsClient } from \"@fern/undiscriminated-unions\";\n\nconst client = new SeedUndiscriminatedUnionsClient({ environment: \"YOUR_BASE_URL\" });\nawait client.union.nestedObjectUnions(\"string\");\n" + } + }, + { + "id": { + "path": "/aliased-object", + "method": "POST", + "identifier_override": "endpoint_union.aliasedObjectUnion" + }, + "snippet": { + "type": "typescript", + "client": "import { SeedUndiscriminatedUnionsClient } from \"@fern/undiscriminated-unions\";\n\nconst client = new SeedUndiscriminatedUnionsClient({ environment: \"YOUR_BASE_URL\" });\nawait client.union.aliasedObjectUnion({\n onlyInA: \"onlyInA\",\n sharedNumber: 1\n});\n" + } + }, { "id": { "path": "/with-base-properties", diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/client/Client.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/client/Client.ts index d3406a6f952e..d1317322b5ce 100644 --- a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/client/Client.ts +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/client/Client.ts @@ -338,6 +338,113 @@ export class UnionClient { return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/nested"); } + /** + * @param {SeedUndiscriminatedUnions.OuterNestedUnion} request + * @param {UnionClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @example + * await client.union.nestedObjectUnions("string") + */ + public nestedObjectUnions( + request: SeedUndiscriminatedUnions.OuterNestedUnion, + requestOptions?: UnionClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__nestedObjectUnions(request, requestOptions)); + } + + private async __nestedObjectUnions( + request: SeedUndiscriminatedUnions.OuterNestedUnion, + requestOptions?: UnionClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders(this._options?.headers, requestOptions?.headers); + const _response = await core.fetcher({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)), + "/nested-objects", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as string, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + throw new errors.SeedUndiscriminatedUnionsError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/nested-objects"); + } + + /** + * @param {SeedUndiscriminatedUnions.AliasedObjectUnion} request + * @param {UnionClient.RequestOptions} requestOptions - Request-specific configuration. + * + * @example + * await client.union.aliasedObjectUnion({ + * onlyInA: "onlyInA", + * sharedNumber: 1 + * }) + */ + public aliasedObjectUnion( + request: SeedUndiscriminatedUnions.AliasedObjectUnion, + requestOptions?: UnionClient.RequestOptions, + ): core.HttpResponsePromise { + return core.HttpResponsePromise.fromPromise(this.__aliasedObjectUnion(request, requestOptions)); + } + + private async __aliasedObjectUnion( + request: SeedUndiscriminatedUnions.AliasedObjectUnion, + requestOptions?: UnionClient.RequestOptions, + ): Promise> { + const _headers: core.Fetcher.Args["headers"] = mergeHeaders(this._options?.headers, requestOptions?.headers); + const _response = await core.fetcher({ + url: core.url.join( + (await core.Supplier.get(this._options.baseUrl)) ?? + (await core.Supplier.get(this._options.environment)), + "/aliased-object", + ), + method: "POST", + headers: _headers, + contentType: "application/json", + queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(), + requestType: "json", + body: request, + timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000, + maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries, + abortSignal: requestOptions?.abortSignal, + fetchFn: this._options?.fetch, + logging: this._options.logging, + }); + if (_response.ok) { + return { data: _response.body as string, rawResponse: _response.rawResponse }; + } + + if (_response.error.reason === "status-code") { + throw new errors.SeedUndiscriminatedUnionsError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + rawResponse: _response.rawResponse, + }); + } + + return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/aliased-object"); + } + /** * @param {SeedUndiscriminatedUnions.UnionWithBaseProperties} request * @param {UnionClient.RequestOptions} requestOptions - Request-specific configuration. diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasToLeafB.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasToLeafB.ts new file mode 100644 index 000000000000..628a3657db20 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasToLeafB.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +export type AliasToLeafB = SeedUndiscriminatedUnions.LeafObjectB; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedLeafA.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedLeafA.ts new file mode 100644 index 000000000000..e4cb213a3b31 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedLeafA.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * An alias around LeafObjectA. + */ +export type AliasedLeafA = SeedUndiscriminatedUnions.LeafObjectA; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedLeafB.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedLeafB.ts new file mode 100644 index 000000000000..1590b56f9fc4 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedLeafB.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * An alias around an alias around LeafObjectB, to exercise the alias-walk loop. + */ +export type AliasedLeafB = SeedUndiscriminatedUnions.AliasToLeafB; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedObjectUnion.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedObjectUnion.ts new file mode 100644 index 000000000000..393611819287 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/AliasedObjectUnion.ts @@ -0,0 +1,10 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * Undiscriminated union whose members are named aliases of object types + * (including an alias-of-alias). Required keys are disjoint, so a correct + * deserializer must emit containsKey() guards for each alias variant. + */ +export type AliasedObjectUnion = SeedUndiscriminatedUnions.AliasedLeafA | SeedUndiscriminatedUnions.AliasedLeafB; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafObjectA.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafObjectA.ts new file mode 100644 index 000000000000..488559de60e4 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafObjectA.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafObjectA { + onlyInA: string; + sharedNumber: number; +} diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafObjectB.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafObjectB.ts new file mode 100644 index 000000000000..5b1e3e2faef2 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafObjectB.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafObjectB { + onlyInB: string; +} diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafTypeA.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafTypeA.ts new file mode 100644 index 000000000000..98988c041ea7 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafTypeA.ts @@ -0,0 +1,6 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafTypeA { + alpha: string; + beta: number; +} diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafTypeB.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafTypeB.ts new file mode 100644 index 000000000000..634346bc69ba --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/LeafTypeB.ts @@ -0,0 +1,5 @@ +// This file was auto-generated by Fern from our API Definition. + +export interface LeafTypeB { + gamma: string; +} diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/NestedObjectUnion.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/NestedObjectUnion.ts new file mode 100644 index 000000000000..2f68d6e96a4b --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/NestedObjectUnion.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * Inner union with two object variants that have disjoint required keys. + * Tests that required-key guards work correctly inside nested union contexts. + */ +export type NestedObjectUnion = SeedUndiscriminatedUnions.LeafTypeA | SeedUndiscriminatedUnions.LeafTypeB; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/OuterNestedUnion.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/OuterNestedUnion.ts new file mode 100644 index 000000000000..dd430a3024c9 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/OuterNestedUnion.ts @@ -0,0 +1,9 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +/** + * Outer union where one variant is an object containing a nested union field. + * Tests that the deserializer correctly handles transitive union deserialization. + */ +export type OuterNestedUnion = string | SeedUndiscriminatedUnions.WrapperObject; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/WrapperObject.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/WrapperObject.ts new file mode 100644 index 000000000000..2048bae4ca48 --- /dev/null +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/WrapperObject.ts @@ -0,0 +1,8 @@ +// This file was auto-generated by Fern from our API Definition. + +import type * as SeedUndiscriminatedUnions from "../../../index.js"; + +export interface WrapperObject { + inner: SeedUndiscriminatedUnions.NestedObjectUnion; + label: string; +} diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/index.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/index.ts index aa01df0fe275..bdd2c7cfc99f 100644 --- a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/index.ts +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/src/api/resources/union/types/index.ts @@ -1,15 +1,25 @@ +export * from "./AliasedLeafA.js"; +export * from "./AliasedLeafB.js"; +export * from "./AliasedObjectUnion.js"; +export * from "./AliasToLeafB.js"; export * from "./ConvertToken.js"; export * from "./Key.js"; export * from "./KeyType.js"; +export * from "./LeafObjectA.js"; +export * from "./LeafObjectB.js"; +export * from "./LeafTypeA.js"; +export * from "./LeafTypeB.js"; export * from "./Metadata.js"; export * from "./MetadataUnion.js"; export * from "./MyUnion.js"; export * from "./Name.js"; export * from "./NamedMetadata.js"; +export * from "./NestedObjectUnion.js"; export * from "./NestedUnionL1.js"; export * from "./NestedUnionL2.js"; export * from "./NestedUnionRoot.js"; export * from "./OptionalMetadata.js"; +export * from "./OuterNestedUnion.js"; export * from "./PaymentMethodUnion.js"; export * from "./Request.js"; export * from "./TokenizeCard.js"; @@ -21,3 +31,4 @@ export * from "./UnionWithIdenticalStrings.js"; export * from "./UnionWithReservedNames.js"; export * from "./UnionWithTypeAliases.js"; export * from "./UserId.js"; +export * from "./WrapperObject.js"; diff --git a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/tests/wire/union.test.ts b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/tests/wire/union.test.ts index 18c38f89f24a..e0c08e39e2df 100644 --- a/seed/ts-sdk/undiscriminated-unions/skip-response-validation/tests/wire/union.test.ts +++ b/seed/ts-sdk/undiscriminated-unions/skip-response-validation/tests/wire/union.test.ts @@ -121,6 +121,47 @@ describe("UnionClient", () => { expect(response).toEqual(rawResponseBody); }); + test("nestedObjectUnions", async () => { + const server = mockServerPool.createServer(); + const client = new SeedUndiscriminatedUnionsClient({ maxRetries: 0, environment: server.baseUrl }); + const rawRequestBody = "string"; + const rawResponseBody = "string"; + + server + .mockEndpoint() + .post("/nested-objects") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.union.nestedObjectUnions("string"); + expect(response).toEqual(rawResponseBody); + }); + + test("aliasedObjectUnion", async () => { + const server = mockServerPool.createServer(); + const client = new SeedUndiscriminatedUnionsClient({ maxRetries: 0, environment: server.baseUrl }); + const rawRequestBody = { onlyInA: "onlyInA", sharedNumber: 1 }; + const rawResponseBody = "string"; + + server + .mockEndpoint() + .post("/aliased-object") + .jsonBody(rawRequestBody) + .respondWith() + .statusCode(200) + .jsonBody(rawResponseBody) + .build(); + + const response = await client.union.aliasedObjectUnion({ + onlyInA: "onlyInA", + sharedNumber: 1, + }); + expect(response).toEqual(rawResponseBody); + }); + test("getWithBaseProperties", async () => { const server = mockServerPool.createServer(); const client = new SeedUndiscriminatedUnionsClient({ maxRetries: 0, environment: server.baseUrl }); diff --git a/test-definitions/fern/apis/java-websocket-shared-discriminator/definition/api.yml b/test-definitions/fern/apis/java-websocket-shared-discriminator/definition/api.yml new file mode 100644 index 000000000000..57a56e873d46 --- /dev/null +++ b/test-definitions/fern/apis/java-websocket-shared-discriminator/definition/api.yml @@ -0,0 +1 @@ +name: java-websocket-shared-discriminator diff --git a/test-definitions/fern/apis/java-websocket-shared-discriminator/definition/realtime.yml b/test-definitions/fern/apis/java-websocket-shared-discriminator/definition/realtime.yml new file mode 100644 index 000000000000..56de507f7b2c --- /dev/null +++ b/test-definitions/fern/apis/java-websocket-shared-discriminator/definition/realtime.yml @@ -0,0 +1,80 @@ +# yaml-language-server: $schema=./../../../../../fern.schema.json + +# Regression fixture: two server messages share the same "type" literal value +# but have disjoint required fields. The generator must use shape-based trial +# deserialization (not switch-on-type) to route them correctly. + +channel: + path: /realtime + auth: false + messages: + send: + display-name: Send + origin: client + body: SendEvent + conversation_history: + display-name: ConversationHistory + origin: server + body: ConversationHistoryMessage + function_call_history: + display-name: FunctionCallHistory + origin: server + body: FunctionCallHistoryMessage + conversation_text: + display-name: ConversationText + origin: server + body: ConversationTextMessage + examples: + - name: Conversation history + messages: + - type: send + body: + text: "hello" + - type: conversation_history + body: + role: "user" + content: "hello" + - type: function_call_history + body: + function_calls: + - id: "fc_123" + name: "lookup" + arguments: "{}" + - type: conversation_text + body: + text: "Hi there" + confidence: 0.95 + +types: + SendEvent: + properties: + text: string + + # Both ConversationHistoryMessage and FunctionCallHistoryMessage share the + # same "type" literal "History". Without shape-based dispatch, a switch on + # "type" cannot distinguish them. + ConversationHistoryMessage: + properties: + type: + type: literal<"History"> + role: string + content: string + + FunctionCallHistoryMessage: + properties: + type: + type: literal<"History"> + function_calls: list + + ConversationTextMessage: + properties: + type: + type: literal<"ConversationText"> + text: string + confidence: double + + FunctionCall: + properties: + id: string + name: string + arguments: string diff --git a/test-definitions/fern/apis/java-websocket-shared-discriminator/generators.yml b/test-definitions/fern/apis/java-websocket-shared-discriminator/generators.yml new file mode 100644 index 000000000000..211e43123d30 --- /dev/null +++ b/test-definitions/fern/apis/java-websocket-shared-discriminator/generators.yml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://schema.buildwithfern.dev/generators-yml.json +groups: {} diff --git a/test-definitions/fern/apis/undiscriminated-unions/definition/union.yml b/test-definitions/fern/apis/undiscriminated-unions/definition/union.yml index 7fb8584b84d0..939ed70ea340 100644 --- a/test-definitions/fern/apis/undiscriminated-unions/definition/union.yml +++ b/test-definitions/fern/apis/undiscriminated-unions/definition/union.yml @@ -56,6 +56,18 @@ service: request: NestedUnionRoot response: string + nestedObjectUnions: + path: "/nested-objects" + method: POST + request: OuterNestedUnion + response: string + + aliasedObjectUnion: + path: "/aliased-object" + method: POST + request: AliasedObjectUnion + response: string + getWithBaseProperties: path: "/with-base-properties" method: POST @@ -264,3 +276,71 @@ types: - string - UserId - Name + + # Test cases for nested undiscriminated unions with object variants + LeafTypeA: + properties: + alpha: string + beta: integer + + LeafTypeB: + properties: + gamma: string + + NestedObjectUnion: + docs: | + Inner union with two object variants that have disjoint required keys. + Tests that required-key guards work correctly inside nested union contexts. + discriminated: false + union: + - LeafTypeA + - LeafTypeB + + WrapperObject: + properties: + inner: NestedObjectUnion + label: string + + OuterNestedUnion: + docs: | + Outer union where one variant is an object containing a nested union field. + Tests that the deserializer correctly handles transitive union deserialization. + discriminated: false + union: + - string + - WrapperObject + + # Test cases for undiscriminated unions with alias-typed object members. + # Under wrappedAliases: false (the Java default), PoetTypeNameMapper unwraps these + # aliases to the underlying object's class, so the deserializer would emit an + # unguarded convertValue and the alias variant would silently win with all-null + # fields. These fixtures verify that getRequiredWireKeys walks alias chains. + AliasedLeafA: + docs: An alias around LeafObjectA. + type: LeafObjectA + + AliasedLeafB: + docs: An alias around an alias around LeafObjectB, to exercise the alias-walk loop. + type: AliasToLeafB + + AliasToLeafB: + type: LeafObjectB + + LeafObjectA: + properties: + onlyInA: string + sharedNumber: integer + + LeafObjectB: + properties: + onlyInB: string + + AliasedObjectUnion: + docs: | + Undiscriminated union whose members are named aliases of object types + (including an alias-of-alias). Required keys are disjoint, so a correct + deserializer must emit containsKey() guards for each alias variant. + discriminated: false + union: + - AliasedLeafA + - AliasedLeafB