syntax = "proto3";

package devvit.data.api.v1alpha;

import "buf/validate/validate.proto";
import "devvit/events/v1alpha/events.proto";
import "devvit/options/options.proto";
import "devvit/reddit/v2alpha/postv2.proto";
import "devvit/reddit/v2alpha/subredditv2.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "openapi/helper.proto";

option go_package = "github.snooguts.net/reddit/devplatform-api/go/grpc/devvit/data/api/v1alpha";

// Enum for vote thing types.
enum VoteType {
  UNKNOWN = 0;
  POST = 1;
  COMMENT = 2;
}

enum ModActionType {
  UNKNOWN_MOD_ACTION = 0;
  EDIT_POST_FLAIR = 3;
  EDIT_USER_FLAIR = 4;
  LOCK_POST = 5;
  LOCK_COMMENT = 6;
  SPAM_POST = 7;
  SPAM_COMMENT = 8;
  DISTINGUISH_POST = 9;
  DISTINGUISH_COMMENT = 10;
  STICKY_POST = 11;
  STICKY_COMMENT = 12;
  reserved 1, 2;
  reserved "APPROVE_POST", "APPROVE_COMMENT";
}

// Post create event
message PostCreateFirehose {
  // Provides information about the post, including the post id, author, and time it was created.
  PostFirehose post = 1 [(buf.validate.field).required = true];
  // Identifies the user who created the post and includes user’s url.
  UserFirehose author = 2 [(buf.validate.field).required = true];
  // Lists the subreddit associated with the post by name and subreddit id.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];
}

// Comment create event
message CommentCreateFirehose {
  // Provides information about the comment, including the comment id, content, and time it was created.
  CommentFirehose comment = 1 [(buf.validate.field).required = true];
  // Identifies the user who created the comment and includes user’s url.
  UserFirehose author = 2 [(buf.validate.field).required = true];
  // Provides information about the post associated with the comment, including the post id, author, and time it was created.
  PostFirehose post = 3 [(buf.validate.field).required = true];
  // Lists the subreddit associated with the post by name and subreddit id.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];
}

// Delete event for a post, comment, or account. The type of delete event is indicated by `eventType` (POST_DELETE, COMMENT_DELETE, or ACCOUNT_DELETE).
message DeletionFirehose {
  // Lists the id of the post or comment object that was deleted.
  string id = 1 [
    (buf.validate.field).required = true,
    (buf.validate.field).string.pattern = "(t1_|t3_|t2_).*",
    (openapi.field_example) = "t1_kiidxv1"
  ];
  // Shows the timestamp indicating when the object was deleted.
  google.protobuf.Timestamp deleted_at = 2 [
    (buf.validate.field).required = true,
    (openapi.field_example) = "2024-01-19T00:07:46.873Z"
  ];
  // Timestamp of the time when the object was created at
  google.protobuf.Timestamp created_at = 3 [(openapi.field_example) = "2024-01-18T23:28:23.170Z"];
  // Shows the post id associated with the deleted comment (for commentDelete only).
  string post_id = 4 [(openapi.field_example) = "t3_19a2zv6"];
  // Permalink to deleted object
  string permalink = 5 [(openapi.field_example) = "/r/Cricket/comments/19a2zv6/comment/kiidxv1"];
  // Who initiated the deletion.
  devvit.events.v1alpha.EventSource source = 6 [(openapi.field_example) = "USER"];
  // Username of the account which is deleted (for account deletes only)
  string name = 7 [(openapi.field_example) = "sassyshalimar"];
  // Reason for the deletion. Currently, this is only populated for admin deletions. Reasons:
  // * EXPLICIT_CONTENT indicates content or account is sexually explicit.
  // * LEGAL indicates content or account may violate law, rule, or regulation.
  // * OTHER indicates content or account may violate Reddit policy.
  // * SPAM indicates content or account identified by Reddit as spam.
  // * UNKNOWN indicates content or account was removed for unknown reason.
  // * UNSPECIFIED_DELETION_REASON will not be sent, as it is the default value.
  devvit.events.v1alpha.DeletionReason reason = 8 [(openapi.field_example) = "LEGAL"];
}

// Post edit event
message PostEditFirehose {
  // Provides information about the post, including the post id, author, and time it was created.
  PostFirehose post = 1 [(buf.validate.field).required = true];
  // Identifies the user who edited the post and includes user’s url.
  UserFirehose author = 2 [(buf.validate.field).required = true];
  // Lists the subreddit associated with the post by name and subreddit id.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];

  // removed fields
  reserved 3;
  reserved "previous_body";
}

// Comment edit event
message CommentEditFirehose {
  // Provides information about the comment, including the comment id, author, and time it was created.
  CommentFirehose comment = 1 [(buf.validate.field).required = true];
  // Identifies the user who edited the post and includes user’s url.
  UserFirehose author = 2 [(buf.validate.field).required = true];
  // Contains the original content before the post was edited.
  PostFirehose post = 3 [(buf.validate.field).required = true];
  // Lists the subreddit associated with the comment by name and subreddit id.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];

  // removed fields
  reserved 4;
  reserved "previous_body";
}

// Post approve event
message PostApproveFirehose {
  // Provides information about the post, including the post id, author, and time it was created.
  PostFirehose post = 1 [(buf.validate.field).required = true];
  // Identifies the user who authored the post and includes user’s url.
  UserFirehose author = 2 [(buf.validate.field).required = true];
  // Shows the timestamp indicating when the object was approved.
  google.protobuf.Timestamp approved_at = 4 [
    (devvit.options.trigger_evt_path) = "approved_at",
    (buf.validate.field).required = true
  ];
  // Who initiated the approval.
  devvit.events.v1alpha.EventSource source = 5 [
    (devvit.options.trigger_evt_path) = "source",
    (openapi.field_example) = "ADMIN",
    (buf.validate.field).required = true
  ];
  // Lists the subreddit associated with the post by name and subreddit id.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];
}

// Comment approve event
message CommentApproveFirehose {
  // Provides information about the comment, including the comment id, author, and time it was created.
  CommentFirehose comment = 1 [(buf.validate.field).required = true];
  // Provides information about the post, including the post id, author, and time it was created.
  PostFirehose post = 2 [(buf.validate.field).required = true];
  // Identifies the user who authored the comment and includes user’s url.
  UserFirehose author = 3 [(buf.validate.field).required = true];
  // Shows the timestamp indicating when the object was approved.
  google.protobuf.Timestamp approved_at = 4 [
    (devvit.options.trigger_evt_path) = "approved_at",
    (buf.validate.field).required = true
  ];
  // Who initiated the approval.
  devvit.events.v1alpha.EventSource source = 5 [
    (buf.validate.field).required = true,
    (devvit.options.trigger_evt_path) = "source",
    (openapi.field_example) = "ADMIN"
  ];
  // Lists the subreddit associated with the comment by name and subreddit id.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];
}

// Vote event
message VoteFirehose {
  // Lists the id of the comment or post receiving the vote event.
  string id = 1 [
    (buf.validate.field).required = true,
    (buf.validate.field).string.pattern = "(t1_|t3_).*",
    (openapi.field_example) = "t3_193x7ph"
  ];
  // Specifies the object (comment or post).
  VoteType type = 5 [
    (buf.validate.field).required = true,
    (openapi.field_example) = "POST"
  ];
  // Populated when COMMENT, postid associated with the comment
  string post_id = 6 [(openapi.field_example) = "t3_193x7ph"];
  // Populated when COMMENT, timestamp of when post was created
  google.protobuf.Timestamp post_created_at = 7;
  // Provides the timestamp when the most recent votes were calculated.
  google.protobuf.Timestamp updated_at = 4 [(buf.validate.field).required = true];
  // Permalink to the object
  string permalink = 8 [
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "/r/",
    (openapi.field_example) = "/r/MARIOPARTY/comments/193x7ph"
  ];
  // Upvote ratio i.e u / (u + d) where u = upvotes and d = downvotes
  google.protobuf.FloatValue upvote_ratio = 9 [
    (buf.validate.field).required = true,
    (openapi.field_example) = "0.94871795"
  ];
  // Score is the number of upvotes minus the number of downvotes on a post/comment. The score is 0 when there are no votes or an equal number of upvotes and downvotes. A negative score indicates more downvotes than upvotes, while a positive score reflects more upvotes than downvotes.
  google.protobuf.Int32Value score = 10 [
    (buf.validate.field).required = true,
    (openapi.field_example) = "35"
  ]; // Int32Value allows us to send '0' value
  // Populated when COMMENT, timestamp of when comment was created
  google.protobuf.Timestamp comment_created_at = 11;

  // removed fields
  reserved 2, 3;
  reserved "upvotes", "downvotes";
}

// Mod action event
message ModActionFirehose {
  // Provides the id of the mod action type (like removing content or banning a user)
  string id = 1 [
    (buf.validate.field).required = true,
    (openapi.field_example) = "t3_abc"
  ];
  // Describes the mod action (like editing settings or creating a rule). You will never receive an action of type UNKNOWN_MOD_ACTION.
  ModActionType action = 2 [
    (buf.validate.field).required = true,
    (openapi.field_example) = "LOCK_POST"
  ];
  // Provides the timestamp when the action occurred.
  google.protobuf.Timestamp actioned_at = 3 [(buf.validate.field).required = true];
  // Lists the subreddit associated with the action.
  SubredditFirehose subreddit = 10 [(buf.validate.field).required = true];

  // The permalink for the post or comment that received the mod action.
  optional string permalink = 4 [(buf.validate.field).required = false];

  // Timestamp indicating when the target post or comment was created. Is not populated for users.
  optional google.protobuf.Timestamp created_at = 5 [(buf.validate.field).required = false];
}

// Info about Post
message PostFirehose {
  // Unique post id
  string id = 1 [
    (devvit.options.trigger_evt_path) = "post.id",
    (devvit.options.im_path) = "post.id",
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "t3_",
    (openapi.field_example) = "t3_1798o2e"
  ];
  // Title of the post
  string title = 2 [
    (devvit.options.trigger_evt_path) = "post.title",
    (devvit.options.im_path) = "post.title",
    (buf.validate.field).required = true,
    (openapi.field_example) = "Reddit Conversion Lift and Lift Study Framework"
  ];
  // Post body
  string body = 3 [
    (devvit.options.trigger_evt_path) = "post.selftext",
    (devvit.options.im_path) = "post.body",
    (openapi.field_example) = "Written by Yimin Wu and Ellis Miranda. At the end of May 2023, Reddit launched Reddit Conversion Lift (RCL) product to General Availability. Reddit Conversion Lift (RCL) is the Reddit first-party measurement solution that enables marketers to evaluate the incremental impact of Reddit ads on driving conversions (conversion is an action that our advertisers define as valuable to their business, such as an online purchase or a subscription of their service, etc). It measures the number of conversions that were caused by exposure to ads on Reddit."
  ];
  // URL the post points to. It can be an external URL in case of link posts, a URL to an image in case of image posts, or a permalink to the Reddit post.
  string url = 4 [
    (devvit.options.trigger_evt_path) = "post.url",
    (devvit.options.im_path) = "post.url",
    (openapi.field_example) = "/r/RedditEng/comments/1798o2e/reddit_conversion_lift_and_lift_study_framework/"
  ];
  // Timestamp for when post was created
  google.protobuf.Timestamp created_at = 5 [
    (devvit.options.trigger_evt_path) = "post.created_at",
    (devvit.options.im_path) = "post.created_at",
    (buf.validate.field).required = true
  ];
  // Flair
  optional PostFlairFirehose flair = 6;
  // Language
  string language_code = 9 [
    (devvit.options.trigger_evt_path) = "post.language_code",
    (devvit.options.im_path) = "post.language_code",
    (openapi.field_example) = "en"
  ];
  // When the post was last updated
  google.protobuf.Timestamp updated_at = 10 [
    (devvit.options.trigger_evt_path) = "post.updated_at",
    (devvit.options.im_path) = "post.last_modified_at"
  ];
  // Gildings (legacy Reddit Gold - does not include new Reddit Awards)
  int32 gildings = 11 [
    (devvit.options.trigger_evt_path) = "post.gildings",
    (devvit.options.im_path) = "post.gildings"
  ];
  // Post score based on the number of upvotes minus the number of downvotes.
  int32 score = 12 [
    (devvit.options.trigger_evt_path) = "post.score",
    (devvit.options.im_path) = "post.score",
    (openapi.field_example) = "18"
  ];
  // Number of comments on the post
  int32 num_comments = 13 [
    (devvit.options.trigger_evt_path) = "post.num_comments",
    (devvit.options.im_path) = "post.num_comments",
    (openapi.field_example) = "5"
  ];
  // Thumbnail associated with the post
  string thumbnail = 14 [
    (devvit.options.trigger_evt_path) = "post.thumbnail",
    (devvit.options.im_path) = "post.thumbnail",
    (openapi.field_example) = "https://b.thumbs.redditmedia.com/xRj014iby3672Hn0dEUfr953QCEY6h_uDQpwYkwcUlQ.jpg"
  ];
  // Crosspost_parent_id
  string crosspost_parent_id = 15 [
    (devvit.options.trigger_evt_path) = "post.crosspost_parent_id",
    (devvit.options.im_path) = "post.crosspost_parent_id",
    (openapi.field_example) = "t3_186up3s"
  ];
  // Media object associated with post
  optional PostMediaObjectFirehose media = 16;
  // Permalink of the post. Only the path of the URL is sent and needs to be prepended with `https://www.reddit.com`, to direct to the post on Reddit
  string permalink = 17 [
    (devvit.options.trigger_evt_path) = "post.permalink",
    (devvit.options.im_path) = "post.permalink",
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "/r/",
    (openapi.field_example) = "/r/RedditEng/comments/1798o2e/"
  ];
  //This post has been flagged as not safe for work. This will only be present if true
  bool nsfw = 18 [
    (devvit.options.trigger_evt_path) = "post.nsfw",
    (devvit.options.im_path) = "post.nsfw",
    (openapi.field_example) = "true"
  ];
  // A text post that does not contain an external link or media. This will only be present if true.
  bool self = 19 [
    (devvit.options.trigger_evt_path) = "post.is_self",
    (devvit.options.im_path) = "post.self"
  ];
  // Whether the post has been locked, preventing new comments. This will only be present if true
  bool locked = 20 [
    (devvit.options.trigger_evt_path) = "post.is_locked",
    (devvit.options.im_path) = "post.locked",
    (openapi.field_example) = "true"
  ];
  // Whether this post has been stickied to the top of the subreddit’s feed. This will only be present if true
  bool sticky = 21 [
    (devvit.options.trigger_evt_path) = "post.is_sticky",
    (devvit.options.im_path) = "post.sticky",
    (openapi.field_example) = "true"
  ];
  // Is a video post. This will only be present if true
  bool video = 22 [
    (devvit.options.trigger_evt_path) = "post.is_video",
    (devvit.options.im_path) = "post.video",
    (openapi.field_example) = "true"
  ];
  // Whether this post includes a spoiler. This will only be present if true
  bool spoiler = 23 [
    (devvit.options.trigger_evt_path) = "post.is_spoiler",
    (devvit.options.im_path) = "post.spoiler",
    (openapi.field_example) = "true"
  ];
  // Whether this post has been marked as spam. This will only be present if true
  bool spam = 24 [
    (devvit.options.trigger_evt_path) = "post.spam",
    (devvit.options.im_path) = "post.spam",
    (openapi.field_example) = "true"
  ];
  // If present, denotes how a post has been distinguished by a moderator, admin or user. NULL_VALUE will never be sent in the response. If a post is not distinguished, then this field will be missing.
  devvit.reddit.v2alpha.DistinguishType distinguished = 25 [
    (devvit.options.trigger_evt_path) = "post.distinguished",
    (devvit.options.im_path) = "post.distinguish_type",
    (openapi.field_example) = "ADMIN"
  ];
  // Identifies the type of post. It can be one of the following values image, video, link, poll, multi_media, crosspost, gallery, text, ama, or media.
  string type = 26 [
    (devvit.options.trigger_evt_path) = "post.type",
    (devvit.options.im_path) = "post.type",
    (openapi.field_example) = "image"
  ];
  // User id of post author. If the post author account was deleted, this field will be `t2_0`.
  string author_id = 27 [
    (devvit.options.trigger_evt_path) = "post.author_id",
    (devvit.options.im_path) = "post.author_id",
    (openapi.field_example) = "t2_bcutkf4n"
  ];
  // URLs to images in the gallery. (Note: This field is only present when `post.type='gallery'`.)
  repeated string gallery_images = 28 [
    (devvit.options.trigger_evt_path) = "post.gallery_images",
    (openapi.field_example) = "['http://i.redd.it/btosxb4kw47d1.jpg', 'http://i.redd.it/btosxb4kw47d1.jpg']"
  ];

  // Whether this post has been approved. This will only be present if true
  bool approved = 29 [
    (devvit.options.trigger_evt_path) = "post.is_approved",
    (openapi.field_example) = "true"
  ];
  // Media urls from the post body text.
  // Only media hosted by Reddit or Giphy is currently supported. (Note: This field is only present when the post body contains an embedded image.)
  repeated string media_urls = 30 [
    (devvit.options.trigger_evt_path) = "post.media_urls",
    (devvit.options.im_path) = "post.media_urls",
    (openapi.field_example) = "['https://i.redd.it/7a0ucn4ltzub1.png', 'https://giphy.com/gifs/Vuw9m5wXviFIQ']"
  ];
  // removed fields
  reserved 7, 8;
  reserved "trending_score", "toxicity_score";
}

// PostFlairFirehose struct
message PostFlairFirehose {
  // Text associated with post flair
  string text = 1 [
    (devvit.options.trigger_evt_path) = "post.link_flair.text",
    (devvit.options.im_path) = "post.flair.text",
    (openapi.field_example) = "Learning"
  ];
}

// PostMediaObjectFirehose struct
message PostMediaObjectFirehose {
  // Post media type
  string type = 1 [
    (devvit.options.trigger_evt_path) = "post.media.type",
    (devvit.options.im_path) = "post.media.type",
    (openapi.field_example) = "youtube.com"
  ];
  // Media object
  optional MediaObjectOembedFirehose oembed = 2;
  // Media object video
  optional MediaObjectRedditVideoFirehose reddit_video = 3;
}

// Media object
message MediaObjectOembedFirehose {
  // Media object type
  string type = 1 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.type",
    (devvit.options.im_path) = "post.media.oembed.type",
    (openapi.field_example) = "video"
  ];
  // Object version
  string version = 2 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.version",
    (devvit.options.im_path) = "post.media.oembed.version",
    (openapi.field_example) = "'1.0'"
  ];
  // Title associated with the object
  string title = 3 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.title",
    (devvit.options.im_path) = "post.media.oembed.title",
    (openapi.field_example) = "'Reddit: Advertiser Audience Forecasting with Druid'"
  ];
  // Object description
  string description = 4 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.description",
    (devvit.options.im_path) = "post.media.oembed.description",
    (openapi.field_example) = "'1080'"
  ];
  // Author name
  string author_name = 5 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.author_name",
    (devvit.options.im_path) = "post.media.oembed.author_name",
    (openapi.field_example) = "Imply"
  ];
  // Url to author's profile
  string author_url = 6 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.author_url",
    (devvit.options.im_path) = "post.media.oembed.author_url",
    (openapi.field_example) = "https://www.youtube.com/@Implydata"
  ];
  // Provider name
  string provider_name = 7 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.provider_name",
    (devvit.options.im_path) = "post.media.oembed.provider_name",
    (openapi.field_example) = "YouTube"
  ];
  // Provider url
  string provider_url = 8 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.provider_url",
    (devvit.options.im_path) = "post.media.oembed.provider_url",
    (openapi.field_example) = "https://www.youtube.com/"
  ];
  // Url to the thumbnail
  string thumbnail_url = 9 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.thumbnail_url",
    (devvit.options.im_path) = "post.media.oembed.thumbnail_url",
    (openapi.field_example) = "https://i.ytimg.com/vi/7PRWDMRSAOw/hqdefault.jpg"
  ];
  // Width of the thumbnail
  int32 thumbnail_width = 10 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.thumbnail_width",
    (devvit.options.im_path) = "post.media.oembed.thumbnail_size.width",
    (openapi.field_example) = "1080"
  ];
  // Height of the thumbnail
  int32 thumbnail_height = 11 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.thumbnail_height",
    (devvit.options.im_path) = "post.media.oembed.thumbnail_size.height",
    (openapi.field_example) = "360"
  ];
  // Html associated with the object
  string html = 12 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.html",
    (devvit.options.im_path) = "post.media.oembed.html",
    (openapi.field_example) = "'&lt;iframe width=356 height=200 src=https://www.youtube.com/embed/7PRWDMRSAOw?feature=oembed&amp;enablejsapi=1 frameborder=0 allow=accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share allowfullscreen title=Reddit: Advertiser Audience Forecasting with Druid&gt;&lt;/iframe&gt;'"
  ];
  // Width of the object
  int32 width = 13 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.width",
    (devvit.options.im_path) = "post.media.oembed.size.width",
    (openapi.field_example) = "356"
  ];
  // Height of the object
  int32 height = 14 [
    (devvit.options.trigger_evt_path) = "post.media.oembed.height",
    (devvit.options.im_path) = "post.media.oembed.size.height",
    (openapi.field_example) = "200"
  ];
}

// MediaObjectRedditVideoFirehose
message MediaObjectRedditVideoFirehose {
  // Bitrate of the video in kbps
  int32 bitrate_kbps = 1 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.bitrate_kbps",
    (devvit.options.im_path) = "post.media.reddit_video.bitrate_kbps",
    (openapi.field_example) = "5000"
  ];
  // Url to fallback on
  string fallback_url = 2 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.fallback_url",
    (devvit.options.im_path) = "post.media.reddit_video.fallback_url",
    (openapi.field_example) = "https://v.redd.it/0k9toa8rlb3c1/DASH_1080.mp4?source=fallback"
  ];
  // Height of the object
  int32 height = 3 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.height",
    (devvit.options.im_path) = "post.media.reddit_video.size.height",
    (openapi.field_example) = "1080"
  ];
  // Width of the object
  int32 width = 4 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.width",
    (devvit.options.im_path) = "post.media.reddit_video.size.width",
    (openapi.field_example) = "1920"
  ];
  // Media url
  string scrubber_media_url = 5 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.scrubber_media_url",
    (devvit.options.im_path) = "post.media.reddit_video.scrubber_media_url",
    (openapi.field_example) = "https://v.redd.it/0k9toa8rlb3c1/DASH_96.mp4"
  ];
  // Dash url
  string dash_url = 6 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.dash_url",
    (devvit.options.im_path) = "post.media.reddit_video.dash_url",
    (openapi.field_example) = "https://v.redd.it/0k9toa8rlb3c1/DASHPlaylist.mpd?a=1708282201%2CMDY3ZWIyODIwZjJkYWFkNDhiMGEzYzI1ZTYwYTJlOWY3ODc2OWYxNmMwNjI1NDYzYTUzODkxYTNhNWVmNzIzZQ%3D%3D&amp;v=1&amp;f=sd"
  ];
  // Duration of the video
  int64 duration = 7 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.duration",
    (devvit.options.im_path) = "post.media.reddit_video.duration",
    (openapi.field_example) = "'57'"
  ];
  // Hls url
  string hls_url = 8 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.hls_url",
    (devvit.options.im_path) = "post.media.reddit_video.hls_url",
    (openapi.field_example) = "https://v.redd.it/0k9toa8rlb3c1/HLSPlaylist.m3u8?a=1708282201%2CMTBiYjcxZTgyODIxYTRhYjI0NGMxZjEzNmU0MTJhMDg2ZDQxNjJhMmEyYmVjYmJhYzk5MDhkNTAxODUzOTkwYw%3D%3D&amp;v=1&amp;f=sd"
  ];
  // If the video is a gif. This will only be present if true
  bool is_gif = 9 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.is_gif",
    (devvit.options.im_path) = "post.media.reddit_video.is_gif",
    (openapi.field_example) = "true"
  ];
  // Transcoding score
  string transcoding_status = 10 [
    (devvit.options.trigger_evt_path) = "post.media.reddit_video.transcoding_status",
    (devvit.options.im_path) = "post.media.reddit_video.transcoding_status",
    (openapi.field_example) = "completed"
  ];
}

// Comment Firehose
message CommentFirehose {
  // Id associated with the comment
  string id = 1 [
    (devvit.options.trigger_evt_path) = "comment.id",
    (devvit.options.im_path) = "comment.id",
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "t1_",
    (openapi.field_example) = "t1_k5kbkod"
  ];
  // Body of the comment
  string body = 2 [
    (devvit.options.trigger_evt_path) = "comment.body",
    (devvit.options.im_path) = "comment.body",
    (openapi.field_example) = "Target Audience is decided by the Ads campaign. The role of lift studies is to conduct A/B tests by splitting the audience randomly and log the counterfactual events so we can measure lifts fair and square."
  ];
  // Comment's parent id
  string parent_id = 3 [
    (devvit.options.trigger_evt_path) = "comment.parent_id",
    (devvit.options.im_path) = "comment.parent_id",
    (buf.validate.field).required = true,
    (buf.validate.field).string.pattern = "(t1_|t3_).*",
    (openapi.field_example) = "t1_k598r8o"
  ];
  // Comment was created at
  google.protobuf.Timestamp created_at = 4 [
    (devvit.options.trigger_evt_path) = "comment.created_at",
    (devvit.options.im_path) = "comment.created_at",
    (buf.validate.field).required = true
  ];
  // Language code (Note: this will be the language code for the associated post and not the comment itself.)
  string language_code = 7 [
    (devvit.options.trigger_evt_path) = "comment.language_code",
    (devvit.options.im_path) = "comment.language_code",
    (openapi.field_example) = "en"
  ];
  // Last modified at
  google.protobuf.Timestamp last_modified_at = 8 [
    (devvit.options.trigger_evt_path) = "comment.last_modified_at",
    (devvit.options.im_path) = "comment.last_modified_at"
  ];
  // Gilded
  bool gilded = 9 [
    (devvit.options.trigger_evt_path) = "comment.gilded",
    (devvit.options.im_path) = "comment.gilded"
  ];
  // The comment's score based on the number of upvotes minus the number of downvotes.
  int32 score = 10 [
    (devvit.options.trigger_evt_path) = "comment.score",
    (devvit.options.im_path) = "comment.score",
    (openapi.field_example) = "8"
  ];
  // Permalink of the comment
  string permalink = 11 [
    (devvit.options.trigger_evt_path) = "comment.permalink",
    (devvit.options.im_path) = "comment.permalink",
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "/r/",
    (openapi.field_example) = "/r/RedditEng/comments/1798o2e/comment/k5kbkod/"
  ];
  // Comment element types, which can be animated-gif, img, text, link, or a combination of types, such as  ['animated-gif', 'text', 'link']. Note that animated-gif and img cannot be combined.
  // (Note: This field is blank for COMMENT_EDIT events. Use the element types from the original COMMENT_CREATE event.)
  repeated string element_types = 12 [
    (devvit.options.trigger_evt_path) = "comment.element_types",
    (devvit.options.im_path) = "comment.element_types",
    (openapi.field_example) = "['animated-gif', 'text']"
  ];
  // Media urls from the comment body text.
  // Only media hosted by Reddit or Giphy is currently supported. (Note: This field is only present when the comment body contains an embedded image.)
  repeated string media_urls = 13 [
    (devvit.options.trigger_evt_path) = "comment.media_urls",
    (devvit.options.im_path) = "comment.media_urls",
    (openapi.field_example) = "['https://i.redd.it/7a0ucn4ltzub1.png', 'https://giphy.com/gifs/Vuw9m5wXviFIQ']"
  ];

  // removed fields
  reserved 5, 6;
  reserved "trending_score", "toxicity_score";
}

// Subreddit info
message SubredditFirehose {
  // Id of the subreddit
  string id = 1 [
    (devvit.options.trigger_evt_path) = "subreddit.id",
    (devvit.options.im_path) = "subreddit.id",
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "t5_",
    (openapi.field_example) = "t5_49fkib"
  ];
  // Name of the subreddit
  string name = 2 [
    (devvit.options.trigger_evt_path) = "subreddit.name",
    (devvit.options.im_path) = "subreddit.name",
    (buf.validate.field).required = true,
    (openapi.field_example) = "RedditEng"
  ];
  // Topics associated with the subreddit. If a subreddit has not been classified with a topic yet, this field will contain "Unclassified".
  repeated string topics = 3 [
    (devvit.options.trigger_evt_path) = "subreddit.topics",
    (devvit.options.im_path) = "subreddit.topics",
    (buf.validate.field).required = true,
    (openapi.field_example) = "['Career', 'Programming']"
  ];
  // Do not send
  devvit.reddit.v2alpha.SubredditRating rating = 5 [
    (devvit.options.trigger_evt_path) = "subreddit.rating",
    (devvit.options.im_path) = "subreddit.rating",
    (google.api.field_behavior) = INPUT_ONLY
  ];
  // Subscribers count on the subreddit
  google.protobuf.Int32Value subscribers_count = 6 [
    (devvit.options.trigger_evt_path) = "subreddit.subscribers_count",
    (devvit.options.im_path) = "subreddit.subscribers_count",
    (buf.validate.field).required = true,
    (openapi.field_example) = "9857"
  ];
  // Permalink of the subreddit
  string permalink = 7 [
    (devvit.options.trigger_evt_path) = "subreddit.permalink",
    (devvit.options.im_path) = "subreddit.permalink",
    (buf.validate.field).required = true,
    (buf.validate.field).string.prefix = "/r/",
    (openapi.field_example) = "/r/RedditEng"
  ];

  // If the subreddit has been marked as not-safe-for-work. This will only be present if true.
  bool nsfw = 8 [
    (devvit.options.trigger_evt_path) = "subreddit.nsfw",
    (devvit.options.im_path) = "subreddit.nsfw",
    (openapi.field_example) = "true"
  ];

  // The type of the subreddit: PUBLIC, RESTRICTED, USER;
  devvit.reddit.v2alpha.SubredditType type = 9 [
    (devvit.options.trigger_evt_path) = "subreddit.type",
    (devvit.options.im_path) = "subreddit.type",
    (openapi.field_example) = "PUBLIC"
  ];

  // The title of the subreddit shown in the sidebar
  string title = 10 [
    (devvit.options.trigger_evt_path) = "subreddit.title",
    (devvit.options.im_path) = "subreddit.title",
    (openapi.field_example) = "The Reddit Fanclub"
  ];

  // The description of the subreddit in the sidebar
  string description = 11 [
    (devvit.options.trigger_evt_path) = "subreddit.description",
    (devvit.options.im_path) = "subreddit.description",
    (openapi.field_example) = "This subreddit is dedicated to all Reddit fans of all walks of life. We can discuss Reddit news, events, and more."
  ];

  // removed fields
  reserved 4;
  reserved "trending_score";
}

// User Flair is a tagging system used to distinguish trusted community members or highlight specialized areas of knowledge someone may have. It can also be used in a variety of other creative and fun ways, depending on what suits the community. This is an optional field and subject to user flair present on the subreddit and user choosing to have the flair in the subreddit.
message UserFlairFirehose {
  string text = 1 [
    (devvit.options.trigger_evt_path) = "author.flair.text",
    (openapi.field_example) = "Super Contributor"
  ];
}

// User's info. To protect Reddit employee accounts from targeting or harassment, the user info may be redacted in some cases - e.g. post or comment removals where the post title or comment body is changed to "Removed by Reddit.
message UserFirehose {
  // Id of the user. If the user account was deleted, this field will be `t2_0`.
  string id = 1 [
    (devvit.options.trigger_evt_path) = "author.id",
    (devvit.options.im_path) = "author.id",
    (buf.validate.field).string.prefix = "t2_",
    (openapi.field_example) = "t2_bcutkf4n"
  ];
  // Name of the user. If the user account was deleted, this field will be `[deleted]`.
  string name = 2 [
    (devvit.options.trigger_evt_path) = "author.name",
    (devvit.options.im_path) = "author.name",
    (buf.validate.field).required = true,
    (openapi.field_example) = "sassyshalimar"
  ];
  // The amount of fake internet points a user has earned based on upvotes
  int64 karma = 4 [
    (devvit.options.trigger_evt_path) = "author.karma",
    (devvit.options.im_path) = "author.karma",
    (openapi.field_example) = "'45'"
  ];
  // Url to the user's profile. If the user account was deleted, this field will be `https://www.reddit.com/`.
  string url = 7 [
    (devvit.options.trigger_evt_path) = "author.url",
    (devvit.options.im_path) = "author.url",
    (buf.validate.field).required = true,
    (buf.validate.field).string.uri = true,
    (openapi.field_example) = "https://www.reddit.com/user/sassyshalimar"
  ];
  // Avatar image associated with the user
  string snoovatar_image = 8 [
    (devvit.options.trigger_evt_path) = "author.snoovatar_image",
    (devvit.options.im_path) = "author.snoovatar_image",
    (openapi.field_example) = "https://i.redd.it/snoovatar/avatars/84cb29a7-9219-45e9-a572-eb170ab34c3e.png"
  ];

  optional UserFlairFirehose flair = 9;

  // Icon image associated with the user. This could be the snoovatar image or a custom image the user has set as profile image.
  string icon_image = 10 [
    (devvit.options.trigger_evt_path) = "author.icon_image",
    (devvit.options.im_path) = "author.icon_image",
    (openapi.field_example) = "https://i.redd.it/snoovatar/avatars/84cb29a7-9219-45e9-a572-eb170ab34c3e.png"
  ];

  // User profile "about description"
  string description = 11 [
    (devvit.options.trigger_evt_path) = "author.description",
    (devvit.options.im_path) = "author.description",
    (openapi.field_example) = "Dog lover, foodie, and tech enthusiast."
  ];

  // Whether this user has been banned. This will only be present if true
  bool banned = 13 [
    (devvit.options.trigger_evt_path) = "user.banned",
    (devvit.options.im_path) = "user.banned",
    (openapi.field_example) = "true"
  ];

  // Whether this user has been suspended. This will only be present if true
  bool suspended = 14 [
    (devvit.options.trigger_evt_path) = "user.suspended",
    (devvit.options.im_path) = "user.suspended",
    (openapi.field_example) = "true"
  ];

  // removed fields
  reserved 3, 5, 6;
  reserved "account_age", "community_karma", "reputation_score";
}
