{
  "$id": "https://hatang.dev/schema/chat-protocol/v1/visitor-frames.json",
  "title": "Ha Tang chat protocol v1: visitor → server frames",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "auth"
        },
        "id": {
          "type": "string"
        },
        "v": {
          "type": "number"
        },
        "d": {
          "type": "object",
          "properties": {
            "token": {
              "type": "string",
              "maxLength": 2048
            },
            "site_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "page": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "maxLength": 2048
                },
                "title": {
                  "type": "string",
                  "maxLength": 300
                },
                "referrer": {
                  "type": "string",
                  "maxLength": 2048
                }
              },
              "required": [
                "url"
              ]
            },
            "screen": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "params": {
                  "type": "object",
                  "propertyNames": {
                    "type": "string",
                    "maxLength": 60
                  },
                  "additionalProperties": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              },
              "required": [
                "name"
              ]
            },
            "app": {
              "type": "object",
              "properties": {
                "install_id": {
                  "type": "string",
                  "minLength": 8,
                  "maxLength": 128
                },
                "version": {
                  "type": "string",
                  "maxLength": 40
                },
                "sdk": {
                  "type": "string",
                  "maxLength": 60
                },
                "os": {
                  "type": "string",
                  "maxLength": 20
                },
                "os_version": {
                  "type": "string",
                  "maxLength": 40
                },
                "device_model": {
                  "type": "string",
                  "maxLength": 80
                },
                "locale": {
                  "type": "string",
                  "maxLength": 10
                }
              },
              "required": [
                "install_id"
              ]
            },
            "client": {
              "type": "object",
              "properties": {
                "sdk": {
                  "type": "string",
                  "maxLength": 40
                },
                "version": {
                  "type": "string",
                  "maxLength": 40
                }
              },
              "required": [
                "sdk",
                "version"
              ]
            },
            "locale": {
              "type": "string",
              "maxLength": 10
            },
            "app_state": {
              "type": "object",
              "properties": {
                "foreground": {
                  "type": "boolean"
                }
              },
              "required": [
                "foreground"
              ]
            }
          },
          "required": [
            "token",
            "site_id"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "page"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "url": {
              "type": "string",
              "maxLength": 2048
            },
            "title": {
              "type": "string",
              "maxLength": 300
            },
            "referrer": {
              "type": "string",
              "maxLength": 2048
            }
          },
          "required": [
            "url"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "screen"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "params": {
              "type": "object",
              "propertyNames": {
                "type": "string",
                "maxLength": 60
              },
              "additionalProperties": {
                "type": "string",
                "maxLength": 500
              }
            }
          },
          "required": [
            "name"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "app.state"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "foreground": {
              "type": "boolean"
            },
            "conversation_id": {
              "anyOf": [
                {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 64
                },
                {
                  "type": "null"
                }
              ]
            }
          },
          "required": [
            "foreground"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "message.send"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "conversation_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "client_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "content": {
              "type": "string",
              "maxLength": 4000
            },
            "attachments": {
              "maxItems": 5,
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              }
            }
          },
          "required": [
            "client_id",
            "content"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "typing"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "conversation_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "on": {
              "type": "boolean"
            }
          },
          "required": [
            "conversation_id",
            "on"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "read"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "conversation_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "up_to_seq": {
              "type": "integer",
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          "required": [
            "conversation_id",
            "up_to_seq"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "identify"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "user_id": {
              "type": "string",
              "maxLength": 200
            },
            "email": {
              "type": "string",
              "maxLength": 320,
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            },
            "name": {
              "type": "string",
              "maxLength": 200
            },
            "phone": {
              "type": "string",
              "maxLength": 40
            },
            "hash": {
              "type": "string",
              "maxLength": 128
            },
            "data": {
              "type": "object",
              "propertyNames": {
                "type": "string"
              },
              "additionalProperties": {}
            }
          }
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "event"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "maxLength": 100
            },
            "data": {
              "type": "object",
              "propertyNames": {
                "type": "string"
              },
              "additionalProperties": {}
            }
          },
          "required": [
            "name"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "resume"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "conversation_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "after_seq": {
              "type": "integer",
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          "required": [
            "conversation_id",
            "after_seq"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "rate"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "conversation_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "score": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5
            },
            "comment": {
              "type": "string",
              "maxLength": 1000
            }
          },
          "required": [
            "conversation_id",
            "score"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "campaign"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "object",
          "properties": {
            "campaign_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            "action": {
              "type": "string",
              "enum": [
                "shown",
                "clicked",
                "open",
                "submit"
              ]
            },
            "button": {
              "type": "string",
              "maxLength": 40
            },
            "fields": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "maxLength": 200
                },
                "phone": {
                  "type": "string",
                  "maxLength": 40
                },
                "email": {
                  "type": "string",
                  "maxLength": 320,
                  "format": "email",
                  "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                }
              }
            }
          },
          "required": [
            "campaign_id",
            "action"
          ]
        }
      },
      "required": [
        "t",
        "d"
      ]
    },
    {
      "type": "object",
      "properties": {
        "t": {
          "type": "string",
          "const": "ping"
        },
        "id": {
          "type": "string"
        },
        "d": {
          "type": "null"
        }
      },
      "required": [
        "t"
      ]
    }
  ]
}
