{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://opensdk.dev/schema/v1/opensdk.schema.json",
  "title": "OpenSDK Specification",
  "description": "A companion spec to OpenAPI that declares how SDKs should be generated from an API definition. Version 1.0.0.",
  "type": "object",
  "required": ["opensdk", "openapi", "sdk"],
  "additionalProperties": false,

  "properties": {

    "opensdk": {
      "type": "string",
      "description": "The version of the OpenSDK Specification being used.",
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
      "examples": ["1.0.0"]
    },

    "openapi": {
      "description": "Reference to the source OpenAPI (or AsyncAPI) specification.",
      "oneOf": [
        {
          "type": "object",
          "required": ["$ref"],
          "additionalProperties": false,
          "properties": {
            "$ref": {
              "type": "string",
              "description": "Relative path or absolute URL to the OpenAPI spec file.",
              "examples": ["./spec/openapi.yaml", "https://api.acme.com/openapi.json"]
            },
            "version": {
              "type": "string",
              "description": "Expected OpenAPI version of the referenced spec.",
              "enum": ["3.0", "3.1", "asyncapi-2", "asyncapi-3"]
            }
          }
        }
      ]
    },

    "sdk": {
      "type": "object",
      "description": "Top-level metadata about the SDK being generated.",
      "required": ["name", "version"],
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "description": "Canonical name of the SDK. Used as a base for package names across languages.",
          "examples": ["acme-api", "stripe", "openai"]
        },
        "version": {
          "type": "string",
          "description": "Semantic version of the SDK being generated.",
          "pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$",
          "examples": ["1.2.3", "2.0.0-beta.1"]
        },
        "license": {
          "type": "string",
          "description": "SPDX license identifier.",
          "examples": ["MIT", "Apache-2.0", "MPL-2.0"]
        },
        "homepage": {
          "type": "string",
          "format": "uri",
          "description": "URL to the SDK homepage or documentation."
        },
        "description": {
          "type": "string",
          "description": "Short human-readable description of the SDK."
        },
        "authors": {
          "type": "array",
          "description": "List of SDK authors or maintainers.",
          "items": {
            "type": "object",
            "required": ["name"],
            "additionalProperties": false,
            "properties": {
              "name": { "type": "string" },
              "email": { "type": "string", "format": "email" },
              "url": { "type": "string", "format": "uri" }
            }
          }
        },
        "repository": {
          "type": "string",
          "format": "uri",
          "description": "URL to the SDK source repository.",
          "examples": ["https://github.com/acme/acme-go"]
        }
      }
    },

    "languages": {
      "type": "array",
      "description": "Officially supported language targets and their codegen configuration.",
      "minItems": 1,
      "items": { "$ref": "#/$defs/LanguageTarget" }
    },

    "codegenRules": {
      "$ref": "#/$defs/CodegenRules"
    },

    "extensions": {
      "type": "object",
      "description": "Arbitrary extension fields. Keys MUST begin with 'x-'.",
      "patternProperties": {
        "^x-": {}
      },
      "additionalProperties": false
    }
  },

  "$defs": {

    "LanguageTarget": {
      "type": "object",
      "description": "Codegen configuration for a single target language.",
      "required": ["language"],
      "additionalProperties": false,
      "properties": {
        "language": {
          "type": "string",
          "description": "Target language identifier. Should match generator identifiers (e.g. openapi-generator --generator-name values).",
          "enum": [
            "go", "typescript", "python", "java", "kotlin",
            "ruby", "rust", "csharp", "php", "swift",
            "dart", "scala", "elixir", "c", "cpp"
          ]
        },
        "enabled": {
          "type": "boolean",
          "description": "Whether this language target is active. Defaults to true.",
          "default": true
        },
        "package": {
          "$ref": "#/$defs/PackageConfig"
        },
        "style": {
          "$ref": "#/$defs/StyleConfig"
        },
        "features": {
          "$ref": "#/$defs/FeatureConfig"
        },
        "templates": {
          "$ref": "#/$defs/TemplateConfig"
        },
        "operationOverrides": {
          "type": "array",
          "description": "Per-operation customizations that override global settings.",
          "items": { "$ref": "#/$defs/OperationOverride" }
        },
        "additionalProperties": {
          "type": "object",
          "description": "Arbitrary key-value pairs passed through to the underlying generator.",
          "additionalProperties": true
        },
        "extensions": {
          "type": "object",
          "patternProperties": { "^x-": {} },
          "additionalProperties": false
        }
      }
    },

    "PackageConfig": {
      "type": "object",
      "description": "Package publication metadata for a target language.",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "description": "Package name as it appears in the target ecosystem's registry.",
          "examples": ["@acme/api", "acme-api", "github.com/acme/acme-go", "Acme.API"]
        },
        "version": {
          "type": "string",
          "description": "Package version. Defaults to sdk.version if omitted.",
          "pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$"
        },
        "module": {
          "type": "string",
          "description": "Module or namespace name (used in Go, Java, etc.).",
          "examples": ["acme-go", "com.acme.api"]
        },
        "registry": {
          "type": "string",
          "description": "Registry to publish to.",
          "enum": ["npm", "pypi", "crates.io", "pkg.go.dev", "maven", "nuget", "rubygems", "packagist", "pub", "hex", "custom"],
          "examples": ["npm", "pypi"]
        },
        "registryUrl": {
          "type": "string",
          "format": "uri",
          "description": "Custom registry URL. Only used when registry is 'custom'."
        }
      }
    },

    "StyleConfig": {
      "type": "object",
      "description": "Naming conventions and stylistic rules for the generated SDK.",
      "additionalProperties": false,
      "properties": {
        "naming": {
          "type": "string",
          "description": "Default naming convention for fields, parameters, and variables.",
          "enum": ["camelCase", "snake_case", "PascalCase", "kebab-case", "SCREAMING_SNAKE_CASE"],
          "examples": ["camelCase", "snake_case"]
        },
        "modelNaming": {
          "type": "string",
          "description": "Naming convention specifically for model/schema types. Defaults to naming if omitted.",
          "enum": ["camelCase", "snake_case", "PascalCase", "kebab-case"]
        },
        "operationNaming": {
          "type": "string",
          "description": "Naming convention for operation/method names. Defaults to naming if omitted.",
          "enum": ["camelCase", "snake_case", "PascalCase", "kebab-case"]
        },
        "enumStyle": {
          "type": "string",
          "description": "How enums are represented in generated code.",
          "enum": ["string-union", "numeric-enum", "string-enum", "const-object", "native"],
          "examples": ["string-union", "native"]
        },
        "optionalStyle": {
          "type": "string",
          "description": "How optional fields are expressed.",
          "enum": ["question-mark", "null-union", "option-type", "pointer", "wrapper"],
          "examples": ["question-mark", "pointer"]
        },
        "dateStyle": {
          "type": "string",
          "description": "How date/datetime fields are typed.",
          "enum": ["string", "native", "library"],
          "examples": ["native", "string"]
        },
        "dateLibrary": {
          "type": "string",
          "description": "Date library to use when dateStyle is 'library'.",
          "examples": ["dayjs", "luxon", "java.time", "NSDate"]
        },
        "fileNaming": {
          "type": "string",
          "description": "Convention for generated source file names.",
          "enum": ["camelCase", "snake_case", "kebab-case", "PascalCase"]
        }
      }
    },

    "FeatureConfig": {
      "type": "object",
      "description": "High-level SDK features to generate.",
      "additionalProperties": false,
      "properties": {
        "auth": {
          "description": "Authentication scheme(s) to auto-generate helpers for.",
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "none", "api-key", "bearer", "basic",
                "oauth2-client-credentials", "oauth2-authorization-code",
                "oauth2-device-code", "oidc"
              ]
            },
            {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "none", "api-key", "bearer", "basic",
                  "oauth2-client-credentials", "oauth2-authorization-code",
                  "oauth2-device-code", "oidc"
                ]
              }
            }
          ]
        },
        "retries": {
          "oneOf": [
            { "type": "boolean" },
            {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "enabled": { "type": "boolean" },
                "maxAttempts": { "type": "integer", "minimum": 1 },
                "backoff": {
                  "type": "string",
                  "enum": ["exponential", "linear", "fixed"],
                  "default": "exponential"
                },
                "retryOn": {
                  "type": "array",
                  "description": "HTTP status codes that trigger a retry.",
                  "items": { "type": "integer" },
                  "examples": [[429, 500, 502, 503, 504]]
                }
              }
            }
          ],
          "description": "Retry behavior on transient failures."
        },
        "pagination": {
          "oneOf": [
            { "type": "boolean" },
            {
              "type": "object",
              "additionalProperties": false,
              "required": ["strategy"],
              "properties": {
                "strategy": {
                  "type": "string",
                  "enum": ["cursor", "offset", "page", "link-header", "none"]
                },
                "iteratorHelper": {
                  "type": "boolean",
                  "description": "Emit a helper that transparently iterates pages.",
                  "default": true
                },
                "defaultPageSize": { "type": "integer", "minimum": 1 }
              }
            }
          ],
          "description": "Pagination strategy and iterator helper generation."
        },
        "reconciliation": {
          "type": "string",
          "description": "Emit reconciliation logic for infrastructure/resource management SDKs.",
          "enum": ["none", "terraform", "kubernetes", "pulumi", "custom"]
        },
        "driftDetection": {
          "type": "boolean",
          "description": "Emit helpers to detect drift between desired and actual resource state.",
          "default": false
        },
        "webhooks": {
          "type": "boolean",
          "description": "Generate webhook payload types and signature verification helpers.",
          "default": false
        },
        "mocking": {
          "type": "boolean",
          "description": "Generate a mock server or mock client for testing.",
          "default": false
        },
        "examples": {
          "type": "boolean",
          "description": "Generate usage examples from OpenAPI example objects.",
          "default": true
        },
        "context": {
          "type": "boolean",
          "description": "Thread a context/cancellation token through all operations (primarily Go).",
          "default": false
        },
        "streaming": {
          "type": "boolean",
          "description": "Generate streaming response helpers (SSE, chunked transfer).",
          "default": false
        },
        "telemetry": {
          "type": "object",
          "description": "Emit OpenTelemetry tracing/metrics instrumentation.",
          "additionalProperties": false,
          "properties": {
            "enabled": { "type": "boolean", "default": false },
            "traces": { "type": "boolean", "default": true },
            "metrics": { "type": "boolean", "default": false }
          }
        }
      }
    },

    "TemplateConfig": {
      "type": "object",
      "description": "Template sources and overrides for code generation.",
      "additionalProperties": false,
      "properties": {
        "base": {
          "type": "string",
          "description": "URL or path to a base template set. Generator-specific (e.g. GitHub release tag URL, local path).",
          "examples": [
            "https://github.com/acme/opensdk-templates/ts@v1",
            "./templates/go"
          ]
        },
        "engine": {
          "type": "string",
          "description": "Template engine used by the base templates.",
          "enum": ["mustache", "handlebars", "jinja2", "go-template", "ejs", "custom"],
          "default": "mustache"
        },
        "overrides": {
          "type": "array",
          "description": "Per-operation or per-model template overrides.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "operationId": {
                "type": "string",
                "description": "Matches an operationId from the OpenAPI spec."
              },
              "model": {
                "type": "string",
                "description": "Matches a schema name from the OpenAPI components."
              },
              "template": {
                "type": "string",
                "description": "Path to the override template file.",
                "examples": ["./custom/createWidget.mustache"]
              }
            }
          }
        }
      }
    },

    "OperationOverride": {
      "type": "object",
      "description": "Per-operation customization that takes precedence over global language config.",
      "required": ["operationId"],
      "additionalProperties": false,
      "properties": {
        "operationId": {
          "type": "string",
          "description": "The operationId from the OpenAPI spec to override."
        },
        "methodName": {
          "type": "string",
          "description": "Override the generated method name for this operation."
        },
        "deprecated": {
          "type": "boolean",
          "description": "Mark this operation as deprecated in the generated SDK regardless of the spec."
        },
        "ignore": {
          "type": "boolean",
          "description": "Exclude this operation from generation entirely.",
          "default": false
        },
        "customImplementation": {
          "type": "string",
          "description": "Path to a file that replaces the generated implementation.",
          "examples": ["./custom/impl/createWidget.go"]
        }
      }
    },

    "CodegenRules": {
      "type": "object",
      "description": "Cross-language governance rules applied during generation and validation.",
      "additionalProperties": false,
      "properties": {
        "validation": {
          "type": "array",
          "description": "Rules enforced before generation. Generators should fail if these are violated.",
          "items": {
            "type": "object",
            "required": ["rule"],
            "additionalProperties": false,
            "properties": {
              "rule": {
                "type": "string",
                "description": "Rule identifier.",
                "enum": [
                  "no-unnamed-operations",
                  "required-tags",
                  "no-inline-schemas",
                  "required-descriptions",
                  "no-deprecated-without-successor",
                  "no-empty-responses",
                  "custom"
                ]
              },
              "severity": {
                "type": "string",
                "enum": ["error", "warn", "info"],
                "default": "error"
              },
              "message": {
                "type": "string",
                "description": "Custom message shown when the rule is violated."
              },
              "customRuleUrl": {
                "type": "string",
                "format": "uri",
                "description": "URL to a custom rule script (only used when rule is 'custom')."
              }
            }
          }
        },
        "reconciliation": {
          "type": "object",
          "description": "Settings for resource reconciliation (Terraform/Kubernetes-style).",
          "additionalProperties": false,
          "properties": {
            "mode": {
              "type": "string",
              "enum": ["declarative", "imperative"],
              "description": "Whether the SDK should emit declarative reconcile loops or imperative CRUD helpers."
            },
            "ignoreDrift": {
              "type": "array",
              "description": "Field names whose server-side drift should not trigger reconciliation.",
              "items": { "type": "string" },
              "examples": [["status", "createdAt", "updatedAt"]]
            },
            "immutableFields": {
              "type": "array",
              "description": "Fields that cannot be updated after resource creation.",
              "items": { "type": "string" },
              "examples": [["id", "region"]]
            }
          }
        },
        "breakingChangePolicy": {
          "type": "string",
          "description": "How breaking changes in the OpenAPI spec should be surfaced in the SDK version.",
          "enum": ["major-version-bump", "deprecate-first", "warn-only"],
          "default": "major-version-bump"
        },
        "sdkVersioning": {
          "type": "string",
          "description": "Strategy for deriving the SDK version.",
          "enum": ["semver-from-openapi", "semver-manual", "date-based"],
          "default": "semver-manual"
        },
        "outputStructure": {
          "type": "string",
          "description": "How generated files should be organized on disk.",
          "enum": ["flat", "by-tag", "by-resource", "by-operation"],
          "default": "by-tag"
        },
        "ignoreFields": {
          "type": "array",
          "description": "Global list of field names to exclude from all generated models.",
          "items": { "type": "string" },
          "examples": [["internalId", "__debug"]]
        }
      }
    }
  }
}
