package Api;

smol Loader {
    jsx = 1;
    js = 2;
    ts = 3;
    tsx = 4;
    css = 5;
    file = 6;
    json = 7;
    toml = 8;
    wasm = 9;
    napi = 10;
}

smol FrameworkEntryPointType {
  client = 1;
  server = 2;
  fallback = 3;
}

smol StackFrameScope {
  Eval = 1;
  Module = 2;
  Function = 3;
  Global = 4;
  Wasm = 5;
  Constructor = 6;
}

struct StackFrame {
  string function_name;
  string file;
  StackFramePosition position;
  StackFrameScope scope;
}

struct StackFramePosition {
  int32 source_offset;
  int32 line;
  int32 line_start;
  int32 line_stop;
  int32 column_start;
  int32 column_stop;
  int32 expression_start;
  int32 expression_stop;
}

struct SourceLine {
  int32 line;
  string text;
}

struct StackTrace {
  SourceLine[] source_lines;
  StackFrame[] frames;
}


message JSException {
  string name = 1;
  string message = 2;
  
  uint16 runtime_type = 3;
  uint8 code = 4;

  StackTrace stack = 5;
}

smol FallbackStep {
  ssr_disabled = 1;
  create_vm = 2;
  configure_router = 3;
  configure_defines = 4;
  resolve_entry_point = 5;
  load_entry_point = 6;
  eval_entry_point = 7;
  fetch_event_handler = 8;
}

struct Problems {
  uint16 code;
  string name;

  JSException[] exceptions;
  Log build;
}

struct Router {
  StringMap routes;
  int32 route;
  StringMap params;
}

message FallbackMessageContainer {
  string message = 1;
  Router router = 2;
  FallbackStep reason = 3;
  Problems problems = 4;
  string cwd = 5;
}
 

smol ResolveMode {
  disable = 1;
  lazy = 2;
  dev = 3;
  bundle = 4;
}

smol Platform {
  browser = 1;
  node = 2;
  bun = 3;
  bun_macro = 4;
}

smol CSSInJSBehavior {
  facade = 1;
  facade_onimportcss = 2;
  auto_onimportcss = 3;
}

smol JSXRuntime {
  automatic = 1;
  classic = 2;
  solid = 3;
}

struct JSX {
  string factory;
  JSXRuntime runtime;
  string fragment;
  bool development;

  // Probably react
  string import_source;

  bool react_fast_refresh;
}

struct StringPointer {
  uint32 offset;
  uint32 length;
}

struct JavascriptBundledModule {
  // package-relative path including file extension
  StringPointer path;

  // Source code
  StringPointer code;

  // index into JavascriptBundle.packages
  uint32 package_id;

  // The ESM export is this id ("$" + number.toString(16))
  uint32 id;

  // This lets us efficiently compare strings ignoring the extension
  byte path_extname_length;
}

struct JavascriptBundledPackage {
  StringPointer name;
  StringPointer version;
  uint32 hash;

  uint32 modules_offset;
  uint32 modules_length;
}

struct JavascriptBundle {
  // These are sorted alphabetically so you can do binary search
  JavascriptBundledModule[] modules;
  JavascriptBundledPackage[] packages;
  
  // This is ASCII-encoded so you can send it directly over HTTP
  byte[] etag;

  uint32 generated_at;
  
  // generated by hashing all ${name}@${version} in sorted order
  byte[] app_package_json_dependencies_hash;

  byte[] import_from_name;

  // This is what StringPointer refers to 
  byte[] manifest_string;
}

message JavascriptBundleContainer {
  uint32 bundle_format_version = 1;

  // These go first so if we change JavaScriptBundle we can still read these
  LoadedRouteConfig routes = 3;
  LoadedFramework framework = 2;

  JavascriptBundle bundle = 4;

  // Don't technically need to store this, but it may be helpful as a sanity check
  uint32 code_length = 5;
}

smol ScanDependencyMode {
  app = 1;
  all = 2;
}

smol ModuleImportType {
  import = 1;
  require = 2;
}

struct ModuleImportRecord {
  ModuleImportType kind;
  string path;

  bool dynamic;
}

struct Module {
  string path;
  ModuleImportRecord[] imports;
}

struct StringMap {
  string[] keys;
  string[] values;
}

struct LoaderMap {
  string[] extensions;
  Loader[] loaders;
}

enum DotEnvBehavior {
  disable = 1;
  prefix = 2;
  load_all = 3;
}

message EnvConfig {
  string prefix = 1;
  StringMap defaults = 2;
}

struct LoadedEnvConfig {
  DotEnvBehavior dotenv;

  StringMap defaults;
  string prefix;
}

message FrameworkConfig {
  string package = 1;
  FrameworkEntryPointMessage client = 2;
  FrameworkEntryPointMessage server = 3;
  FrameworkEntryPointMessage fallback = 4;
  bool development = 5;

  CSSInJSBehavior client_css_in_js = 6;
  string display_name = 7;

  StringMap overrideModules = 8;
}

struct FrameworkEntryPoint {
  FrameworkEntryPointType kind;
  string path;
  LoadedEnvConfig env;
}

message FrameworkEntryPointMap {
  FrameworkEntryPoint client = 1;
  FrameworkEntryPoint server = 2;
  FrameworkEntryPoint fallback = 3;
}

message FrameworkEntryPointMessage {
  string path = 1;
  EnvConfig env = 2;
}

struct LoadedFramework {
  string package;
  string display_name;
  bool development;
  FrameworkEntryPointMap entry_points;
  CSSInJSBehavior client_css_in_js;
  StringMap overrideModules;
}

struct LoadedRouteConfig {
  string dir;
  string[] extensions;
  string static_dir;
  string asset_prefix;
}

message RouteConfig {
  string[] dir = 1;
  string[] extensions = 2;
  string static_dir = 3;
  string asset_prefix = 4;
}

message TransformOptions {
  JSX jsx = 1;
  string tsconfig_override = 2;
  ResolveMode resolve = 3;

  string origin = 4;
  string absolute_working_dir = 5;

  StringMap define = 6;

  bool preserve_symlinks = 7;

  string[] entry_points = 8;
  bool write = 9;

  string[] inject = 10;
  string output_dir = 11;

  string[] external = 12;

  LoaderMap loaders = 13;

  string[] main_fields = 14;
  Platform platform = 15;

  bool serve = 16;

  string[] extension_order = 17;

  bool generate_node_module_bundle = 18;

  string node_modules_bundle_path = 19;
  string node_modules_bundle_path_server = 20;

  FrameworkConfig framework = 21;
  RouteConfig router = 22;
  bool no_summary = 23;

  bool disable_hmr = 24;

  uint16 port = 25;
  MessageLevel logLevel = 26;
  SourceMapMode source_map = 27;
}

smol SourceMapMode {
  inline_into_file = 1;
  external = 2;
}

struct FileHandle {
  string path;
  uint size;
  uint fd; 
}

message Transform {
  FileHandle handle = 1;
  string path = 2;
  byte[] contents = 3;

  Loader loader = 4;
  TransformOptions options = 5;
}

message Scan {
  string path = 1;
  byte[] contents = 2;
  Loader loader = 3;
}

struct ScanResult {
    string[] exports;
    ScannedImport[] imports;
}

struct ScannedImport {
  string path;
  ImportKind kind;
}

smol ImportKind {
  entry_point = 1;
  stmt = 2;
  require = 3;
  dynamic = 4;
  require_resolve = 5;
  at = 6;
  url = 7;
  internal = 8;
}


enum TransformResponseStatus {
  success = 1;
  fail = 2;
}

struct OutputFile {
  byte[] data;
  string path;
}

struct TransformResponse {
  TransformResponseStatus status;
  OutputFile[] files;
  Message[] errors;
}

enum MessageLevel {
  err = 1;
  warn  =2;
  note = 3;
  info = 4;
  debug = 5;
}

struct Location {
  string file;
  string namespace;
  int32 line;
  int32 column;
  string line_text;
  string suggestion;
  uint offset;
}

message MessageData {
  string text = 1;
   Location location = 2;
}



message MessageMeta {
  string resolve = 1;
  bool build = 2;
}

struct Message {
  MessageLevel level;
  MessageData data;
  MessageData[] notes;
  MessageMeta on;
}

struct Log {
  uint32 warnings;
  uint32 errors;
  Message[] msgs;
}


smol Reloader {
  disable = 1;
  // equivalent of CMD + R 
  live = 2;
  // React Fast Refresh
  fast_refresh = 3;
}

// The WebSocket protocol
// Server: "hey, this file changed. Does anyone want it?"
// Browser: *checks array* "uhh yeah, ok. rebuild that for me"
// Server: "here u go"
// This makes the client responsible for tracking which files it needs to listen for.
// From a server perspective, this means the filesystem watching thread can send the same WebSocket message
// to every client, which is good for performance. It means if you have 5 tabs open it won't really be different than one tab
// The clients can just ignore files they don't care about
smol WebsocketMessageKind {
  welcome = 1;
  file_change_notification = 2;
  build_success = 3;
  build_fail = 4;
  manifest_success = 5;
  manifest_fail = 6;
  resolve_file = 7;
  file_change_notification_with_hint = 8;
}

smol WebsocketCommandKind {
  build = 1;
  manifest = 2;
  build_with_file_path = 3;
}

// Each websocket message has two messages in it!
// This is the first.
struct WebsocketMessage {
  uint32 timestamp;
  WebsocketMessageKind kind;
}

// This is the first.
struct WebsocketMessageWelcome {
  uint32 epoch;
  Reloader javascriptReloader;
  string cwd;
  string assetPrefix;
}

struct WebsocketMessageFileChangeNotification {
  uint32 id;
  Loader loader;
}

struct WebsocketCommand {
  WebsocketCommandKind kind;
  uint32 timestamp;
}

// The timestamp is used for client-side deduping
struct WebsocketCommandBuild {
  uint32 id;
}

struct WebsocketCommandManifest {
  uint32 id;
}

// We copy the module_path here incase they don't already have it
struct WebsocketMessageBuildSuccess {
  uint32 id;
  uint32 from_timestamp;

  Loader loader;
  string module_path;
  
  // This is the length of the blob that immediately follows this message.
  uint32 blob_length;
}

struct WebsocketMessageBuildFailure {
  uint32 id;
  uint32 from_timestamp;
  Loader loader;

  string module_path;
  Log log;
}

struct WebsocketCommandBuildWithFilePath {
  uint32 id;
  string file_path;
}

struct WebsocketMessageResolveID {
  uint32 id;
}

struct NPMRegistry {
  string url;
  string username;
  string password;
  string token;
}

struct NPMRegistryMap {
  string[] scopes;
  NPMRegistry[] registries;
}

message BunInstall {
  NPMRegistry default_registry = 1;
  NPMRegistryMap scoped = 2;
  string lockfile_path = 3;
  string save_lockfile_path = 4;
  string cache_directory = 5;
  bool dry_run = 6;
  bool force = 7;
  bool save_dev = 8;
  bool save_optional = 9;
  bool save_peer = 10;
  bool save_lockfile = 11;
  bool production = 12;
  bool save_yarn_lockfile = 13;
  string[] native_bin_links = 14;

  bool disable_cache = 15;
  bool disable_manifest_cache = 16;
  string global_dir = 17;
  string global_bin_dir = 18;
}
