syntax = "proto3";

package devvit.runtime;

import "devvit/runtime/serializable.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "reddit/devvit/app_permission/v1/app_permission.proto";

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

// Bundle or plugin configuration. This config is usually set by Config.init()
// but some plugins may configure differently.
message ActorSpec {
  // Bundle or plugin (PLUGIN_APP_NAME) name. This should be unique across app
  // actors. Usually just "main".
  string name = 1;
  // Bundle or plugin (PLUGIN_OWNER) owner. Eg, "spez".
  string owner = 2;
  // Bundle or plugin version. Eg, 1.2.3 or 1.2.3.0.
  string version = 3;
}

// See also LinkedBundle.
enum LinkedBundleTargetPlatform {
  // A LinkedBundle for browser runtimes.
  BROWSER = 0;
  // A LinkedBundle for V8 runtimes.
  V8 = 1;
  // An API definition that cannot be executed. This is a LinkedBundle with no
  // code and no dependencies.
  SKINNY = 2;
}

// Permitted and forbidden execution environments.
message LocationFilter {
  repeated string allow = 1;
  repeated string deny = 2;
}

message Permissions {
  // List of fetch domains requested by the app.
  repeated string requested_fetch_domains = 1;
  // List of scopes that dictate what the app can run on behalf of the user.
  repeated .reddit.devvit.app_permission.v1.Scope as_user_scopes = 2;
}

// A provided implementation specified by a Bundle or plugin. See
// Config.provides() and DependencySpec.provides.
message PackageSpec {
  ActorSpec actor = 1;
  // The version provided.
  devvit.runtime.SerializableServiceDefinition definition = 2;
  LocationFilter locations = 3;
  repeated string partitions_by = 4;
}

// A dependency use requirement specified by a Bundle or plugin. See
// Config.use() and DependencySpec.uses. Dependencies may resolve to different
// implementations in different execution environments.
message PackageQuery {
  // Limit resolution to a Bundle or plugins (PLUGIN_APP_NAME). Eg,
  // com.devvit.example/foo.
  google.protobuf.StringValue name = 1;
  // Limit resolution to owner. Eg, com.reddit.
  google.protobuf.StringValue owner = 2;
  // Limit resolution to type. No slashes. Eg,
  // "devvit.plugin.logger.Logger". See Definition.fullName.
  string type_name = 3;
  // Limit resolution to versions. Eg, ">=0" or "1.0.0".
  google.protobuf.StringValue versions = 4;
}

// Dependencies offered and required by a Bundle or plugin. See Config.export().
message DependencySpec {
  ActorSpec actor = 1;
  // Actor hostname. This may be a plugin or a user actor. Eg,
  // "fd23937c-2891-44ed-a66c-5277265cfd54.pixelary-game.main.devvit-gateway.reddit.com":
  //
  // | Prisma Installation.id               | devvit.yaml app name / slug | ActorSpec.name |                           |
  // | ------------------------------------ | --------------------------- | -------------- | ------------------------- |
  // | fd23937c-2891-44ed-a66c-5277265cfd54 | pixelary-game               | main           | devvit-gateway.reddit.com |
  //
  // Which corresponds to the V8 LinkedBundle at
  // https://devvit-gateway.reddit.com/bundles/fd23937c-2891-44ed-a66c-5277265cfd54/main/0.0.8-359.
  //
  // Multi-actor apps are deprecated so app name is usually what's most
  // important. Plugins are simpler. Eg, "http.plugins.local".
  string hostname = 2;
  repeated PackageSpec provides = 3;
  repeated PackageQuery uses = 4;
  repeated Permissions permissions = 5;
}

// A fully built actor (either a user app or plugin). This resolved Bundle is
// ready for execution by the runtime.
message LinkedBundle {
  ActorSpec actor = 1;
  // Compiled bundle or plugin code. A hostname and empty code implies that the
  // runtime should resolve this as a remote actor accessible over the network;
  // this is empty for "skinny bundles" (AKA Gateway bundles).
  string code = 2;
  // Source map accompanying code. This should be a JSON string containing the
  // source map bundle accompanying the code. Not required.
  google.protobuf.StringValue source_map = 10;
  // Actor hostname. This may be a plugin or a user. See DependencySpec.hostname
  // which Community Portal copies here.
  string hostname = 3;
  repeated SerializableServiceDefinition provides = 4;
  // True dependencies. This is empty for skinny bundles which describe the
  // input / output API only. They have no code and cannot be executed so their
  // dependencies are not needed.
  repeated LinkedBundle uses = 5;
  // Optional information about the environment the code was built in. Outdated
  // dependencies may indicate an invalid build.
  BuildInfo build_info = 6;

  // Where did the uploaded ./assets folder land?  This is a URL to the FileSystem
  // as JSON that contains the assets.
  google.protobuf.StringValue assets_url = 7 [deprecated = true];

  // This map is used to resolve relative asset paths to URLs. The key
  // is the path to the asset, and the value is the URL to the asset.
  // e.g. `"images/example.png": "https://i.redd.it/example.png"`. May include
  // the app icon as `$devvit_icon.png`.
  map<string, string> assets = 8;

  // This map is used to resolve assets for the webview block. These are uploaded
  // to S3 and servable as static contents from CDN.
  //
  // For historical reasons, the key is the developer's local asset path (e.g. "images/example.png"),
  // and the value is `<app ID>/<asset path>`, e.g. "fd23937c-2891-44ed-a66c-5277265cfd54/images/example.png".
  // These should all be served from the webview domain at the asset path (e.g. "GET /images/example.png").
  map<string, string> webview_assets = 9;

  // This map is used to resolve a sku to a UUID used by the Payment platform to identify the product
  map<string, string> products = 11;
  // Standalone server implementation, without Blocks rendering or "Devvit Classic".
  // If provided, this code is expected to be an entry point for an HTTP server that can
  // handle requests at process.env.WEBBIT_PORT. Present in server (UNIVERSAL)
  // bundles only.
  ServerBundle server = 12;
}

// This represents a standalone server implementation that starts an HTTP server
// to execute on Devvit's compute platform.
message ServerBundle {
  // A compiled bundle of code to be executed as-is. Listening on the server port
  // for HTTP requests should occur through side effects of evaluating this code.
  string code = 1;
  // Source map accompanying |code|, used for better stack traces when erorrs occur.
  // Not required. For specification, see: https://tc39.es/ecma426/
  string source_map = 2;
}

enum TargetRuntime {
  // Server-only as of 2025-06-04 or so.
  UNIVERSAL = 0;
  CLIENT = 1;
}

// Detail about the tooling used to construct a LinkedBundle.
message BuildInfo {
  // When the LinkedBundle was built.
  google.protobuf.Timestamp created = 1;
  // Notable package.json versions recorded at build time. Eg:
  //
  //   @devvit/protos → 1.2.3
  //   @devvit/public-api → 4.5.6
  //   node → 7.8.9
  map<string, string> dependencies = 2;
  // Where the bundle can be executed
  TargetRuntime target_runtime = 3;
}
