{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://javascriptobfuscator.com/docs/wire-format.schema.json",
  "title": "JSO HTTP API wire format",
  "description": "Request and response shape for the JavaScript Obfuscator HTTP API (HttpApi.ashx). Use this schema with openapi-generator, quicktype, datamodel-code-generator, or any other JSON-Schema-to-types tool to generate a typed client in a language we don't already ship.",
  "$defs": {
    "ProtectRequest": {
      "type": "object",
      "description": "POST body for HttpApi.ashx. Combines credentials, the file list, and any number of protection options.",
      "required": ["APIKey", "APIPwd", "Items"],
      "additionalProperties": true,
      "properties": {
        "APIKey": {
          "type": "string",
          "minLength": 1,
          "description": "Base64-encoded API key from the JSO dashboard. NOT a separate plaintext key — pass the opaque base-64 string through verbatim."
        },
        "APIPwd": {
          "type": "string",
          "minLength": 1,
          "description": "Base64-encoded API password from the JSO dashboard."
        },
        "Name": {
          "type": "string",
          "description": "Project name surfaced in the dashboard audit log. Default per language client: 'python-session', 'dotnet-session', etc.",
          "default": "default"
        },
        "ReleaseLabel": {
          "type": "string",
          "description": "Optional release tag forwarded with the request. Use the commit SHA for CI runs to group audit entries by commit."
        },
        "Items": {
          "type": "array",
          "minItems": 1,
          "description": "Files to protect. The response Items array is keyed by FileName so order does not matter; filenames are normalized to forward-slashes regardless of how they are sent.",
          "items": { "$ref": "#/$defs/ProtectItem" }
        },
        "Compress": { "type": "boolean", "description": "Standard/balanced/maximum: compact whitespace and structural redundancy in the output." },
        "EncodeStrings": { "type": "boolean", "description": "Standard/balanced/maximum: encode string literals using a per-build encoding." },
        "EncryptStrings": { "type": "boolean", "description": "Balanced/maximum: cryptographically encrypt the hoisted string pool." },
        "MoveStringsIntoArray": { "type": "boolean", "description": "Standard/balanced/maximum: hoist all string literals into a single indexed array." },
        "NameMangling": { "type": "boolean", "description": "Standard/balanced/maximum: rename local identifiers to short opaque tokens." },
        "DeepObfuscate": { "type": "boolean", "description": "Balanced/maximum: deeper transforms on nested scope and identifier shadowing." },
        "FlatTransform": { "type": "boolean", "description": "Balanced/maximum: control-flow flattening — linear code becomes a state-machine loop." },
        "CodeTransposition": { "type": "boolean", "description": "Balanced/maximum: reorder statements while preserving semantics." },
        "ProtectMembers": { "type": "boolean", "description": "Maximum: rename non-public object property names." },
        "RenameGlobals": { "type": "boolean", "description": "Maximum: rename globals (be careful — escapes the bundle by definition)." },
        "MoveMembers": { "type": "boolean", "description": "Maximum: relocate member declarations across scope boundaries." },
        "DeadCodeInsertion": { "type": "boolean", "description": "Maximum: splice in provably-unreachable branches to grow the decompiler's search space." },
        "LockDate": { "type": "boolean", "description": "Lock the protected build to expire after LockDateValue." },
        "LockDateValue": { "type": "string", "pattern": "^[0-9]{8}$", "description": "Expiration date in YYYYMMDD format. Use with LockDate=true." },
        "LockDateMsg": { "type": "string", "description": "Optional message displayed when the runtime detects expiry." },
        "LockStartDate": { "type": "boolean", "description": "Prevent the protected build from running before LockStartDateValue." },
        "LockStartDateValue": { "type": "string", "pattern": "^[0-9]{8}$", "description": "Activation date in YYYYMMDD format. Use with LockStartDate=true." },
        "LockStartDateMsg": { "type": "string", "description": "Optional message used when the runtime detects an early launch." },
        "LockBrowser": { "type": "boolean", "description": "Restrict execution to the canonical names in LockBrowserList using browser runtime signals." },
        "LockBrowserList": { "type": "string", "description": "Comma or newline-separated allowlist: chrome, edge, firefox, safari, opera, ie." },
        "LockBrowserMsg": { "type": "string", "description": "Optional message used when the browser allowlist fails." },
        "LockOS": { "type": "boolean", "description": "Restrict execution to the canonical names in LockOSList using browser runtime signals." },
        "LockOSList": { "type": "string", "description": "Comma or newline-separated allowlist: windows, macos, linux, android, ios." },
        "LockOSMsg": { "type": "string", "description": "Optional message used when the operating-system allowlist fails." },
        "LockDomain": { "type": "boolean", "description": "Lock the protected build to one of LockDomainList." },
        "LockDomainList": { "type": "string", "description": "Newline-separated list of domains the protected output is allowed to run on." },
        "LockDomainRedirectUrl": { "type": "string", "description": "Domain-lock-specific HTTP(S) or same-origin root-relative redirect target." },
        "ReservedStrings": { "type": "string", "maxLength": 51300, "description": "Up to 100 newline-delimited regular expressions for literals that must remain verbatim and outside string move/encode transforms." },
        "ForceTransformStrings": { "type": "string", "maxLength": 51300, "description": "Up to 100 newline-delimited regular expressions that override ReservedStrings for matching literals." },
        "SplitStrings": { "type": "boolean", "description": "Split eligible string literals into fixed-length concatenated chunks." },
        "SplitStringsChunkLength": { "type": "integer", "minimum": 1, "maximum": 1024, "default": 10 },
        "StringArrayIndexShift": { "type": "boolean", "description": "Offset moved-string table references by one nonzero slot." },
        "StringArrayShuffle": { "type": "boolean", "description": "Randomize moved-string table order while preserving generated lookups." },
        "StringArrayRotate": { "type": "boolean", "description": "Cyclically rotate moved-string table order by a per-build offset." },
        "StringArrayIndexesType": { "type": "string", "pattern": "^(hexadecimal-number|hexadecimal-numeric-string)(\\n(hexadecimal-number|hexadecimal-numeric-string))*$", "description": "Newline-delimited hexadecimal lookup representations." },
        "StringArrayThreshold": { "type": "number", "minimum": 0, "maximum": 1, "description": "Probability that each unique eligible literal enters the moved-string table." },
        "StringArrayCallsTransform": { "type": "boolean", "description": "Route selected moved-string lookups through a secondary index table." },
        "StringArrayCallsTransformThreshold": { "type": "number", "minimum": 0, "maximum": 1, "description": "Probability that each moved-string lookup receives secondary indirection." },
        "StringArrayWrappersCount": { "type": "integer", "minimum": 0, "maximum": 10, "description": "Root-level string-table wrapper count." },
        "StringArrayWrappersChainedCalls": { "type": "boolean", "description": "Delegate generated wrappers through predecessors." },
        "StringArrayWrappersParametersMaxCount": { "type": "integer", "minimum": 2, "maximum": 5, "description": "Function-wrapper parameter ceiling." },
        "StringArrayWrappersType": { "type": "string", "enum": ["variable", "function"], "description": "Wrapper implementation style." },
        "TransformObjectKeys": { "type": "boolean", "description": "Move safe object-literal data keys into computed string-table lookups." },
        "DebugProtection": { "type": "boolean", "description": "Runtime Defense: throw on detectable debugger attach." },
        "DebugProtectionIntervalMilliseconds": { "type": "integer", "minimum": 0, "maximum": 60000, "description": "Periodic debug timing probe interval. Use 0 or 100-60000 milliseconds." },
        "DisableConsoleOutput": { "type": "boolean", "description": "Runtime Defense: blackhole console.log / warn / error in the protected scope." },
        "SelfDefending": { "type": "boolean", "description": "Runtime Defense: integrity-heartbeat guard. Trips when the protected source is edited." },
		"AntiMonkeyPatching": { "type": "boolean", "description": "Runtime Defense: snapshots selected browser APIs and trips if they are replaced after startup. Browser-only; default false." },
		"AntiMonkeyPatchingMsg": { "type": "string", "description": "Optional message used when AntiMonkeyPatching detects a replaced API." },
        "SelfDefendingIntervalSeconds": { "type": "integer", "minimum": 1, "maximum": 86400, "description": "Heartbeat interval. Lower = more frequent checks = higher detection rate, slightly higher overhead." },
        "BlockDevToolsKeys": { "type": "boolean", "description": "Block F12, Ctrl+Shift+I, and similar devtools-trigger keystrokes in the protected scope." },
        "DetectHeadlessBrowser": { "type": "boolean", "description": "Trip the Runtime Defense beacon when running under Puppeteer/Playwright/Selenium." }
      }
    },

    "ProtectItem": {
      "type": "object",
      "required": ["FileName", "FileCode"],
      "additionalProperties": false,
      "properties": {
        "FileName": { "type": "string", "minLength": 1, "description": "Logical filename. Forward-slash separators; the server normalizes backslashes." },
        "FileCode": { "type": "string", "description": "Source code as a UTF-8 string. Pass the file contents verbatim — no encoding, no escaping." }
      }
    },

    "ProtectResponse": {
      "type": "object",
      "description": "Body shape returned by HttpApi.ashx. HTTP 2xx; failure modes are signalled in the body via a non-Succeed Type.",
      "required": ["Type"],
      "additionalProperties": true,
      "properties": {
        "Type": {
          "type": "string",
          "enum": ["Succeed", "Error", "SourceError", "Exception", "ServerException", "LoginFailed"],
          "description": "Outcome tag. Only 'Succeed' is success; everything else is a hard error."
        },
        "Items": {
          "type": "array",
          "description": "Protected source per input file. Present iff Type=Succeed.",
          "items": { "$ref": "#/$defs/ProtectItem" }
        },
        "Report": {
          "$ref": "#/$defs/ProtectReport",
          "description": "Audit metadata. Present iff Type=Succeed."
        },
        "Message": { "type": "string", "description": "Human-readable failure message. Present when Type != Succeed." },
        "ErrorCode": { "type": "string", "description": "Stable failure code for programmatic routing. Present when Type != Succeed." },
        "FileName": { "type": "string", "description": "Offending filename when Type=SourceError." },
        "LineNumber": { "type": ["string", "integer"], "description": "Offending line when Type=SourceError." },
        "ExceptionToString": { "type": "string", "deprecated": true, "description": "Local-development diagnostic only. Remote production failures omit this field and provide an opaque support reference in Message." }
      }
    },

    "ProtectReport": {
      "type": "object",
      "description": "Audit-friendly metadata for a successful protection run.",
      "additionalProperties": true,
      "properties": {
        "BuildId": {
          "type": "string",
          "description": "Stable identifier for this protection run. Inject as a global into your runtime so production crash reports carry the matching BuildId."
        },
        "PolymorphismFingerprint": {
          "type": "string",
          "description": "Short SHA-256-derived fingerprint over the protected output. Two consecutive obfuscations of identical input MUST produce different fingerprints when polymorphism is engaged."
        },
        "EnabledOptions": {
          "type": "array",
          "items": { "type": "string" },
          "description": "List of API option names that the server actually applied."
        },
        "GlobalIdentifierMap": {
          "type": "array",
          "description": "Mangled-to-original mapping for renamed global identifiers. Persist alongside the protected dist; feed to jso-symbolicate when a production crash arrives.",
          "items": { "$ref": "#/$defs/IdentifierMapEntry" }
        },
        "MemberIdentifierMap": {
          "type": "array",
          "description": "Mangled-to-original mapping for renamed object members.",
          "items": { "$ref": "#/$defs/IdentifierMapEntry" }
        },
        "InputBytes": { "type": "integer", "minimum": 0 },
        "OutputBytes": { "type": "integer", "minimum": 0 },
        "InputFiles":  { "type": "integer", "minimum": 0 },
        "OutputFiles": { "type": "integer", "minimum": 0 },
        "InputLines":  { "type": "integer", "minimum": 0 },
        "OutputLines": { "type": "integer", "minimum": 0 },
        "GeneratedUtc": { "type": "string", "format": "date-time" }
      }
    },

    "IdentifierMapEntry": {
      "type": "object",
      "required": ["Mangled", "Original"],
      "additionalProperties": false,
      "properties": {
        "Mangled":  { "type": "string", "description": "Mangled identifier as it appears in the protected source." },
        "Original": { "type": "string", "description": "Original identifier name from the input source." }
      }
    }
  },

  "oneOf": [
    { "$ref": "#/$defs/ProtectRequest" },
    { "$ref": "#/$defs/ProtectResponse" }
  ]
}
