// Generated by ext/tools/gen_model from ext/metadata/model.json.
// DO NOT EDIT. Run `just gen` to regenerate; CI fails when this drifts.
//
// One struct per Slack entity, each with the `extra` that holds every field
// this version does not model. Parsing is total in the sense @jsonx
// describes: a field of an unexpected type is never taken, so it stays in
// `extra` and comes back out of `to_json` unchanged. `ext/test/modelcorpus`
// holds that property against every occurrence in the reference corpus.
//
// Which fields exist here, and at which type, is a fact about
// ext/fixtures/java -- not a reading of Slack's documentation. Each struct
// says where in the corpus it was observed.

///|
/// A member of a workspace: `users.info`, `users.list`, `users.lookupByEmail`.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.user, $.self, $.users[], $.members[], $.rejected_users[],
/// $.*.inviting_user, $.*.accepting_user
pub(all) struct User {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  color : String?
  created : Int64?
  date_created : Int64?
  deleted : Bool?
  email : String?
  enterprise_id : String?
  enterprise_name : String?
  error : String?
  expiration_ts : Int64?
  first_login : Int64?
  full_name : String?
  has_2fa : Bool?
  has_sso : Bool?
  image_192 : String?
  image_24 : String?
  image_32 : String?
  image_48 : String?
  image_512 : String?
  image_72 : String?
  is_active : Bool?
  is_admin : Bool?
  is_app_user : Bool?
  is_bot : Bool?
  is_connector_bot : Bool?
  is_email_confirmed : Bool?
  is_invited_user : Bool?
  is_owner : Bool?
  is_primary_owner : Bool?
  is_restricted : Bool?
  is_stranger : Bool?
  is_ultra_restricted : Bool?
  is_workflow_bot : Bool?
  last_active_ts : Int64?
  locale : String?
  manual_presence : String?
  name : String?
  presence : String?
  profile : Profile?
  real_name : String?
  roles : Array[String]?
  team_id : String?
  teams : Array[String]?
  two_factor_type : String?
  tz : String?
  tz_label : String?
  tz_offset : Int?
  updated : Int64?
  username : String?
  who_can_share_contact_card : String?
  workspaces : Array[String]?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn User::from_json(json : Json) -> User? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let color = @jsonx.take_str(rest, "color")
  let created = @jsonx.take_int64(rest, "created")
  let date_created = @jsonx.take_int64(rest, "date_created")
  let deleted = @jsonx.take_bool(rest, "deleted")
  let email = @jsonx.take_str(rest, "email")
  let enterprise_id = @jsonx.take_str(rest, "enterprise_id")
  let enterprise_name = @jsonx.take_str(rest, "enterprise_name")
  let error = @jsonx.take_str(rest, "error")
  let expiration_ts = @jsonx.take_int64(rest, "expiration_ts")
  let first_login = @jsonx.take_int64(rest, "first_login")
  let full_name = @jsonx.take_str(rest, "full_name")
  let has_2fa = @jsonx.take_bool(rest, "has_2fa")
  let has_sso = @jsonx.take_bool(rest, "has_sso")
  let image_192 = @jsonx.take_str(rest, "image_192")
  let image_24 = @jsonx.take_str(rest, "image_24")
  let image_32 = @jsonx.take_str(rest, "image_32")
  let image_48 = @jsonx.take_str(rest, "image_48")
  let image_512 = @jsonx.take_str(rest, "image_512")
  let image_72 = @jsonx.take_str(rest, "image_72")
  let is_active = @jsonx.take_bool(rest, "is_active")
  let is_admin = @jsonx.take_bool(rest, "is_admin")
  let is_app_user = @jsonx.take_bool(rest, "is_app_user")
  let is_bot = @jsonx.take_bool(rest, "is_bot")
  let is_connector_bot = @jsonx.take_bool(rest, "is_connector_bot")
  let is_email_confirmed = @jsonx.take_bool(rest, "is_email_confirmed")
  let is_invited_user = @jsonx.take_bool(rest, "is_invited_user")
  let is_owner = @jsonx.take_bool(rest, "is_owner")
  let is_primary_owner = @jsonx.take_bool(rest, "is_primary_owner")
  let is_restricted = @jsonx.take_bool(rest, "is_restricted")
  let is_stranger = @jsonx.take_bool(rest, "is_stranger")
  let is_ultra_restricted = @jsonx.take_bool(rest, "is_ultra_restricted")
  let is_workflow_bot = @jsonx.take_bool(rest, "is_workflow_bot")
  let last_active_ts = @jsonx.take_int64(rest, "last_active_ts")
  let locale = @jsonx.take_str(rest, "locale")
  let manual_presence = @jsonx.take_str(rest, "manual_presence")
  let name = @jsonx.take_str(rest, "name")
  let presence = @jsonx.take_str(rest, "presence")
  let profile = @jsonx.take_obj(rest, "profile", Profile::from_json)
  let real_name = @jsonx.take_str(rest, "real_name")
  let roles = @jsonx.take_str_arr(rest, "roles")
  let team_id = @jsonx.take_str(rest, "team_id")
  let teams = @jsonx.take_str_arr(rest, "teams")
  let two_factor_type = @jsonx.take_str(rest, "two_factor_type")
  let tz = @jsonx.take_str(rest, "tz")
  let tz_label = @jsonx.take_str(rest, "tz_label")
  let tz_offset = @jsonx.take_int(rest, "tz_offset")
  let updated = @jsonx.take_int64(rest, "updated")
  let username = @jsonx.take_str(rest, "username")
  let who_can_share_contact_card = @jsonx.take_str(
    rest, "who_can_share_contact_card",
  )
  let workspaces = @jsonx.take_str_arr(rest, "workspaces")
  Some({
    id,
    color,
    created,
    date_created,
    deleted,
    email,
    enterprise_id,
    enterprise_name,
    error,
    expiration_ts,
    first_login,
    full_name,
    has_2fa,
    has_sso,
    image_192,
    image_24,
    image_32,
    image_48,
    image_512,
    image_72,
    is_active,
    is_admin,
    is_app_user,
    is_bot,
    is_connector_bot,
    is_email_confirmed,
    is_invited_user,
    is_owner,
    is_primary_owner,
    is_restricted,
    is_stranger,
    is_ultra_restricted,
    is_workflow_bot,
    last_active_ts,
    locale,
    manual_presence,
    name,
    presence,
    profile,
    real_name,
    roles,
    team_id,
    teams,
    two_factor_type,
    tz,
    tz_label,
    tz_offset,
    updated,
    username,
    who_can_share_contact_card,
    workspaces,
    extra: rest,
  })
}

///|
pub fn User::to_json(self : User) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_str(o, "color", self.color)
  @jsonx.put_int64(o, "created", self.created)
  @jsonx.put_int64(o, "date_created", self.date_created)
  @jsonx.put_bool(o, "deleted", self.deleted)
  @jsonx.put_str(o, "email", self.email)
  @jsonx.put_str(o, "enterprise_id", self.enterprise_id)
  @jsonx.put_str(o, "enterprise_name", self.enterprise_name)
  @jsonx.put_str(o, "error", self.error)
  @jsonx.put_int64(o, "expiration_ts", self.expiration_ts)
  @jsonx.put_int64(o, "first_login", self.first_login)
  @jsonx.put_str(o, "full_name", self.full_name)
  @jsonx.put_bool(o, "has_2fa", self.has_2fa)
  @jsonx.put_bool(o, "has_sso", self.has_sso)
  @jsonx.put_str(o, "image_192", self.image_192)
  @jsonx.put_str(o, "image_24", self.image_24)
  @jsonx.put_str(o, "image_32", self.image_32)
  @jsonx.put_str(o, "image_48", self.image_48)
  @jsonx.put_str(o, "image_512", self.image_512)
  @jsonx.put_str(o, "image_72", self.image_72)
  @jsonx.put_bool(o, "is_active", self.is_active)
  @jsonx.put_bool(o, "is_admin", self.is_admin)
  @jsonx.put_bool(o, "is_app_user", self.is_app_user)
  @jsonx.put_bool(o, "is_bot", self.is_bot)
  @jsonx.put_bool(o, "is_connector_bot", self.is_connector_bot)
  @jsonx.put_bool(o, "is_email_confirmed", self.is_email_confirmed)
  @jsonx.put_bool(o, "is_invited_user", self.is_invited_user)
  @jsonx.put_bool(o, "is_owner", self.is_owner)
  @jsonx.put_bool(o, "is_primary_owner", self.is_primary_owner)
  @jsonx.put_bool(o, "is_restricted", self.is_restricted)
  @jsonx.put_bool(o, "is_stranger", self.is_stranger)
  @jsonx.put_bool(o, "is_ultra_restricted", self.is_ultra_restricted)
  @jsonx.put_bool(o, "is_workflow_bot", self.is_workflow_bot)
  @jsonx.put_int64(o, "last_active_ts", self.last_active_ts)
  @jsonx.put_str(o, "locale", self.locale)
  @jsonx.put_str(o, "manual_presence", self.manual_presence)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_str(o, "presence", self.presence)
  @jsonx.put_obj(o, "profile", self.profile, Profile::to_json)
  @jsonx.put_str(o, "real_name", self.real_name)
  @jsonx.put_str_arr(o, "roles", self.roles)
  @jsonx.put_str(o, "team_id", self.team_id)
  @jsonx.put_str_arr(o, "teams", self.teams)
  @jsonx.put_str(o, "two_factor_type", self.two_factor_type)
  @jsonx.put_str(o, "tz", self.tz)
  @jsonx.put_str(o, "tz_label", self.tz_label)
  @jsonx.put_int(o, "tz_offset", self.tz_offset)
  @jsonx.put_int64(o, "updated", self.updated)
  @jsonx.put_str(o, "username", self.username)
  @jsonx.put_str(
    o,
    "who_can_share_contact_card",
    self.who_can_share_contact_card,
  )
  @jsonx.put_str_arr(o, "workspaces", self.workspaces)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A user's profile. Separate because Slack sends it separately -- `users.profile.get` returns one on its own.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.profile, $.*.profile, $.*.*.profile
pub(all) struct Profile {
  always_active : Bool?
  api_app_id : String?
  avatar_hash : String?
  bot_id : String?
  display_name : String?
  display_name_normalized : String?
  email : String?
  first_name : String?
  guest_invited_by : String?
  huddle_state : String?
  huddle_state_expiration_ts : Int64?
  image_1024 : String?
  image_192 : String?
  image_24 : String?
  image_32 : String?
  image_48 : String?
  image_512 : String?
  image_72 : String?
  image_original : String?
  is_custom_image : Bool?
  last_name : String?
  phone : String?
  pronouns : String?
  real_name : String?
  real_name_normalized : String?
  skype : String?
  start_date : String?
  status_clear_on_focus_end : Bool?
  status_emoji : String?
  status_emoji_url : String?
  status_expiration : Int64?
  status_text : String?
  status_text_canonical : String?
  team : String?
  title : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object.
pub fn Profile::from_json(json : Json) -> Profile? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  let always_active = @jsonx.take_bool(rest, "always_active")
  let api_app_id = @jsonx.take_str(rest, "api_app_id")
  let avatar_hash = @jsonx.take_str(rest, "avatar_hash")
  let bot_id = @jsonx.take_str(rest, "bot_id")
  let display_name = @jsonx.take_str(rest, "display_name")
  let display_name_normalized = @jsonx.take_str(rest, "display_name_normalized")
  let email = @jsonx.take_str(rest, "email")
  let first_name = @jsonx.take_str(rest, "first_name")
  let guest_invited_by = @jsonx.take_str(rest, "guest_invited_by")
  let huddle_state = @jsonx.take_str(rest, "huddle_state")
  let huddle_state_expiration_ts = @jsonx.take_int64(
    rest, "huddle_state_expiration_ts",
  )
  let image_1024 = @jsonx.take_str(rest, "image_1024")
  let image_192 = @jsonx.take_str(rest, "image_192")
  let image_24 = @jsonx.take_str(rest, "image_24")
  let image_32 = @jsonx.take_str(rest, "image_32")
  let image_48 = @jsonx.take_str(rest, "image_48")
  let image_512 = @jsonx.take_str(rest, "image_512")
  let image_72 = @jsonx.take_str(rest, "image_72")
  let image_original = @jsonx.take_str(rest, "image_original")
  let is_custom_image = @jsonx.take_bool(rest, "is_custom_image")
  let last_name = @jsonx.take_str(rest, "last_name")
  let phone = @jsonx.take_str(rest, "phone")
  let pronouns = @jsonx.take_str(rest, "pronouns")
  let real_name = @jsonx.take_str(rest, "real_name")
  let real_name_normalized = @jsonx.take_str(rest, "real_name_normalized")
  let skype = @jsonx.take_str(rest, "skype")
  let start_date = @jsonx.take_str(rest, "start_date")
  let status_clear_on_focus_end = @jsonx.take_bool(
    rest, "status_clear_on_focus_end",
  )
  let status_emoji = @jsonx.take_str(rest, "status_emoji")
  let status_emoji_url = @jsonx.take_str(rest, "status_emoji_url")
  let status_expiration = @jsonx.take_int64(rest, "status_expiration")
  let status_text = @jsonx.take_str(rest, "status_text")
  let status_text_canonical = @jsonx.take_str(rest, "status_text_canonical")
  let team = @jsonx.take_str(rest, "team")
  let title = @jsonx.take_str(rest, "title")
  Some({
    always_active,
    api_app_id,
    avatar_hash,
    bot_id,
    display_name,
    display_name_normalized,
    email,
    first_name,
    guest_invited_by,
    huddle_state,
    huddle_state_expiration_ts,
    image_1024,
    image_192,
    image_24,
    image_32,
    image_48,
    image_512,
    image_72,
    image_original,
    is_custom_image,
    last_name,
    phone,
    pronouns,
    real_name,
    real_name_normalized,
    skype,
    start_date,
    status_clear_on_focus_end,
    status_emoji,
    status_emoji_url,
    status_expiration,
    status_text,
    status_text_canonical,
    team,
    title,
    extra: rest,
  })
}

///|
pub fn Profile::to_json(self : Profile) -> Json {
  let o : Map[String, Json] = Map([])
  @jsonx.put_bool(o, "always_active", self.always_active)
  @jsonx.put_str(o, "api_app_id", self.api_app_id)
  @jsonx.put_str(o, "avatar_hash", self.avatar_hash)
  @jsonx.put_str(o, "bot_id", self.bot_id)
  @jsonx.put_str(o, "display_name", self.display_name)
  @jsonx.put_str(o, "display_name_normalized", self.display_name_normalized)
  @jsonx.put_str(o, "email", self.email)
  @jsonx.put_str(o, "first_name", self.first_name)
  @jsonx.put_str(o, "guest_invited_by", self.guest_invited_by)
  @jsonx.put_str(o, "huddle_state", self.huddle_state)
  @jsonx.put_int64(
    o,
    "huddle_state_expiration_ts",
    self.huddle_state_expiration_ts,
  )
  @jsonx.put_str(o, "image_1024", self.image_1024)
  @jsonx.put_str(o, "image_192", self.image_192)
  @jsonx.put_str(o, "image_24", self.image_24)
  @jsonx.put_str(o, "image_32", self.image_32)
  @jsonx.put_str(o, "image_48", self.image_48)
  @jsonx.put_str(o, "image_512", self.image_512)
  @jsonx.put_str(o, "image_72", self.image_72)
  @jsonx.put_str(o, "image_original", self.image_original)
  @jsonx.put_bool(o, "is_custom_image", self.is_custom_image)
  @jsonx.put_str(o, "last_name", self.last_name)
  @jsonx.put_str(o, "phone", self.phone)
  @jsonx.put_str(o, "pronouns", self.pronouns)
  @jsonx.put_str(o, "real_name", self.real_name)
  @jsonx.put_str(o, "real_name_normalized", self.real_name_normalized)
  @jsonx.put_str(o, "skype", self.skype)
  @jsonx.put_str(o, "start_date", self.start_date)
  @jsonx.put_bool(
    o,
    "status_clear_on_focus_end",
    self.status_clear_on_focus_end,
  )
  @jsonx.put_str(o, "status_emoji", self.status_emoji)
  @jsonx.put_str(o, "status_emoji_url", self.status_emoji_url)
  @jsonx.put_int64(o, "status_expiration", self.status_expiration)
  @jsonx.put_str(o, "status_text", self.status_text)
  @jsonx.put_str(o, "status_text_canonical", self.status_text_canonical)
  @jsonx.put_str(o, "team", self.team)
  @jsonx.put_str(o, "title", self.title)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A conversation: public or private channel, DM or MPIM. Slack calls all four a channel here.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.channel, $.channels[], $.group, $.groups[], $.ims[],
/// $.conversations[]
pub(all) struct Channel {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  channel_manager_count : Int?
  connected_limited_team_ids : Array[String]?
  connected_team_ids : Array[String]?
  context_team_id : String?
  conversation_host_id : String?
  created : Int64?
  creator : String?
  creator_id : String?
  date_connected : Int64?
  enterprise_id : String?
  external_user_count : Int?
  has_pins : Bool?
  internal_team_ids : Array[String]?
  internal_team_ids_count : Int?
  internal_team_ids_sample_team : String?
  is_archived : Bool?
  is_channel : Bool?
  is_disconnect_in_progress : Bool?
  is_ext_shared : Bool?
  is_frozen : Bool?
  is_general : Bool?
  is_global_shared : Bool?
  is_group : Bool?
  is_im : Bool?
  is_member : Bool?
  is_moved : Int?
  is_mpim : Bool?
  is_non_threadable : Bool?
  is_open : Bool?
  is_org_default : Bool?
  is_org_mandatory : Bool?
  is_org_shared : Bool?
  is_pending_ext_shared : Bool?
  is_private : Bool?
  is_read_only : Bool?
  is_shared : Bool?
  is_starred : Bool?
  is_thread_only : Bool?
  is_user_deleted : Bool?
  last_activity_ts : Int64?
  last_read : String?
  latest : Message?
  locale : String?
  member_count : Int?
  members : Array[String]?
  name : String?
  name_normalized : String?
  num_members : Int?
  parent_conversation : String?
  parent_group : String?
  pending_connected_team_ids : Array[String]?
  pending_shared : Array[String]?
  previous_names : Array[String]?
  priority : Int?
  shared_team_ids : Array[String]?
  topic : ChannelText?
  unlinked : Int?
  unread_count : Int?
  unread_count_display : Int?
  updated : Int64?
  user : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn Channel::from_json(json : Json) -> Channel? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let channel_manager_count = @jsonx.take_int(rest, "channel_manager_count")
  let connected_limited_team_ids = @jsonx.take_str_arr(
    rest, "connected_limited_team_ids",
  )
  let connected_team_ids = @jsonx.take_str_arr(rest, "connected_team_ids")
  let context_team_id = @jsonx.take_str(rest, "context_team_id")
  let conversation_host_id = @jsonx.take_str(rest, "conversation_host_id")
  let created = @jsonx.take_int64(rest, "created")
  let creator = @jsonx.take_str(rest, "creator")
  let creator_id = @jsonx.take_str(rest, "creator_id")
  let date_connected = @jsonx.take_int64(rest, "date_connected")
  let enterprise_id = @jsonx.take_str(rest, "enterprise_id")
  let external_user_count = @jsonx.take_int(rest, "external_user_count")
  let has_pins = @jsonx.take_bool(rest, "has_pins")
  let internal_team_ids = @jsonx.take_str_arr(rest, "internal_team_ids")
  let internal_team_ids_count = @jsonx.take_int(rest, "internal_team_ids_count")
  let internal_team_ids_sample_team = @jsonx.take_str(
    rest, "internal_team_ids_sample_team",
  )
  let is_archived = @jsonx.take_bool(rest, "is_archived")
  let is_channel = @jsonx.take_bool(rest, "is_channel")
  let is_disconnect_in_progress = @jsonx.take_bool(
    rest, "is_disconnect_in_progress",
  )
  let is_ext_shared = @jsonx.take_bool(rest, "is_ext_shared")
  let is_frozen = @jsonx.take_bool(rest, "is_frozen")
  let is_general = @jsonx.take_bool(rest, "is_general")
  let is_global_shared = @jsonx.take_bool(rest, "is_global_shared")
  let is_group = @jsonx.take_bool(rest, "is_group")
  let is_im = @jsonx.take_bool(rest, "is_im")
  let is_member = @jsonx.take_bool(rest, "is_member")
  let is_moved = @jsonx.take_int(rest, "is_moved")
  let is_mpim = @jsonx.take_bool(rest, "is_mpim")
  let is_non_threadable = @jsonx.take_bool(rest, "is_non_threadable")
  let is_open = @jsonx.take_bool(rest, "is_open")
  let is_org_default = @jsonx.take_bool(rest, "is_org_default")
  let is_org_mandatory = @jsonx.take_bool(rest, "is_org_mandatory")
  let is_org_shared = @jsonx.take_bool(rest, "is_org_shared")
  let is_pending_ext_shared = @jsonx.take_bool(rest, "is_pending_ext_shared")
  let is_private = @jsonx.take_bool(rest, "is_private")
  let is_read_only = @jsonx.take_bool(rest, "is_read_only")
  let is_shared = @jsonx.take_bool(rest, "is_shared")
  let is_starred = @jsonx.take_bool(rest, "is_starred")
  let is_thread_only = @jsonx.take_bool(rest, "is_thread_only")
  let is_user_deleted = @jsonx.take_bool(rest, "is_user_deleted")
  let last_activity_ts = @jsonx.take_int64(rest, "last_activity_ts")
  let last_read = @jsonx.take_str(rest, "last_read")
  let latest = @jsonx.take_obj(rest, "latest", Message::from_json)
  let locale = @jsonx.take_str(rest, "locale")
  let member_count = @jsonx.take_int(rest, "member_count")
  let members = @jsonx.take_str_arr(rest, "members")
  let name = @jsonx.take_str(rest, "name")
  let name_normalized = @jsonx.take_str(rest, "name_normalized")
  let num_members = @jsonx.take_int(rest, "num_members")
  let parent_conversation = @jsonx.take_str(rest, "parent_conversation")
  let parent_group = @jsonx.take_str(rest, "parent_group")
  let pending_connected_team_ids = @jsonx.take_str_arr(
    rest, "pending_connected_team_ids",
  )
  let pending_shared = @jsonx.take_str_arr(rest, "pending_shared")
  let previous_names = @jsonx.take_str_arr(rest, "previous_names")
  let priority = @jsonx.take_int(rest, "priority")
  let shared_team_ids = @jsonx.take_str_arr(rest, "shared_team_ids")
  let topic = @jsonx.take_obj(rest, "topic", ChannelText::from_json)
  let unlinked = @jsonx.take_int(rest, "unlinked")
  let unread_count = @jsonx.take_int(rest, "unread_count")
  let unread_count_display = @jsonx.take_int(rest, "unread_count_display")
  let updated = @jsonx.take_int64(rest, "updated")
  let user = @jsonx.take_str(rest, "user")
  Some({
    id,
    channel_manager_count,
    connected_limited_team_ids,
    connected_team_ids,
    context_team_id,
    conversation_host_id,
    created,
    creator,
    creator_id,
    date_connected,
    enterprise_id,
    external_user_count,
    has_pins,
    internal_team_ids,
    internal_team_ids_count,
    internal_team_ids_sample_team,
    is_archived,
    is_channel,
    is_disconnect_in_progress,
    is_ext_shared,
    is_frozen,
    is_general,
    is_global_shared,
    is_group,
    is_im,
    is_member,
    is_moved,
    is_mpim,
    is_non_threadable,
    is_open,
    is_org_default,
    is_org_mandatory,
    is_org_shared,
    is_pending_ext_shared,
    is_private,
    is_read_only,
    is_shared,
    is_starred,
    is_thread_only,
    is_user_deleted,
    last_activity_ts,
    last_read,
    latest,
    locale,
    member_count,
    members,
    name,
    name_normalized,
    num_members,
    parent_conversation,
    parent_group,
    pending_connected_team_ids,
    pending_shared,
    previous_names,
    priority,
    shared_team_ids,
    topic,
    unlinked,
    unread_count,
    unread_count_display,
    updated,
    user,
    extra: rest,
  })
}

///|
pub fn Channel::to_json(self : Channel) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_int(o, "channel_manager_count", self.channel_manager_count)
  @jsonx.put_str_arr(
    o,
    "connected_limited_team_ids",
    self.connected_limited_team_ids,
  )
  @jsonx.put_str_arr(o, "connected_team_ids", self.connected_team_ids)
  @jsonx.put_str(o, "context_team_id", self.context_team_id)
  @jsonx.put_str(o, "conversation_host_id", self.conversation_host_id)
  @jsonx.put_int64(o, "created", self.created)
  @jsonx.put_str(o, "creator", self.creator)
  @jsonx.put_str(o, "creator_id", self.creator_id)
  @jsonx.put_int64(o, "date_connected", self.date_connected)
  @jsonx.put_str(o, "enterprise_id", self.enterprise_id)
  @jsonx.put_int(o, "external_user_count", self.external_user_count)
  @jsonx.put_bool(o, "has_pins", self.has_pins)
  @jsonx.put_str_arr(o, "internal_team_ids", self.internal_team_ids)
  @jsonx.put_int(o, "internal_team_ids_count", self.internal_team_ids_count)
  @jsonx.put_str(
    o,
    "internal_team_ids_sample_team",
    self.internal_team_ids_sample_team,
  )
  @jsonx.put_bool(o, "is_archived", self.is_archived)
  @jsonx.put_bool(o, "is_channel", self.is_channel)
  @jsonx.put_bool(
    o,
    "is_disconnect_in_progress",
    self.is_disconnect_in_progress,
  )
  @jsonx.put_bool(o, "is_ext_shared", self.is_ext_shared)
  @jsonx.put_bool(o, "is_frozen", self.is_frozen)
  @jsonx.put_bool(o, "is_general", self.is_general)
  @jsonx.put_bool(o, "is_global_shared", self.is_global_shared)
  @jsonx.put_bool(o, "is_group", self.is_group)
  @jsonx.put_bool(o, "is_im", self.is_im)
  @jsonx.put_bool(o, "is_member", self.is_member)
  @jsonx.put_int(o, "is_moved", self.is_moved)
  @jsonx.put_bool(o, "is_mpim", self.is_mpim)
  @jsonx.put_bool(o, "is_non_threadable", self.is_non_threadable)
  @jsonx.put_bool(o, "is_open", self.is_open)
  @jsonx.put_bool(o, "is_org_default", self.is_org_default)
  @jsonx.put_bool(o, "is_org_mandatory", self.is_org_mandatory)
  @jsonx.put_bool(o, "is_org_shared", self.is_org_shared)
  @jsonx.put_bool(o, "is_pending_ext_shared", self.is_pending_ext_shared)
  @jsonx.put_bool(o, "is_private", self.is_private)
  @jsonx.put_bool(o, "is_read_only", self.is_read_only)
  @jsonx.put_bool(o, "is_shared", self.is_shared)
  @jsonx.put_bool(o, "is_starred", self.is_starred)
  @jsonx.put_bool(o, "is_thread_only", self.is_thread_only)
  @jsonx.put_bool(o, "is_user_deleted", self.is_user_deleted)
  @jsonx.put_int64(o, "last_activity_ts", self.last_activity_ts)
  @jsonx.put_str(o, "last_read", self.last_read)
  @jsonx.put_obj(o, "latest", self.latest, Message::to_json)
  @jsonx.put_str(o, "locale", self.locale)
  @jsonx.put_int(o, "member_count", self.member_count)
  @jsonx.put_str_arr(o, "members", self.members)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_str(o, "name_normalized", self.name_normalized)
  @jsonx.put_int(o, "num_members", self.num_members)
  @jsonx.put_str(o, "parent_conversation", self.parent_conversation)
  @jsonx.put_str(o, "parent_group", self.parent_group)
  @jsonx.put_str_arr(
    o,
    "pending_connected_team_ids",
    self.pending_connected_team_ids,
  )
  @jsonx.put_str_arr(o, "pending_shared", self.pending_shared)
  @jsonx.put_str_arr(o, "previous_names", self.previous_names)
  @jsonx.put_int(o, "priority", self.priority)
  @jsonx.put_str_arr(o, "shared_team_ids", self.shared_team_ids)
  @jsonx.put_obj(o, "topic", self.topic, ChannelText::to_json)
  @jsonx.put_int(o, "unlinked", self.unlinked)
  @jsonx.put_int(o, "unread_count", self.unread_count)
  @jsonx.put_int(o, "unread_count_display", self.unread_count_display)
  @jsonx.put_int64(o, "updated", self.updated)
  @jsonx.put_str(o, "user", self.user)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A channel's topic or purpose. The same three fields for both.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.*.purpose, $.*.topic, $.*.*.purpose, $.*.*.topic
pub(all) struct ChannelText {
  creator : String?
  last_set : Int64?
  value : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object.
pub fn ChannelText::from_json(json : Json) -> ChannelText? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  let creator = @jsonx.take_str(rest, "creator")
  let last_set = @jsonx.take_int64(rest, "last_set")
  let value = @jsonx.take_str(rest, "value")
  Some({ creator, last_set, value, extra: rest })
}

///|
pub fn ChannelText::to_json(self : ChannelText) -> Json {
  let o : Map[String, Json] = Map([])
  @jsonx.put_str(o, "creator", self.creator)
  @jsonx.put_int64(o, "last_set", self.last_set)
  @jsonx.put_str(o, "value", self.value)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A message, as `conversations.history`, `conversations.replies` and `chat.postMessage` return one.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.message, $.messages[], $.channel.latest, $.group.latest,
/// $.messages[].root, $.items[].message, $.messages.matches[]
pub(all) struct Message {
  app_id : String?
  blocks : Array[@blocks.LayoutBlock]?
  bot_id : String?
  bot_profile : BotProfile?
  client_msg_id : String?
  display_as_bot : Bool?
  edited : Edited?
  files : Array[File]?
  iid : String?
  inviter : String?
  is_locked : Bool?
  is_mpim : Bool?
  is_starred : Bool?
  last_read : String?
  latest_reply : String?
  no_notifications : Bool?
  no_reactions : Bool?
  parent_user_id : String?
  permalink : String?
  purpose : String?
  reactions : Array[Reaction]?
  reply_count : Int?
  reply_users : Array[String]?
  reply_users_count : Int?
  root : Message?
  score : Int?
  subscribed : Bool?
  subtype : String?
  team : String?
  text : String?
  thread_ts : String?
  topic : String?
  ts : String?
  type_ : String?
  upload : Bool?
  user : String?
  username : String?
  x_files : Array[String]?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object.
pub fn Message::from_json(json : Json) -> Message? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  let app_id = @jsonx.take_str(rest, "app_id")
  let blocks = take_blocks(rest, "blocks")
  let bot_id = @jsonx.take_str(rest, "bot_id")
  let bot_profile = @jsonx.take_obj(rest, "bot_profile", BotProfile::from_json)
  let client_msg_id = @jsonx.take_str(rest, "client_msg_id")
  let display_as_bot = @jsonx.take_bool(rest, "display_as_bot")
  let edited = @jsonx.take_obj(rest, "edited", Edited::from_json)
  let files = @jsonx.take_arr(rest, "files", File::from_json)
  let iid = @jsonx.take_str(rest, "iid")
  let inviter = @jsonx.take_str(rest, "inviter")
  let is_locked = @jsonx.take_bool(rest, "is_locked")
  let is_mpim = @jsonx.take_bool(rest, "is_mpim")
  let is_starred = @jsonx.take_bool(rest, "is_starred")
  let last_read = @jsonx.take_str(rest, "last_read")
  let latest_reply = @jsonx.take_str(rest, "latest_reply")
  let no_notifications = @jsonx.take_bool(rest, "no_notifications")
  let no_reactions = @jsonx.take_bool(rest, "no_reactions")
  let parent_user_id = @jsonx.take_str(rest, "parent_user_id")
  let permalink = @jsonx.take_str(rest, "permalink")
  let purpose = @jsonx.take_str(rest, "purpose")
  let reactions = @jsonx.take_arr(rest, "reactions", Reaction::from_json)
  let reply_count = @jsonx.take_int(rest, "reply_count")
  let reply_users = @jsonx.take_str_arr(rest, "reply_users")
  let reply_users_count = @jsonx.take_int(rest, "reply_users_count")
  let root = @jsonx.take_obj(rest, "root", Message::from_json)
  let score = @jsonx.take_int(rest, "score")
  let subscribed = @jsonx.take_bool(rest, "subscribed")
  let subtype = @jsonx.take_str(rest, "subtype")
  let team = @jsonx.take_str(rest, "team")
  let text = @jsonx.take_str(rest, "text")
  let thread_ts = @jsonx.take_str(rest, "thread_ts")
  let topic = @jsonx.take_str(rest, "topic")
  let ts = @jsonx.take_str(rest, "ts")
  let type_ = @jsonx.take_str(rest, "type")
  let upload = @jsonx.take_bool(rest, "upload")
  let user = @jsonx.take_str(rest, "user")
  let username = @jsonx.take_str(rest, "username")
  let x_files = @jsonx.take_str_arr(rest, "x_files")
  Some({
    app_id,
    blocks,
    bot_id,
    bot_profile,
    client_msg_id,
    display_as_bot,
    edited,
    files,
    iid,
    inviter,
    is_locked,
    is_mpim,
    is_starred,
    last_read,
    latest_reply,
    no_notifications,
    no_reactions,
    parent_user_id,
    permalink,
    purpose,
    reactions,
    reply_count,
    reply_users,
    reply_users_count,
    root,
    score,
    subscribed,
    subtype,
    team,
    text,
    thread_ts,
    topic,
    ts,
    type_,
    upload,
    user,
    username,
    x_files,
    extra: rest,
  })
}

///|
pub fn Message::to_json(self : Message) -> Json {
  let o : Map[String, Json] = Map([])
  @jsonx.put_str(o, "app_id", self.app_id)
  @jsonx.put_obj(o, "blocks", self.blocks, @blocks.blocks_to_json)
  @jsonx.put_str(o, "bot_id", self.bot_id)
  @jsonx.put_obj(o, "bot_profile", self.bot_profile, BotProfile::to_json)
  @jsonx.put_str(o, "client_msg_id", self.client_msg_id)
  @jsonx.put_bool(o, "display_as_bot", self.display_as_bot)
  @jsonx.put_obj(o, "edited", self.edited, Edited::to_json)
  @jsonx.put_arr(o, "files", self.files, File::to_json)
  @jsonx.put_str(o, "iid", self.iid)
  @jsonx.put_str(o, "inviter", self.inviter)
  @jsonx.put_bool(o, "is_locked", self.is_locked)
  @jsonx.put_bool(o, "is_mpim", self.is_mpim)
  @jsonx.put_bool(o, "is_starred", self.is_starred)
  @jsonx.put_str(o, "last_read", self.last_read)
  @jsonx.put_str(o, "latest_reply", self.latest_reply)
  @jsonx.put_bool(o, "no_notifications", self.no_notifications)
  @jsonx.put_bool(o, "no_reactions", self.no_reactions)
  @jsonx.put_str(o, "parent_user_id", self.parent_user_id)
  @jsonx.put_str(o, "permalink", self.permalink)
  @jsonx.put_str(o, "purpose", self.purpose)
  @jsonx.put_arr(o, "reactions", self.reactions, Reaction::to_json)
  @jsonx.put_int(o, "reply_count", self.reply_count)
  @jsonx.put_str_arr(o, "reply_users", self.reply_users)
  @jsonx.put_int(o, "reply_users_count", self.reply_users_count)
  @jsonx.put_obj(o, "root", self.root, Message::to_json)
  @jsonx.put_int(o, "score", self.score)
  @jsonx.put_bool(o, "subscribed", self.subscribed)
  @jsonx.put_str(o, "subtype", self.subtype)
  @jsonx.put_str(o, "team", self.team)
  @jsonx.put_str(o, "text", self.text)
  @jsonx.put_str(o, "thread_ts", self.thread_ts)
  @jsonx.put_str(o, "topic", self.topic)
  @jsonx.put_str(o, "ts", self.ts)
  @jsonx.put_str(o, "type", self.type_)
  @jsonx.put_bool(o, "upload", self.upload)
  @jsonx.put_str(o, "user", self.user)
  @jsonx.put_str(o, "username", self.username)
  @jsonx.put_str_arr(o, "x_files", self.x_files)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// When a message was last edited, and by whom.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.*.edited, $.*.*.edited
pub(all) struct Edited {
  ts : String?
  user : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object.
pub fn Edited::from_json(json : Json) -> Edited? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  let ts = @jsonx.take_str(rest, "ts")
  let user = @jsonx.take_str(rest, "user")
  Some({ ts, user, extra: rest })
}

///|
pub fn Edited::to_json(self : Edited) -> Json {
  let o : Map[String, Json] = Map([])
  @jsonx.put_str(o, "ts", self.ts)
  @jsonx.put_str(o, "user", self.user)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// One emoji on a message, and who added it.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.*.reactions[], $.*.*.reactions[]
pub(all) struct Reaction {
  count : Int?
  name : String?
  url : String?
  users : Array[String]?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object.
pub fn Reaction::from_json(json : Json) -> Reaction? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  let count = @jsonx.take_int(rest, "count")
  let name = @jsonx.take_str(rest, "name")
  let url = @jsonx.take_str(rest, "url")
  let users = @jsonx.take_str_arr(rest, "users")
  Some({ count, name, url, users, extra: rest })
}

///|
pub fn Reaction::to_json(self : Reaction) -> Json {
  let o : Map[String, Json] = Map([])
  @jsonx.put_int(o, "count", self.count)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_str(o, "url", self.url)
  @jsonx.put_str_arr(o, "users", self.users)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// The app behind a bot message.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.bot, $.bots[], $.*.bot_profile, $.*.*.bot_profile
pub(all) struct BotProfile {
  app_id : String?
  bot_access_token : String?
  bot_user_id : String?
  deleted : Bool?
  id : String?
  is_workflow_bot : Bool?
  name : String?
  team_id : String?
  updated : Int64?
  user_id : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object.
pub fn BotProfile::from_json(json : Json) -> BotProfile? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  let app_id = @jsonx.take_str(rest, "app_id")
  let bot_access_token = @jsonx.take_str(rest, "bot_access_token")
  let bot_user_id = @jsonx.take_str(rest, "bot_user_id")
  let deleted = @jsonx.take_bool(rest, "deleted")
  let id = @jsonx.take_str(rest, "id")
  let is_workflow_bot = @jsonx.take_bool(rest, "is_workflow_bot")
  let name = @jsonx.take_str(rest, "name")
  let team_id = @jsonx.take_str(rest, "team_id")
  let updated = @jsonx.take_int64(rest, "updated")
  let user_id = @jsonx.take_str(rest, "user_id")
  Some({
    app_id,
    bot_access_token,
    bot_user_id,
    deleted,
    id,
    is_workflow_bot,
    name,
    team_id,
    updated,
    user_id,
    extra: rest,
  })
}

///|
pub fn BotProfile::to_json(self : BotProfile) -> Json {
  let o : Map[String, Json] = Map([])
  @jsonx.put_str(o, "app_id", self.app_id)
  @jsonx.put_str(o, "bot_access_token", self.bot_access_token)
  @jsonx.put_str(o, "bot_user_id", self.bot_user_id)
  @jsonx.put_bool(o, "deleted", self.deleted)
  @jsonx.put_str(o, "id", self.id)
  @jsonx.put_bool(o, "is_workflow_bot", self.is_workflow_bot)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_str(o, "team_id", self.team_id)
  @jsonx.put_int64(o, "updated", self.updated)
  @jsonx.put_str(o, "user_id", self.user_id)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A workspace.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.team, $.teams[]
pub(all) struct Team {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  avatar_base_url : String?
  date_create : Int64?
  default_channels : Array[String]?
  discoverability : String?
  discoverable : String?
  domain : String?
  email_domain : String?
  enterprise_domain : String?
  enterprise_id : String?
  enterprise_name : String?
  is_sfdc_auto_slack : Bool?
  is_verified : Bool?
  limit_ts : Int64?
  lob_sales_home_enabled : Bool?
  locale : String?
  messages_count : Int?
  msg_edit_window_mins : Int?
  name : String?
  onboarding_channel_id : String?
  over_storage_limit : Bool?
  pay_prod_cur : String?
  plan : String?
  team_url : String?
  url : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn Team::from_json(json : Json) -> Team? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let avatar_base_url = @jsonx.take_str(rest, "avatar_base_url")
  let date_create = @jsonx.take_int64(rest, "date_create")
  let default_channels = @jsonx.take_str_arr(rest, "default_channels")
  let discoverability = @jsonx.take_str(rest, "discoverability")
  let discoverable = @jsonx.take_str(rest, "discoverable")
  let domain = @jsonx.take_str(rest, "domain")
  let email_domain = @jsonx.take_str(rest, "email_domain")
  let enterprise_domain = @jsonx.take_str(rest, "enterprise_domain")
  let enterprise_id = @jsonx.take_str(rest, "enterprise_id")
  let enterprise_name = @jsonx.take_str(rest, "enterprise_name")
  let is_sfdc_auto_slack = @jsonx.take_bool(rest, "is_sfdc_auto_slack")
  let is_verified = @jsonx.take_bool(rest, "is_verified")
  let limit_ts = @jsonx.take_int64(rest, "limit_ts")
  let lob_sales_home_enabled = @jsonx.take_bool(rest, "lob_sales_home_enabled")
  let locale = @jsonx.take_str(rest, "locale")
  let messages_count = @jsonx.take_int(rest, "messages_count")
  let msg_edit_window_mins = @jsonx.take_int(rest, "msg_edit_window_mins")
  let name = @jsonx.take_str(rest, "name")
  let onboarding_channel_id = @jsonx.take_str(rest, "onboarding_channel_id")
  let over_storage_limit = @jsonx.take_bool(rest, "over_storage_limit")
  let pay_prod_cur = @jsonx.take_str(rest, "pay_prod_cur")
  let plan = @jsonx.take_str(rest, "plan")
  let team_url = @jsonx.take_str(rest, "team_url")
  let url = @jsonx.take_str(rest, "url")
  Some({
    id,
    avatar_base_url,
    date_create,
    default_channels,
    discoverability,
    discoverable,
    domain,
    email_domain,
    enterprise_domain,
    enterprise_id,
    enterprise_name,
    is_sfdc_auto_slack,
    is_verified,
    limit_ts,
    lob_sales_home_enabled,
    locale,
    messages_count,
    msg_edit_window_mins,
    name,
    onboarding_channel_id,
    over_storage_limit,
    pay_prod_cur,
    plan,
    team_url,
    url,
    extra: rest,
  })
}

///|
pub fn Team::to_json(self : Team) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_str(o, "avatar_base_url", self.avatar_base_url)
  @jsonx.put_int64(o, "date_create", self.date_create)
  @jsonx.put_str_arr(o, "default_channels", self.default_channels)
  @jsonx.put_str(o, "discoverability", self.discoverability)
  @jsonx.put_str(o, "discoverable", self.discoverable)
  @jsonx.put_str(o, "domain", self.domain)
  @jsonx.put_str(o, "email_domain", self.email_domain)
  @jsonx.put_str(o, "enterprise_domain", self.enterprise_domain)
  @jsonx.put_str(o, "enterprise_id", self.enterprise_id)
  @jsonx.put_str(o, "enterprise_name", self.enterprise_name)
  @jsonx.put_bool(o, "is_sfdc_auto_slack", self.is_sfdc_auto_slack)
  @jsonx.put_bool(o, "is_verified", self.is_verified)
  @jsonx.put_int64(o, "limit_ts", self.limit_ts)
  @jsonx.put_bool(o, "lob_sales_home_enabled", self.lob_sales_home_enabled)
  @jsonx.put_str(o, "locale", self.locale)
  @jsonx.put_int(o, "messages_count", self.messages_count)
  @jsonx.put_int(o, "msg_edit_window_mins", self.msg_edit_window_mins)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_str(o, "onboarding_channel_id", self.onboarding_channel_id)
  @jsonx.put_bool(o, "over_storage_limit", self.over_storage_limit)
  @jsonx.put_str(o, "pay_prod_cur", self.pay_prod_cur)
  @jsonx.put_str(o, "plan", self.plan)
  @jsonx.put_str(o, "team_url", self.team_url)
  @jsonx.put_str(o, "url", self.url)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A user group, which Slack also calls a subteam.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.usergroup, $.usergroups[], $.subteams.all[]
pub(all) struct Usergroup {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  auto_provision : Bool?
  channel_count : Int?
  created_by : String?
  date_create : Int64?
  date_delete : Int64?
  date_update : Int64?
  deleted_by : String?
  description : String?
  enterprise_subteam_id : String?
  handle : String?
  is_editing_restricted : Bool?
  is_external : Bool?
  is_idp_group : Bool?
  is_membership_locked : Bool?
  is_org_level : Bool?
  is_section : Bool?
  is_subteam : Bool?
  is_usergroup : Bool?
  is_visible : Bool?
  name : String?
  team_id : String?
  updated_by : String?
  user_count : Int?
  users : Array[String]?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn Usergroup::from_json(json : Json) -> Usergroup? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let auto_provision = @jsonx.take_bool(rest, "auto_provision")
  let channel_count = @jsonx.take_int(rest, "channel_count")
  let created_by = @jsonx.take_str(rest, "created_by")
  let date_create = @jsonx.take_int64(rest, "date_create")
  let date_delete = @jsonx.take_int64(rest, "date_delete")
  let date_update = @jsonx.take_int64(rest, "date_update")
  let deleted_by = @jsonx.take_str(rest, "deleted_by")
  let description = @jsonx.take_str(rest, "description")
  let enterprise_subteam_id = @jsonx.take_str(rest, "enterprise_subteam_id")
  let handle = @jsonx.take_str(rest, "handle")
  let is_editing_restricted = @jsonx.take_bool(rest, "is_editing_restricted")
  let is_external = @jsonx.take_bool(rest, "is_external")
  let is_idp_group = @jsonx.take_bool(rest, "is_idp_group")
  let is_membership_locked = @jsonx.take_bool(rest, "is_membership_locked")
  let is_org_level = @jsonx.take_bool(rest, "is_org_level")
  let is_section = @jsonx.take_bool(rest, "is_section")
  let is_subteam = @jsonx.take_bool(rest, "is_subteam")
  let is_usergroup = @jsonx.take_bool(rest, "is_usergroup")
  let is_visible = @jsonx.take_bool(rest, "is_visible")
  let name = @jsonx.take_str(rest, "name")
  let team_id = @jsonx.take_str(rest, "team_id")
  let updated_by = @jsonx.take_str(rest, "updated_by")
  let user_count = @jsonx.take_int(rest, "user_count")
  let users = @jsonx.take_str_arr(rest, "users")
  Some({
    id,
    auto_provision,
    channel_count,
    created_by,
    date_create,
    date_delete,
    date_update,
    deleted_by,
    description,
    enterprise_subteam_id,
    handle,
    is_editing_restricted,
    is_external,
    is_idp_group,
    is_membership_locked,
    is_org_level,
    is_section,
    is_subteam,
    is_usergroup,
    is_visible,
    name,
    team_id,
    updated_by,
    user_count,
    users,
    extra: rest,
  })
}

///|
pub fn Usergroup::to_json(self : Usergroup) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_bool(o, "auto_provision", self.auto_provision)
  @jsonx.put_int(o, "channel_count", self.channel_count)
  @jsonx.put_str(o, "created_by", self.created_by)
  @jsonx.put_int64(o, "date_create", self.date_create)
  @jsonx.put_int64(o, "date_delete", self.date_delete)
  @jsonx.put_int64(o, "date_update", self.date_update)
  @jsonx.put_str(o, "deleted_by", self.deleted_by)
  @jsonx.put_str(o, "description", self.description)
  @jsonx.put_str(o, "enterprise_subteam_id", self.enterprise_subteam_id)
  @jsonx.put_str(o, "handle", self.handle)
  @jsonx.put_bool(o, "is_editing_restricted", self.is_editing_restricted)
  @jsonx.put_bool(o, "is_external", self.is_external)
  @jsonx.put_bool(o, "is_idp_group", self.is_idp_group)
  @jsonx.put_bool(o, "is_membership_locked", self.is_membership_locked)
  @jsonx.put_bool(o, "is_org_level", self.is_org_level)
  @jsonx.put_bool(o, "is_section", self.is_section)
  @jsonx.put_bool(o, "is_subteam", self.is_subteam)
  @jsonx.put_bool(o, "is_usergroup", self.is_usergroup)
  @jsonx.put_bool(o, "is_visible", self.is_visible)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_str(o, "team_id", self.team_id)
  @jsonx.put_str(o, "updated_by", self.updated_by)
  @jsonx.put_int(o, "user_count", self.user_count)
  @jsonx.put_str_arr(o, "users", self.users)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A modal or App Home view.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.view, $.views[]
pub(all) struct View {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  app_id : String?
  app_installed_team_id : String?
  app_unfurl_url : String?
  blocks : Array[@blocks.LayoutBlock]?
  bot_id : String?
  callback_id : String?
  channel : String?
  clear_on_close : Bool?
  close : @blocks.TextObject?
  entity_url : String?
  external_id : String?
  hash : String?
  message_ts : String?
  notify_on_close : Bool?
  previous_view_id : String?
  private_metadata : String?
  root_view_id : String?
  submit : @blocks.TextObject?
  submit_disabled : Bool?
  team_id : String?
  thread_ts : String?
  title : @blocks.TextObject?
  type_ : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn View::from_json(json : Json) -> View? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let app_id = @jsonx.take_str(rest, "app_id")
  let app_installed_team_id = @jsonx.take_str(rest, "app_installed_team_id")
  let app_unfurl_url = @jsonx.take_str(rest, "app_unfurl_url")
  let blocks = take_blocks(rest, "blocks")
  let bot_id = @jsonx.take_str(rest, "bot_id")
  let callback_id = @jsonx.take_str(rest, "callback_id")
  let channel = @jsonx.take_str(rest, "channel")
  let clear_on_close = @jsonx.take_bool(rest, "clear_on_close")
  let close = take_text(rest, "close")
  let entity_url = @jsonx.take_str(rest, "entity_url")
  let external_id = @jsonx.take_str(rest, "external_id")
  let hash = @jsonx.take_str(rest, "hash")
  let message_ts = @jsonx.take_str(rest, "message_ts")
  let notify_on_close = @jsonx.take_bool(rest, "notify_on_close")
  let previous_view_id = @jsonx.take_str(rest, "previous_view_id")
  let private_metadata = @jsonx.take_str(rest, "private_metadata")
  let root_view_id = @jsonx.take_str(rest, "root_view_id")
  let submit = take_text(rest, "submit")
  let submit_disabled = @jsonx.take_bool(rest, "submit_disabled")
  let team_id = @jsonx.take_str(rest, "team_id")
  let thread_ts = @jsonx.take_str(rest, "thread_ts")
  let title = take_text(rest, "title")
  let type_ = @jsonx.take_str(rest, "type")
  Some({
    id,
    app_id,
    app_installed_team_id,
    app_unfurl_url,
    blocks,
    bot_id,
    callback_id,
    channel,
    clear_on_close,
    close,
    entity_url,
    external_id,
    hash,
    message_ts,
    notify_on_close,
    previous_view_id,
    private_metadata,
    root_view_id,
    submit,
    submit_disabled,
    team_id,
    thread_ts,
    title,
    type_,
    extra: rest,
  })
}

///|
pub fn View::to_json(self : View) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_str(o, "app_id", self.app_id)
  @jsonx.put_str(o, "app_installed_team_id", self.app_installed_team_id)
  @jsonx.put_str(o, "app_unfurl_url", self.app_unfurl_url)
  @jsonx.put_obj(o, "blocks", self.blocks, @blocks.blocks_to_json)
  @jsonx.put_str(o, "bot_id", self.bot_id)
  @jsonx.put_str(o, "callback_id", self.callback_id)
  @jsonx.put_str(o, "channel", self.channel)
  @jsonx.put_bool(o, "clear_on_close", self.clear_on_close)
  @jsonx.put_obj(o, "close", self.close, @blocks.TextObject::to_json)
  @jsonx.put_str(o, "entity_url", self.entity_url)
  @jsonx.put_str(o, "external_id", self.external_id)
  @jsonx.put_str(o, "hash", self.hash)
  @jsonx.put_str(o, "message_ts", self.message_ts)
  @jsonx.put_bool(o, "notify_on_close", self.notify_on_close)
  @jsonx.put_str(o, "previous_view_id", self.previous_view_id)
  @jsonx.put_str(o, "private_metadata", self.private_metadata)
  @jsonx.put_str(o, "root_view_id", self.root_view_id)
  @jsonx.put_obj(o, "submit", self.submit, @blocks.TextObject::to_json)
  @jsonx.put_bool(o, "submit_disabled", self.submit_disabled)
  @jsonx.put_str(o, "team_id", self.team_id)
  @jsonx.put_str(o, "thread_ts", self.thread_ts)
  @jsonx.put_obj(o, "title", self.title, @blocks.TextObject::to_json)
  @jsonx.put_str(o, "type", self.type_)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// An uploaded file.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.file, $.files[], $.files.matches[], $.*.files[]
pub(all) struct File {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  access : String?
  alt_txt : String?
  app_id : String?
  app_name : String?
  blocks : Array[@blocks.LayoutBlock]?
  bot_id : String?
  channels : Array[String]?
  comments_count : Int?
  converted_pdf : String?
  created : Int64?
  deanimate_gif : String?
  display_as_bot : Bool?
  duration_ms : Int?
  editable : Bool?
  editor : String?
  external_id : String?
  external_type : String?
  external_url : String?
  file_access : String?
  filetype : String?
  groups : Array[String]?
  has_rich_preview : Bool?
  hls : String?
  ims : Array[String]?
  is_external : Bool?
  is_modified_by_ai : Bool?
  is_public : Bool?
  is_starred : Bool?
  last_editor : String?
  lines : Int?
  media_display_type : String?
  mimetype : String?
  mode : String?
  mp4 : String?
  name : String?
  num_stars : Int?
  original_attachment_count : Int?
  permalink : String?
  permalink_public : String?
  pinned_to : Array[String]?
  plain_text : String?
  pretty_type : String?
  preview : String?
  preview_is_truncated : Bool?
  public_url_shared : Bool?
  reactions : Array[Reaction]?
  size : Int?
  source_team : String?
  subtype : String?
  timestamp : Int64?
  title : String?
  title_blocks : Array[@blocks.LayoutBlock]?
  url_private : String?
  url_private_download : String?
  user : String?
  user_team : String?
  username : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn File::from_json(json : Json) -> File? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let access = @jsonx.take_str(rest, "access")
  let alt_txt = @jsonx.take_str(rest, "alt_txt")
  let app_id = @jsonx.take_str(rest, "app_id")
  let app_name = @jsonx.take_str(rest, "app_name")
  let blocks = take_blocks(rest, "blocks")
  let bot_id = @jsonx.take_str(rest, "bot_id")
  let channels = @jsonx.take_str_arr(rest, "channels")
  let comments_count = @jsonx.take_int(rest, "comments_count")
  let converted_pdf = @jsonx.take_str(rest, "converted_pdf")
  let created = @jsonx.take_int64(rest, "created")
  let deanimate_gif = @jsonx.take_str(rest, "deanimate_gif")
  let display_as_bot = @jsonx.take_bool(rest, "display_as_bot")
  let duration_ms = @jsonx.take_int(rest, "duration_ms")
  let editable = @jsonx.take_bool(rest, "editable")
  let editor = @jsonx.take_str(rest, "editor")
  let external_id = @jsonx.take_str(rest, "external_id")
  let external_type = @jsonx.take_str(rest, "external_type")
  let external_url = @jsonx.take_str(rest, "external_url")
  let file_access = @jsonx.take_str(rest, "file_access")
  let filetype = @jsonx.take_str(rest, "filetype")
  let groups = @jsonx.take_str_arr(rest, "groups")
  let has_rich_preview = @jsonx.take_bool(rest, "has_rich_preview")
  let hls = @jsonx.take_str(rest, "hls")
  let ims = @jsonx.take_str_arr(rest, "ims")
  let is_external = @jsonx.take_bool(rest, "is_external")
  let is_modified_by_ai = @jsonx.take_bool(rest, "is_modified_by_ai")
  let is_public = @jsonx.take_bool(rest, "is_public")
  let is_starred = @jsonx.take_bool(rest, "is_starred")
  let last_editor = @jsonx.take_str(rest, "last_editor")
  let lines = @jsonx.take_int(rest, "lines")
  let media_display_type = @jsonx.take_str(rest, "media_display_type")
  let mimetype = @jsonx.take_str(rest, "mimetype")
  let mode = @jsonx.take_str(rest, "mode")
  let mp4 = @jsonx.take_str(rest, "mp4")
  let name = @jsonx.take_str(rest, "name")
  let num_stars = @jsonx.take_int(rest, "num_stars")
  let original_attachment_count = @jsonx.take_int(
    rest, "original_attachment_count",
  )
  let permalink = @jsonx.take_str(rest, "permalink")
  let permalink_public = @jsonx.take_str(rest, "permalink_public")
  let pinned_to = @jsonx.take_str_arr(rest, "pinned_to")
  let plain_text = @jsonx.take_str(rest, "plain_text")
  let pretty_type = @jsonx.take_str(rest, "pretty_type")
  let preview = @jsonx.take_str(rest, "preview")
  let preview_is_truncated = @jsonx.take_bool(rest, "preview_is_truncated")
  let public_url_shared = @jsonx.take_bool(rest, "public_url_shared")
  let reactions = @jsonx.take_arr(rest, "reactions", Reaction::from_json)
  let size = @jsonx.take_int(rest, "size")
  let source_team = @jsonx.take_str(rest, "source_team")
  let subtype = @jsonx.take_str(rest, "subtype")
  let timestamp = @jsonx.take_int64(rest, "timestamp")
  let title = @jsonx.take_str(rest, "title")
  let title_blocks = take_blocks(rest, "title_blocks")
  let url_private = @jsonx.take_str(rest, "url_private")
  let url_private_download = @jsonx.take_str(rest, "url_private_download")
  let user = @jsonx.take_str(rest, "user")
  let user_team = @jsonx.take_str(rest, "user_team")
  let username = @jsonx.take_str(rest, "username")
  Some({
    id,
    access,
    alt_txt,
    app_id,
    app_name,
    blocks,
    bot_id,
    channels,
    comments_count,
    converted_pdf,
    created,
    deanimate_gif,
    display_as_bot,
    duration_ms,
    editable,
    editor,
    external_id,
    external_type,
    external_url,
    file_access,
    filetype,
    groups,
    has_rich_preview,
    hls,
    ims,
    is_external,
    is_modified_by_ai,
    is_public,
    is_starred,
    last_editor,
    lines,
    media_display_type,
    mimetype,
    mode,
    mp4,
    name,
    num_stars,
    original_attachment_count,
    permalink,
    permalink_public,
    pinned_to,
    plain_text,
    pretty_type,
    preview,
    preview_is_truncated,
    public_url_shared,
    reactions,
    size,
    source_team,
    subtype,
    timestamp,
    title,
    title_blocks,
    url_private,
    url_private_download,
    user,
    user_team,
    username,
    extra: rest,
  })
}

///|
pub fn File::to_json(self : File) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_str(o, "access", self.access)
  @jsonx.put_str(o, "alt_txt", self.alt_txt)
  @jsonx.put_str(o, "app_id", self.app_id)
  @jsonx.put_str(o, "app_name", self.app_name)
  @jsonx.put_obj(o, "blocks", self.blocks, @blocks.blocks_to_json)
  @jsonx.put_str(o, "bot_id", self.bot_id)
  @jsonx.put_str_arr(o, "channels", self.channels)
  @jsonx.put_int(o, "comments_count", self.comments_count)
  @jsonx.put_str(o, "converted_pdf", self.converted_pdf)
  @jsonx.put_int64(o, "created", self.created)
  @jsonx.put_str(o, "deanimate_gif", self.deanimate_gif)
  @jsonx.put_bool(o, "display_as_bot", self.display_as_bot)
  @jsonx.put_int(o, "duration_ms", self.duration_ms)
  @jsonx.put_bool(o, "editable", self.editable)
  @jsonx.put_str(o, "editor", self.editor)
  @jsonx.put_str(o, "external_id", self.external_id)
  @jsonx.put_str(o, "external_type", self.external_type)
  @jsonx.put_str(o, "external_url", self.external_url)
  @jsonx.put_str(o, "file_access", self.file_access)
  @jsonx.put_str(o, "filetype", self.filetype)
  @jsonx.put_str_arr(o, "groups", self.groups)
  @jsonx.put_bool(o, "has_rich_preview", self.has_rich_preview)
  @jsonx.put_str(o, "hls", self.hls)
  @jsonx.put_str_arr(o, "ims", self.ims)
  @jsonx.put_bool(o, "is_external", self.is_external)
  @jsonx.put_bool(o, "is_modified_by_ai", self.is_modified_by_ai)
  @jsonx.put_bool(o, "is_public", self.is_public)
  @jsonx.put_bool(o, "is_starred", self.is_starred)
  @jsonx.put_str(o, "last_editor", self.last_editor)
  @jsonx.put_int(o, "lines", self.lines)
  @jsonx.put_str(o, "media_display_type", self.media_display_type)
  @jsonx.put_str(o, "mimetype", self.mimetype)
  @jsonx.put_str(o, "mode", self.mode)
  @jsonx.put_str(o, "mp4", self.mp4)
  @jsonx.put_str(o, "name", self.name)
  @jsonx.put_int(o, "num_stars", self.num_stars)
  @jsonx.put_int(o, "original_attachment_count", self.original_attachment_count)
  @jsonx.put_str(o, "permalink", self.permalink)
  @jsonx.put_str(o, "permalink_public", self.permalink_public)
  @jsonx.put_str_arr(o, "pinned_to", self.pinned_to)
  @jsonx.put_str(o, "plain_text", self.plain_text)
  @jsonx.put_str(o, "pretty_type", self.pretty_type)
  @jsonx.put_str(o, "preview", self.preview)
  @jsonx.put_bool(o, "preview_is_truncated", self.preview_is_truncated)
  @jsonx.put_bool(o, "public_url_shared", self.public_url_shared)
  @jsonx.put_arr(o, "reactions", self.reactions, Reaction::to_json)
  @jsonx.put_int(o, "size", self.size)
  @jsonx.put_str(o, "source_team", self.source_team)
  @jsonx.put_str(o, "subtype", self.subtype)
  @jsonx.put_int64(o, "timestamp", self.timestamp)
  @jsonx.put_str(o, "title", self.title)
  @jsonx.put_obj(o, "title_blocks", self.title_blocks, @blocks.blocks_to_json)
  @jsonx.put_str(o, "url_private", self.url_private)
  @jsonx.put_str(o, "url_private_download", self.url_private_download)
  @jsonx.put_str(o, "user", self.user)
  @jsonx.put_str(o, "user_team", self.user_team)
  @jsonx.put_str(o, "username", self.username)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A channel bookmark: a pinned link, file or app shortcut in a channel's header.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.bookmark, $.bookmarks[]
pub(all) struct Bookmark {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  app_action_id : String?
  app_id : String?
  channel_id : String?
  date_created : Int64?
  date_updated : Int64?
  emoji : String?
  entity_id : String?
  icon_url : String?
  last_updated_by_team_id : String?
  last_updated_by_user_id : String?
  link : String?
  rank : String?
  shortcut_id : String?
  title : String?
  type_ : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn Bookmark::from_json(json : Json) -> Bookmark? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let app_action_id = @jsonx.take_str(rest, "app_action_id")
  let app_id = @jsonx.take_str(rest, "app_id")
  let channel_id = @jsonx.take_str(rest, "channel_id")
  let date_created = @jsonx.take_int64(rest, "date_created")
  let date_updated = @jsonx.take_int64(rest, "date_updated")
  let emoji = @jsonx.take_str(rest, "emoji")
  let entity_id = @jsonx.take_str(rest, "entity_id")
  let icon_url = @jsonx.take_str(rest, "icon_url")
  let last_updated_by_team_id = @jsonx.take_str(rest, "last_updated_by_team_id")
  let last_updated_by_user_id = @jsonx.take_str(rest, "last_updated_by_user_id")
  let link = @jsonx.take_str(rest, "link")
  let rank = @jsonx.take_str(rest, "rank")
  let shortcut_id = @jsonx.take_str(rest, "shortcut_id")
  let title = @jsonx.take_str(rest, "title")
  let type_ = @jsonx.take_str(rest, "type")
  Some({
    id,
    app_action_id,
    app_id,
    channel_id,
    date_created,
    date_updated,
    emoji,
    entity_id,
    icon_url,
    last_updated_by_team_id,
    last_updated_by_user_id,
    link,
    rank,
    shortcut_id,
    title,
    type_,
    extra: rest,
  })
}

///|
pub fn Bookmark::to_json(self : Bookmark) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_str(o, "app_action_id", self.app_action_id)
  @jsonx.put_str(o, "app_id", self.app_id)
  @jsonx.put_str(o, "channel_id", self.channel_id)
  @jsonx.put_int64(o, "date_created", self.date_created)
  @jsonx.put_int64(o, "date_updated", self.date_updated)
  @jsonx.put_str(o, "emoji", self.emoji)
  @jsonx.put_str(o, "entity_id", self.entity_id)
  @jsonx.put_str(o, "icon_url", self.icon_url)
  @jsonx.put_str(o, "last_updated_by_team_id", self.last_updated_by_team_id)
  @jsonx.put_str(o, "last_updated_by_user_id", self.last_updated_by_user_id)
  @jsonx.put_str(o, "link", self.link)
  @jsonx.put_str(o, "rank", self.rank)
  @jsonx.put_str(o, "shortcut_id", self.shortcut_id)
  @jsonx.put_str(o, "title", self.title)
  @jsonx.put_str(o, "type", self.type_)
  @jsonx.merge_extra(o, self.extra)
}

///|
/// A message queued for later by `chat.scheduleMessage`, until it is sent or cancelled.
///
/// Anything Slack sends that is not below is in `extra`. Observed in the
/// reference corpus at:
/// $.scheduled_messages[]
pub(all) struct ScheduledMessage {
  /// Always sent, on every occurrence in the corpus. A payload without
  /// one is not this entity, and `from_json` answers `None`.
  id : String
  channel_id : String?
  date_created : Int64?
  post_at : Int64?
  text : String?
  /// Every field this version does not model, verbatim.
  extra : Map[String, Json]
} derive(Eq, @debug.Debug)

///|
/// `None` when the value is not an object, or has no string `id`.
pub fn ScheduledMessage::from_json(json : Json) -> ScheduledMessage? {
  guard json is Object(o) else { return None }
  let rest = @jsonx.fields_of(o)
  guard @jsonx.take_str(rest, "id") is Some(id) else { return None }
  let channel_id = @jsonx.take_str(rest, "channel_id")
  let date_created = @jsonx.take_int64(rest, "date_created")
  let post_at = @jsonx.take_int64(rest, "post_at")
  let text = @jsonx.take_str(rest, "text")
  Some({ id, channel_id, date_created, post_at, text, extra: rest })
}

///|
pub fn ScheduledMessage::to_json(self : ScheduledMessage) -> Json {
  let o : Map[String, Json] = Map([])
  o["id"] = Json::string(self.id)
  @jsonx.put_str(o, "channel_id", self.channel_id)
  @jsonx.put_int64(o, "date_created", self.date_created)
  @jsonx.put_int64(o, "post_at", self.post_at)
  @jsonx.put_str(o, "text", self.text)
  @jsonx.merge_extra(o, self.extra)
}