syntax = "proto3";

package devvit.ui.events.v1alpha;

import "devvit/ui/effect_types/v1alpha/app_permission.proto";
import "devvit/ui/effect_types/v1alpha/create_order.proto";
import "devvit/ui/effect_types/v1alpha/show_form.proto";
import "devvit/ui/effect_types/v1alpha/show_toast.proto";
import "devvit/ui/effects/v1alpha/realtime_subscriptions.proto";
import "devvit/ui/events/v1alpha/web_view.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/wrappers.proto";

option go_package = "github.snooguts.net/reddit/reddit-devplatform-monorepo/go-common/generated/protos/types/devvit/ui/events/v1alpha";
option java_package = "com.reddit.devvit.ui.events.v1alpha";

// This is set when we want to map events to a specific runtime, examples:
// [1] incoming realtime messages on a websocket connection
// [2] keydown events in a text input block
// Both are intended to be run only on local runtime
enum UIEventScope {
  ALL = 0;
  LOCAL = 1;
  REMOTE = 2;
}

// Blocks events. Don't add Webbit events here.
message UIEvent {
  option deprecated = true;

  oneof event {
    devvit.ui.effects.v1alpha.RealtimeSubscriptionEvent realtime_event = 2;
    devvit.ui.effect_types.v1alpha.FormSubmittedEvent form_submitted = 3;
    devvit.ui.effect_types.v1alpha.OrderResultEvent order_result = 19;
    devvit.ui.effect_types.v1alpha.ToastActionEvent toast_action = 4;
    UserAction user_action = 6;
    AsyncRequest async_request = 7;
    AsyncResponse async_response = 8;
    TimerEvent timer = 12;
    BlockingRenderEvent blocking = 13;
    ResizeEvent resize = 14;
    WebViewEvent web_view = 20;
    devvit.ui.effect_types.v1alpha.FormCanceledEvent form_canceled = 21;
    devvit.ui.effect_types.v1alpha.ConsentStatusEvent consent_status = 23;
  }

  // If an event is async, it can be fired in parallel with other events.  Async events
  // are not allowed to mutate state.  Any state mutations they attempt would be ignored.
  // If they want to communicate something back to the state, they need to pass a message via
  // effects.
  google.protobuf.BoolValue async = 15;

  // The id of a the hook that should respond to this event
  google.protobuf.StringValue hook = 10;

  // Signals if this event should be sent to the front (true) or back of the queue (false)
  google.protobuf.BoolValue retry = 17;

  optional UIEventScope scope = 18;

  // Deprecate remote_only boolean field which is intended
  // for circuit-broken or fetchy events that are known to only
  // work on the remote runtime.
  reserved 16;
  reserved "remote_only";
}

/**
 * Server-side rendering event.  This is a signal to the server that it should
 * wait for all of the promises to resolve before sending the response.
 *
 * The default behavior is to send the response as soon as possible, and then
 * stream in the rest of the data as it becomes available.  This is usually
 * slower on first load, but faster on subsequent loads.
 *
 * On first load, the server is usually close to the database, so the
 * back-and-forth is relatively cheap compared to asking the client to initiate
 * a bunch of waterfalling requests to the server.
 */
message BlockingRenderEvent {}

/**
 *  Signals to the server of device/client-side surface size changes
 */
message ResizeEvent {}

/**
 * There's no data sent with the timer (yet?).  Just knowing to fire it is
 * enough.
 */
message TimerEvent {}

message AsyncError {
  string message = 1;

  /**
   * Typically a stack trace
   */
  string details = 2;
}

message AsyncRequest {
  string request_id = 1;
  google.protobuf.Struct data = 2;
}

message AsyncResponse {
  string request_id = 1;
  google.protobuf.Struct data = 2;
  AsyncError error = 3;
}

message UserAction {
  string action_id = 1;
  google.protobuf.Struct data = 2;
}
