// Copyright 2018 The Nakama Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * The Nakama server RPC protocol for games and apps.
 */
syntax = "proto3";

package nakama.api;

import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "protoc-gen-swagger/options/annotations.proto";

option go_package = "api";

option java_multiple_files = true;
option java_outer_classname = "NakamaApi";
option java_package = "com.heroiclabs.nakama.api";

option csharp_namespace = "Nakama";

option objc_class_prefix = "NKPB";

// NOTE: we will no longer return server time.
// NOTE: we will implement a logout message later.
// NOTE: unlink will behave exactly like link/register now.
// NOTE: last_online_at is now online in user messages.
// NOTE: metadata will not be modifiable in user, self, and group messages.
// NOTE: group state will become an enum. Join will now be JOIN_REQUEST.
// NOTE: topic will now be known as channel.
// NOTE: we will flatten realtime messages to be simpler as JSON inputs.
// NOTE: remove bucket field and concept from server.
// NOTE: remove expires_at field and concept from server.
// NOTE: leaderboard sort field will become an enum.
// NOTE: we will use plural to describe batched results and list to describe results with a cursor.
// NOTE: TLeaderboardsRecordsFetch should return the current user's records from 1+ leaderboard ids.
// NOTE: add conditional get support to storage fetch operations.
// NOTE: record field in storage objects will be renamed to id. We should also refer to them as "storage objects" in docs.
// NOTE: a user's handle will now be called "username" (and "nickname" will be non-unique).
// NOTE: user records will now contain device messages which will store device specific details.
// NOTE: all timestamps will use UNIX time (i.e. in seconds).
// NOTE: we'll use a healthcheck on a separate port for GCLB with our GRPC server.
// NOTE: we'll add nk.timemillis() as a helper for millisecond resolution to Lua runtime.
// NOTE: Facebook, (and maybe Google, Game Center, and Steam) will belong on a user not the self message.
// NOTE: self message will now be called account.
// NOTE: add batch friend operations.
// NOTE: all batch operations will be limited to 100 results.
// NOTE: all list operations will return 1 by default and start at 1 up to 100 results.
// NOTE: before/after hook names will not be downcased by default.

option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {
  info: {
    title: "Nakama API v2";
    version: "2.0";
    contact: {
      name: "The Nakama Authors & Contributors";
      url: "https://github.com/heroiclabs/nakama";
      email: "hello@heroiclabs.com";
    };
  };
  external_docs: {
    url: "https://heroiclabs.com/docs";
    description: "Nakama server documentation";
  }
  schemes: HTTP;
  consumes: "application/json";
  produces: "application/json";
};

/**
 * The Nakama RPC protocol service built with GRPC.
 */
service Nakama {
  // Add friends by ID or username to a user's account.
  rpc AddFriends (AddFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).post = "/v2/friend";
  }

  // Authenticate a user with a custom id against the server.
  rpc AuthenticateCustom (AuthenticateCustomRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/custom",
      body: "account"
    };
  }

  // Authenticate a user with a device id against the server.
  rpc AuthenticateDevice (AuthenticateDeviceRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/device",
      body: "account"
    };
  }

  // Authenticate a user with an email+password against the server.
  rpc AuthenticateEmail (AuthenticateEmailRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/email",
      body: "account"
    };
  }

  // Authenticate a user with a Facebook OAuth token against the server.
  rpc AuthenticateFacebook (AuthenticateFacebookRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/facebook",
      body: "account"
    };
  }

  // Authenticate a user with Apple's GameCenter against the server.
  rpc AuthenticateGameCenter (AuthenticateGameCenterRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/gamecenter",
      body: "account"
    };
  }

  // Authenticate a user with Google against the server.
  rpc AuthenticateGoogle (AuthenticateGoogleRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/google",
      body: "account"
    };
  }

  // Authenticate a user with Steam against the server.
  rpc AuthenticateSteam (AuthenticateSteamRequest) returns (Session) {
    option (google.api.http) = {
      post: "/v2/account/authenticate/steam",
      body: "account"
    };
  }

  // Block one or more users by ID or username.
  rpc BlockFriends (BlockFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/friend/block"
    };
  }

  // Create one or more new groups with the current user as the owner.
  rpc CreateGroup (CreateGroupsRequest) returns (Groups) {
    option (google.api.http) = {
      post: "/v2/group",
      body: "*"
    };
  }

  // Delete one or more users by ID or username.
  rpc DeleteFriends (DeleteFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/friend";
  }

  // Delete one or more users by ID or username.
  rpc DeleteNotifications (DeleteNotificationsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/notification";
  }

  // Delete one or more objects by ID or username.
  rpc DeleteStorageObjects (DeleteStorageObjectsRequest) returns (google.protobuf.Empty) {
    option (google.api.http).delete = "/v2/storage";
  }

  // Fetch the current user's account.
  rpc GetAccount (google.protobuf.Empty) returns (Account) {
    option (google.api.http).get = "/v2/account";
  }

  // Fetch zero or more users by ID and/or username.
  rpc GetUsers (GetUsersRequest) returns (Users) {
    option (google.api.http).get = "/v2/user";
  }

  // A healthcheck which load balancers can use to check the service.
  rpc Healthcheck (google.protobuf.Empty) returns (google.protobuf.Empty) {
    option (google.api.http).get = "/healthcheck";
  }

  // Import Facebook friends and add them to a user's account.
  rpc ImportFacebookFriends (ImportFacebookFriendsRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/friend/facebook",
      body: "account"
    };
  }

  // Add a custom ID to the social profiles on the current user's account.
  rpc LinkCustom (AccountCustom) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/custom",
      body: "*"
    };
  }

  // Add a device ID to the social profiles on the current user's account.
  rpc LinkDevice (AccountDevice) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/device",
      body: "*"
    };
  }

  // Add an email+password to the social profiles on the current user's account.
  rpc LinkEmail (AccountEmail) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/email",
      body: "*"
    };
  }

  // Add Facebook to the social profiles on the current user's account.
  rpc LinkFacebook (LinkFacebookRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/facebook",
      body: "account"
    };
  }

  // Add Apple's GameCenter to the social profiles on the current user's account.
  rpc LinkGameCenter (AccountGameCenter) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/gamecenter",
      body: "*"
    };
  }

  // Add Google to the social profiles on the current user's account.
  rpc LinkGoogle (AccountGoogle) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/google",
      body: "*"
    };
  }

  // Add Steam to the social profiles on the current user's account.
  rpc LinkSteam (AccountSteam) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/link/steam",
      body: "*"
    };
  }

  // List all friends for the current user.
  rpc ListFriends (google.protobuf.Empty) returns (Friends) {
    option (google.api.http).get = "/v2/friend";
  }

  // Fetch list of running matches.
  rpc ListMatches (ListMatchesRequest) returns (MatchList) {
    option (google.api.http).get = "/v2/match";
  }

  // Fetch list of notifications.
  rpc ListNotifications (ListNotificationsRequest) returns (NotificationList) {
    option (google.api.http).get = "/v2/notification";
  }

  // List collections of storage objects.
  rpc ListStorageObjects (ListStorageObjectsRequest) returns (StorageObjectList) {
    option (google.api.http) = {
      get: "/v2/storage/{collection}",
      additional_bindings {
        get: "/v2/storage/{collection}/{user_id}"
      }
    };
  }

  // Get storage objects.
  rpc ReadStorageObjects (ReadStorageObjectsRequest) returns (StorageObjects) {
    option (google.api.http) = {
      post: "/v2/storage",
      body: "*"
    };
  }

  // Execute a Lua function on the server.
  rpc RpcFunc (Rpc) returns (Rpc) {
    option (google.api.http) = {
      post: "/v2/rpc/{id}",
      body: "payload",
      additional_bindings {
        get: "/v2/rpc/{id}"
      }
    };
  }

  // Remove the custom ID from the social profiles on the current user's account.
  rpc UnlinkCustom (AccountCustom) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/custom",
      body: "*"
    };
  }

  // Remove the device ID from the social profiles on the current user's account.
  rpc UnlinkDevice (AccountDevice) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/device",
      body: "*"
    };
  }

  // Remove the email+password from the social profiles on the current user's account.
  rpc UnlinkEmail (AccountEmail) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/email",
      body: "*"
    };
  }

  // Remove Facebook from the social profiles on the current user's account.
  rpc UnlinkFacebook (AccountFacebook) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/facebook",
      body: "*"
    };
  }

  // Remove Apple's GameCenter from the social profiles on the current user's account.
  rpc UnlinkGameCenter (AccountGameCenter) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/gamecenter",
      body: "*"
    };
  }

  // Remove Google from the social profiles on the current user's account.
  rpc UnlinkGoogle (AccountGoogle) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/google",
      body: "*"
    };
  }

  // Remove Steam from the social profiles on the current user's account.
  rpc UnlinkSteam (AccountSteam) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      post: "/v2/account/unlink/steam",
      body: "*"
    };
  }

  // Update fields in the current user's account.
  rpc UpdateAccount (UpdateAccountRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      put: "/v2/account",
      body: "*"
    };
  }

  // Write objects into the storage engine.
  rpc WriteStorageObjects (WriteStorageObjectsRequest) returns (StorageObjectAcks) {
    option (google.api.http) = {
      put: "/v2/storage",
      body: "*"
    };
  }
}

// A user with additional account details. Always the current user.
message Account {
  // The user object.
  User user = 1;
  // The user's wallet data.
  string wallet = 2;
  // The email address of the user.
  string email = 3;
  // The devices which belong to the user's account.
  repeated AccountDevice devices = 4;
  // The custom id in the user's account.
  string custom_id = 5;
  // The UNIX time when the user's email was verified.
  google.protobuf.Timestamp verify_time = 6;
}

// Send a custom ID to the server. Used with authenticate/link/unlink.
message AccountCustom {
  // A custom identifier.
  string id = 1;
}

// Send a device to the server. Used with authenticate/link/unlink and user.
message AccountDevice {
  // A device identifier. Should be obtained by a platform-specific device API.
  string id = 1;
}

// Send an email with password to the server. Used with authenticate/link/unlink.
message AccountEmail {
  // A valid RFC-5322 email address.
  string email = 1;
  // A password for the user account.
  string password = 2; // Ignored with unlink operations.
}

// Send a Facebook token to the server. Used with authenticate/link/unlink.
message AccountFacebook {
  // The OAuth token received from Facebook to access their profile API.
  string token = 1;
}

// Send Apple's Game Center account credentials to the server. Used with authenticate/link/unlink.
message AccountGameCenter {
  // https://developer.apple.com/documentation/gamekit/gklocalplayer/1515407-generateidentityverificationsign

  // Player ID (generated by GameCenter).
  string player_id = 1;
  // Bundle ID (generated by GameCenter).
  string bundle_id = 2;
  // Time since UNIX epoch when the signature was created.
  int64 timestamp_seconds = 3;
  // A random "NSString" used to compute the hash and keep it randomized.
  string salt = 4;
  // The verification signature data generated.
  string signature = 5;
  // The URL for the public encryption key.
  string public_key_url = 6;
}

// Send a Google token to the server. Used with authenticate/link/unlink.
message AccountGoogle {
  // The OAuth token received from Google to access their profile API.
  string token = 1;
}

// Send a Steam token to the server. Used with authenticate/link/unlink.
message AccountSteam {
  // The account token received from Steam to access their profile API.
  string token = 1;
}

// Add one or more friends to the current user.
message AddFriendsRequest {
  // The account id of a user.
  repeated string ids = 1;
  // The account username of a user.
  repeated string usernames = 2;
}

// Authenticate against the server with a custom ID.
message AuthenticateCustomRequest {
  // The custom account details.
  AccountCustom account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
}

// Authenticate against the server with a device ID.
message AuthenticateDeviceRequest {
  // The device account details.
  AccountDevice account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
}

// Authenticate against the server with email+password.
message AuthenticateEmailRequest {
  // The email account details.
  AccountEmail account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
}

// Authenticate against the server with Facebook.
message AuthenticateFacebookRequest {
  // The Facebook account details.
  AccountFacebook account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
  // Import Facebook friends for the user.
  google.protobuf.BoolValue import = 4;
}

// Authenticate against the server with Apple's Game Center.
message AuthenticateGameCenterRequest {
  // The Game Center account details.
  AccountGameCenter account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
}

// Authenticate against the server with Google.
message AuthenticateGoogleRequest {
  // The Google account details.
  AccountGoogle account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
}

// Authenticate against the server with Steam.
message AuthenticateSteamRequest {
  // The Steam account details.
  AccountSteam account = 1;
  // Register the account if the user does not already exist.
  google.protobuf.BoolValue create = 2;
  // Set the username on the account at register. Must be unique.
  string username = 3;
}

// Block one or more friends for the current user.
message BlockFriendsRequest {
  // The account id of a user.
  repeated string ids = 1;
  // The account username of a user.
  repeated string usernames = 2;
}

// An identifier for a realtime chat channel.
message ChannelId {
  // The type of chat channel.
  enum Type {
    // Default case. Assumed as ROOM type.
    TYPE_UNSPECIFIED = 0;
    // A room which anyone can join to chat.
    ROOM = 1;
    // A private channel for 1-on-1 chat.
    DIRECT_MESSAGE = 2;
    // A channel for group chat.
    GROUP = 3;
  }

  // The identifier for the realtime channel.
  string id = 1;
  // The type of the chat channel.
  int32 type = 2; // one of "ChannelId.Type".
}

// Create one or more groups with the current user as owner.
message CreateGroupsRequest {
  // A group to create.
  message NewGroup {
    // A unique name for the group.
    string name = 1;
    // A description for the group.
    string description = 2;
    // The language expected to be a tag which follows the BCP-47 spec.
    string lang_tag = 3;
    // Additional information stored as a JSON object.
    string metadata = 4;
    // A URL for an avatar image.
    string avatar_url = 5;
    // Mark a group as private where only admins can accept members.
    bool private = 6;
  }

  // The Group objects to create.
  repeated NewGroup groups = 1;
}

// Delete one or more friends for the current user.
message DeleteFriendsRequest {
  // The account id of a user.
  repeated string ids = 1;
  // The account username of a user.
  repeated string usernames = 2;
}

// Delete one or more notifications for the current user.
message DeleteNotificationsRequest {
  // The id of notifications.
  repeated string ids = 1;
}

// Storage objects to delete.
message DeleteStorageObjectId {
  // The collection which stores the object.
  string collection = 1;
  // The key of the object within the collection.
  string key = 2;
  // The version hash of the object.
  string version = 3;
}

// Batch delete storage objects.
message DeleteStorageObjectsRequest {
  // Batch of storage objects.
  repeated DeleteStorageObjectId objectIds = 1;
}

// A friend of a user.
message Friend {
  // The friendship status.
  enum State {
    // Default case. Assumed as FRIEND state.
    STATE_UNSPECIFIED = 0;
    // The user is a friend of the current user.
    FRIEND = 1;
    // The user has sent an invite to the current user.
    INVITE_SENT = 2;
    // The current user has sent an invite to this user.
    INVITE_RECEIVED = 3;
    // The current user has blocked this user.
    BLOCKED = 4;
  }

  // The user object.
  User user = 1;
  // The friend status.
  int32 state = 2; // one of "Friend.State".
}

// A collection of zero or more friends of the user.
message Friends {
  // The Friend objects.
  repeated Friend friends = 1;
}

// Fetch a batch of zero or more users from the server.
message GetUsersRequest {
  // The account id of a user.
  repeated string ids = 1;
  // The account username of a user.
  repeated string usernames = 2;
  // The Facebook ID of a user.
  repeated string facebook_ids = 3;
}

// A group in the server.
message Group {
  // The id of a group.
  string id = 1;
  // The id of the user who created the group.
  string creator_id = 2;
  // The unique name of the group.
  string name = 3;
  // A description for the group.
  string description = 4;
  // The language expected to be a tag which follows the BCP-47 spec.
  string lang_tag = 5;
  // Additional information stored as a JSON object.
  string metadata = 6;
  // A URL for an avatar image.
  string avatar_url = 7;
  // Mark a group as private where only admins can accept members.
  bool private = 8;
  // The current count of all members in the group.
  int32 count = 9;
  // The UNIX time when the group was created.
  google.protobuf.Timestamp create_time = 10;
  // The UNIX time when the group was last updated.
  google.protobuf.Timestamp update_time = 11;
}

// A collection of zero or more groups.
message Groups {
  // The Group objects.
  repeated Group groups = 1;
}

// Import Facebook friends into the current user's account.
message ImportFacebookFriendsRequest {
  // The Facebook account details.
  AccountFacebook account = 1;
  // Reset the current user's friends list.
  google.protobuf.BoolValue reset = 2;
}

// Link Facebook to the current user's account.
message LinkFacebookRequest {
  // The Facebook account details.
  AccountFacebook account = 1;
  // Import Facebook friends for the user.
  google.protobuf.BoolValue import = 4;
}

message ListMatchesRequest {
  // Limit the number of returned matches.
  google.protobuf.Int32Value limit = 1;
  // Authoritative or relayed matches.
  google.protobuf.BoolValue authoritative = 2;
  // Label filter.
  google.protobuf.StringValue label = 3;
  // Minimum user count.
  google.protobuf.Int32Value min_size = 4;
  // Maximum user count.
  google.protobuf.Int32Value max_size = 5;
}

// Get a list of unexpired notifications.
message ListNotificationsRequest {
  // The number of notifications to get. Between 1 and 100.
  google.protobuf.Int32Value limit = 1;
  // A cursor to page through notifications. May be cached by clients to get from point in time forwards.
  string cacheable_cursor = 2; // value from NotificationList.cacheable_cursor.
}

// List storage objects by user ID or collection or both.
message ListStorageObjectsRequest {
  // ID of the user.
  string user_id = 1;
  // The collection which stores the object.
  string collection = 2;
  // The number of storage objects to list. Between 1 and 100.
  google.protobuf.Int32Value limit = 3;
  // The cursor to page through results from.
  string cursor = 4; // value from StorageObjectList.cursor.
}

// Represents a realtime match.
message Match {
  // The ID of the match, can be used to join.
  string match_id = 1;
  // True if it's an server-managed authoritative match, false otherwise.
  bool authoritative = 2;
  // Match label, if any.
  google.protobuf.StringValue label = 3;
  // Current number of users in the match.
  int32 size = 4;
}

// A list of realtime matches.
message MatchList {
  // A number of matches corresponding to a list operation.
  repeated Match matches = 1;
}

// A notification in the server.
message Notification {
  // ID of the Notification.
  string id = 1;
  // Subject of the notification.
  string subject = 2;
  // Content of the notification in JSON.
  string content = 3;
  // Category code for this notification.
  int32 code = 4;
  // ID of the sender, if a user. Otherwise 'null'.
  string sender_id = 5;
  // The UNIX time when the notification was created.
  google.protobuf.Timestamp create_time = 6;
  // True if this notification was persisted to the database.
  bool persistent = 7;
}

// A collection of zero or more notifications.
message NotificationList {
  // Collection of notifications.
  repeated Notification notifications = 1;
  // Use this cursor to paginate notifications. Cache this to catch up to new notifications.
  string cacheable_cursor = 2;
}

// Storage objects to get.
message ReadStorageObjectId {
  // The collection which stores the object.
  string collection = 1;
  // The key of the object within the collection.
  string key = 2;
  // The user owner of the object.
  string user_id = 3;
}

// Batch get storage objects.
message ReadStorageObjectsRequest {
  // Batch of storage objects.
  repeated ReadStorageObjectId objectIds = 1;
}

// Execute an Lua function on the server.
message Rpc {
  // The identifier of the function.
  string id = 1;
  // The payload of the function which must be a JSON object.
  string payload = 2;
  // The authentication key used when executed as a non-client HTTP request.
  string http_key = 3;
}

// A user's session used to authenticate messages.
message Session {
  // Authentication credentials.
  string token = 1;
  // rUDP specific authentication credentials.
  string udp_token = 2; // TODO(zyro): will we remove it?
}

// The read access permissions for a storage object.
enum StoragePermissionRead {
  // Default case. Assumed as OWNER_READ permission.
  STORAGE_PERMISSION_READ_UNSPECIFIED = 0;
  // The object does not have client read permissions.
  NO_READ = 1;
  // The object may be read by the user owner.
  OWNER_READ = 2;
  // The object may be read by any user.
  PUBLIC_READ = 3;
}

// The write access permission for a storage object.
enum StoragePermissionWrite {
  // Default case. Assumed as OWNER_WRITE permission.
  STORAGE_PERMISSION_WRITE_UNSPECIFIED = 0;
  // The object does not have client write permissions.
  NO_WRITE = 1;
  // The object may be written by the user owner.
  OWNER_WRITE = 2;
}

// An object within the storage engine.
message StorageObject {
  // The collection which stores the object.
  string collection = 1;
  // The key of the object within the collection.
  string key = 2;
  // The user owner of the object.
  string user_id = 3;
  // The value of the object.
  string value = 4;
  // The version hash of the object.
  string version = 5;
  // The read access permissions for the object.
  int32 permission_read = 6;
  // The write access permissions for the object.
  int32 permission_write = 7;
  // The UNIX time when the object was created.
  google.protobuf.Timestamp create_time = 8;
  // The UNIX time when the object was last updated.
  google.protobuf.Timestamp update_time = 9;
}

// A storage acknowledgement.
message StorageObjectAck {
  // The collection which stores the object.
  string collection = 1;
  // The key of the object within the collection.
  string key = 2;
  // The version hash of the object.
  string version = 3;
}

// Batch of acknowledgements for the storage object write.
message StorageObjectAcks {
  // Batch of storage write acknowledgements.
  repeated StorageObjectAck acks = 1;
}

// Batch of storage objects.
message StorageObjects {
  // The batch of storage objects.
  repeated StorageObject objects = 1;
}

// List of storage objects.
message StorageObjectList {
  // The list of storage objects.
  repeated StorageObject objects = 1;
  // The cursor associated with the query a page of results.
  string cursor = 2;
}

// Update a user's account details.
message UpdateAccountRequest {
  // The username of the user's account.
  google.protobuf.StringValue username = 1;
  // The display name of the user.
  google.protobuf.StringValue display_name = 2;
  // A URL for an avatar image.
  google.protobuf.StringValue avatar_url = 3;
  // The language expected to be a tag which follows the BCP-47 spec.
  google.protobuf.StringValue lang_tag = 4;
  // The location set by the user.
  google.protobuf.StringValue location = 5;
  // The timezone set by the user.
  google.protobuf.StringValue timezone = 6;
}

// A user in the server.
message User {
  // The id of the user's account.
  string id = 1;
  // The username of the user's account.
  string username = 2;
  // The display name of the user.
  string display_name = 3;
  // A URL for an avatar image.
  string avatar_url = 4;
  // The language expected to be a tag which follows the BCP-47 spec.
  string lang_tag = 5;
  // The location set by the user.
  string location = 6;
  // The timezone set by the user.
  string timezone = 7;
  // Additional information stored as a JSON object.
  string metadata = 8;
  // The Facebook id in the user's account.
  string facebook_id = 9;
  // The Google id in the user's account.
  string google_id = 10;
  // The Apple Game Center in of the user's account.
  string gamecenter_id = 11;
  // The Steam id in the user's account.
  string steam_id = 12;
  // Indicates whether the user is currently online.
  bool online = 13;
  // Number of related edges to this user.
  int32 edge_count = 14;
  // The UNIX time when the user was created.
  google.protobuf.Timestamp create_time = 15;
  // The UNIX time when the user was last updated.
  google.protobuf.Timestamp update_time = 16;
}

// A collection of zero or more users.
message Users {
  // The User objects.
  repeated User users = 1;
}

// The object to store.
message WriteStorageObject {
  // The collection to store the object.
  string collection = 1;
  // The key for the object within the collection.
  string key = 2;
  // The value of the object.
  string value = 3;
  // The version hash of the object to check. Possible values are: ["", "*", "#hash#"].
  string version = 4; // if-match and if-none-match
  // The read access permissions for the object.
  int32 permission_read = 5;
  // The write access permissions for the object.
  int32 permission_write = 6;
}

// Write objects to the storage engine.
message WriteStorageObjectsRequest {
  // The objects to store on the server.
  repeated WriteStorageObject objects = 1;
}
