first commit
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled

This commit is contained in:
2026-03-04 06:30:47 +00:00
commit bb402d4ccc
777 changed files with 135661 additions and 0 deletions

3
proto/api/v1/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Memos API Design
This API design should follow the guidelines and best practices outlined in the [Google API Improvement Proposals (AIPs)](https://google.aip.dev/).

View File

@@ -0,0 +1,125 @@
syntax = "proto3";
package memos.api.v1;
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/timestamp.proto";
option go_package = "gen/api/v1";
service ActivityService {
// ListActivities returns a list of activities.
rpc ListActivities(ListActivitiesRequest) returns (ListActivitiesResponse) {
option (google.api.http) = {get: "/api/v1/activities"};
}
// GetActivity returns the activity with the given id.
rpc GetActivity(GetActivityRequest) returns (Activity) {
option (google.api.http) = {get: "/api/v1/{name=activities/*}"};
option (google.api.method_signature) = "name";
}
}
message Activity {
option (google.api.resource) = {
type: "memos.api.v1/Activity"
pattern: "activities/{activity}"
name_field: "name"
singular: "activity"
plural: "activities"
};
// The name of the activity.
// Format: activities/{id}
string name = 1 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.field_behavior) = IDENTIFIER
];
// The name of the creator.
// Format: users/{user}
string creator = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
// The type of the activity.
Type type = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
// The level of the activity.
Level level = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
// The create time of the activity.
google.protobuf.Timestamp create_time = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
// The payload of the activity.
ActivityPayload payload = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
// Activity types.
enum Type {
// Unspecified type.
TYPE_UNSPECIFIED = 0;
// Memo comment activity.
MEMO_COMMENT = 1;
}
// Activity levels.
enum Level {
// Unspecified level.
LEVEL_UNSPECIFIED = 0;
// Info level.
INFO = 1;
// Warn level.
WARN = 2;
// Error level.
ERROR = 3;
}
}
message ActivityPayload {
oneof payload {
// Memo comment activity payload.
ActivityMemoCommentPayload memo_comment = 1;
}
}
// ActivityMemoCommentPayload represents the payload of a memo comment activity.
message ActivityMemoCommentPayload {
// The memo name of comment.
// Format: memos/{memo}
string memo = 1;
// The name of related memo.
// Format: memos/{memo}
string related_memo = 2;
}
message ListActivitiesRequest {
// The maximum number of activities to return.
// The service may return fewer than this value.
// If unspecified, at most 100 activities will be returned.
// The maximum value is 1000; values above 1000 will be coerced to 1000.
int32 page_size = 1;
// A page token, received from a previous `ListActivities` call.
// Provide this to retrieve the subsequent page.
string page_token = 2;
}
message ListActivitiesResponse {
// The activities.
repeated Activity activities = 1;
// A token to retrieve the next page of results.
// Pass this value in the page_token field in the subsequent call to `ListActivities`
// method to retrieve the next page of results.
string next_page_token = 2;
}
message GetActivityRequest {
// The name of the activity.
// Format: activities/{id}, id is the system generated auto-incremented id.
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Activity"}
];
}

View File

@@ -0,0 +1,96 @@
syntax = "proto3";
package memos.api.v1;
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
option go_package = "gen/api/v1";
// AIService provides AI-related functionality
service AIService {
// Get AI provider settings
rpc GetAISettings(GetAISettingsRequest) returns (AISettings) {
option (google.api.http) = {
get: "/api/v1/ai/settings"
};
}
// Update AI provider settings
rpc UpdateAISettings(UpdateAISettingsRequest) returns (AISettings) {
option (google.api.http) = {
patch: "/api/v1/ai/settings"
body: "settings"
};
}
// Test AI provider connection
rpc TestAIProvider(TestAIProviderRequest) returns (TestAIProviderResponse) {
option (google.api.http) = {
post: "/api/v1/ai/test"
body: "*"
};
}
// Generate text completion
rpc GenerateCompletion(GenerateCompletionRequest) returns (GenerateCompletionResponse) {
option (google.api.http) = {
post: "/api/v1/ai/completion"
body: "*"
};
}
}
message AISettings {
GroqSettings groq = 1;
OllamaSettings ollama = 2;
}
message GroqSettings {
string api_key = 1;
string default_model = 2;
bool enabled = 3;
}
message OllamaSettings {
string host = 1;
string default_model = 2;
bool enabled = 3;
}
message GetAISettingsRequest {}
message UpdateAISettingsRequest {
AISettings settings = 1;
}
message TestAIProviderRequest {
ProviderType provider = 1;
}
message TestAIProviderResponse {
bool success = 1;
string message = 2;
}
message GenerateCompletionRequest {
ProviderType provider = 1;
string prompt = 2;
string model = 3;
double temperature = 4;
int32 max_tokens = 5;
}
message GenerateCompletionResponse {
string text = 1;
string model_used = 2;
int32 prompt_tokens = 3;
int32 completion_tokens = 4;
int32 total_tokens = 5;
}
enum ProviderType {
PROVIDER_TYPE_UNSPECIFIED = 0;
PROVIDER_TYPE_GROQ = 1;
PROVIDER_TYPE_OLLAMA = 2;
}

View File

@@ -0,0 +1,150 @@
syntax = "proto3";
package memos.api.v1;
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
option go_package = "gen/api/v1";
service AttachmentService {
// CreateAttachment creates a new attachment.
rpc CreateAttachment(CreateAttachmentRequest) returns (Attachment) {
option (google.api.http) = {
post: "/api/v1/attachments"
body: "attachment"
};
option (google.api.method_signature) = "attachment";
}
// ListAttachments lists all attachments.
rpc ListAttachments(ListAttachmentsRequest) returns (ListAttachmentsResponse) {
option (google.api.http) = {get: "/api/v1/attachments"};
}
// GetAttachment returns a attachment by name.
rpc GetAttachment(GetAttachmentRequest) returns (Attachment) {
option (google.api.http) = {get: "/api/v1/{name=attachments/*}"};
option (google.api.method_signature) = "name";
}
// UpdateAttachment updates a attachment.
rpc UpdateAttachment(UpdateAttachmentRequest) returns (Attachment) {
option (google.api.http) = {
patch: "/api/v1/{attachment.name=attachments/*}"
body: "attachment"
};
option (google.api.method_signature) = "attachment,update_mask";
}
// DeleteAttachment deletes a attachment by name.
rpc DeleteAttachment(DeleteAttachmentRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=attachments/*}"};
option (google.api.method_signature) = "name";
}
}
message Attachment {
option (google.api.resource) = {
type: "memos.api.v1/Attachment"
pattern: "attachments/{attachment}"
singular: "attachment"
plural: "attachments"
};
// The name of the attachment.
// Format: attachments/{attachment}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// Output only. The creation timestamp.
google.protobuf.Timestamp create_time = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
// The filename of the attachment.
string filename = 3 [(google.api.field_behavior) = REQUIRED];
// Input only. The content of the attachment.
bytes content = 4 [(google.api.field_behavior) = INPUT_ONLY];
// Optional. The external link of the attachment.
string external_link = 5 [(google.api.field_behavior) = OPTIONAL];
// The MIME type of the attachment.
string type = 6 [(google.api.field_behavior) = REQUIRED];
// Output only. The size of the attachment in bytes.
int64 size = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
// Optional. The related memo. Refer to `Memo.name`.
// Format: memos/{memo}
optional string memo = 8 [(google.api.field_behavior) = OPTIONAL];
}
message CreateAttachmentRequest {
// Required. The attachment to create.
Attachment attachment = 1 [(google.api.field_behavior) = REQUIRED];
// Optional. The attachment ID to use for this attachment.
// If empty, a unique ID will be generated.
string attachment_id = 2 [(google.api.field_behavior) = OPTIONAL];
}
message ListAttachmentsRequest {
// Optional. The maximum number of attachments to return.
// The service may return fewer than this value.
// If unspecified, at most 50 attachments will be returned.
// The maximum value is 1000; values above 1000 will be coerced to 1000.
int32 page_size = 1 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token, received from a previous `ListAttachments` call.
// Provide this to retrieve the subsequent page.
string page_token = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. Filter to apply to the list results.
// Example: "mime_type==\"image/png\"" or "filename.contains(\"test\")"
// Supported operators: =, !=, <, <=, >, >=, : (contains), in
// Supported fields: filename, mime_type, create_time, memo
string filter = 3 [(google.api.field_behavior) = OPTIONAL];
// Optional. The order to sort results by.
// Example: "create_time desc" or "filename asc"
string order_by = 4 [(google.api.field_behavior) = OPTIONAL];
}
message ListAttachmentsResponse {
// The list of attachments.
repeated Attachment attachments = 1;
// A token that can be sent as `page_token` to retrieve the next page.
// If this field is omitted, there are no subsequent pages.
string next_page_token = 2;
// The total count of attachments (may be approximate).
int32 total_size = 3;
}
message GetAttachmentRequest {
// Required. The attachment name of the attachment to retrieve.
// Format: attachments/{attachment}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Attachment"}
];
}
message UpdateAttachmentRequest {
// Required. The attachment which replaces the attachment on the server.
Attachment attachment = 1 [(google.api.field_behavior) = REQUIRED];
// Required. The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
}
message DeleteAttachmentRequest {
// Required. The attachment name of the attachment to delete.
// Format: attachments/{attachment}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Attachment"}
];
}

View File

@@ -0,0 +1,114 @@
syntax = "proto3";
package memos.api.v1;
import "api/v1/user_service.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
option go_package = "gen/api/v1";
service AuthService {
// GetCurrentUser returns the authenticated user's information.
// Validates the access token and returns user details.
// Similar to OIDC's /userinfo endpoint.
rpc GetCurrentUser(GetCurrentUserRequest) returns (GetCurrentUserResponse) {
option (google.api.http) = {get: "/api/v1/auth/me"};
}
// SignIn authenticates a user with credentials and returns tokens.
// On success, returns an access token and sets a refresh token cookie.
// Supports password-based and SSO authentication methods.
rpc SignIn(SignInRequest) returns (SignInResponse) {
option (google.api.http) = {
post: "/api/v1/auth/signin"
body: "*"
};
}
// SignOut terminates the user's authentication.
// Revokes the refresh token and clears the authentication cookie.
rpc SignOut(SignOutRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {post: "/api/v1/auth/signout"};
}
// RefreshToken exchanges a valid refresh token for a new access token.
// The refresh token is read from the HttpOnly cookie.
// Returns a new short-lived access token.
rpc RefreshToken(RefreshTokenRequest) returns (RefreshTokenResponse) {
option (google.api.http) = {
post: "/api/v1/auth/refresh"
body: "*"
};
}
}
message GetCurrentUserRequest {}
message GetCurrentUserResponse {
// The authenticated user's information.
User user = 1;
}
message SignInRequest {
// Nested message for password-based authentication credentials.
message PasswordCredentials {
// The username to sign in with.
string username = 1 [(google.api.field_behavior) = REQUIRED];
// The password to sign in with.
string password = 2 [(google.api.field_behavior) = REQUIRED];
}
// Nested message for SSO authentication credentials.
message SSOCredentials {
// The ID of the SSO provider.
int32 idp_id = 1 [(google.api.field_behavior) = REQUIRED];
// The authorization code from the SSO provider.
string code = 2 [(google.api.field_behavior) = REQUIRED];
// The redirect URI used in the SSO flow.
string redirect_uri = 3 [(google.api.field_behavior) = REQUIRED];
// The PKCE code verifier for enhanced security (RFC 7636).
// Optional - enables PKCE flow protection against authorization code interception.
string code_verifier = 4 [(google.api.field_behavior) = OPTIONAL];
}
// Authentication credentials. Provide one method.
oneof credentials {
// Username and password authentication.
PasswordCredentials password_credentials = 1;
// SSO provider authentication.
SSOCredentials sso_credentials = 2;
}
}
message SignInResponse {
// The authenticated user's information.
User user = 1;
// The short-lived access token for API requests.
// Store in memory only, not in localStorage.
string access_token = 2;
// When the access token expires.
// Client should call RefreshToken before this time.
google.protobuf.Timestamp access_token_expires_at = 3;
}
message SignOutRequest {}
message RefreshTokenRequest {}
message RefreshTokenResponse {
// The new short-lived access token.
string access_token = 1;
// When the access token expires.
google.protobuf.Timestamp expires_at = 2;
}

23
proto/api/v1/common.proto Normal file
View File

@@ -0,0 +1,23 @@
syntax = "proto3";
package memos.api.v1;
option go_package = "gen/api/v1";
enum State {
STATE_UNSPECIFIED = 0;
NORMAL = 1;
ARCHIVED = 2;
}
// Used internally for obfuscating the page token.
message PageToken {
int32 limit = 1;
int32 offset = 2;
}
enum Direction {
DIRECTION_UNSPECIFIED = 0;
ASC = 1;
DESC = 2;
}

View File

@@ -0,0 +1,147 @@
syntax = "proto3";
package memos.api.v1;
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
option go_package = "gen/api/v1";
service IdentityProviderService {
// ListIdentityProviders lists identity providers.
rpc ListIdentityProviders(ListIdentityProvidersRequest) returns (ListIdentityProvidersResponse) {
option (google.api.http) = {get: "/api/v1/identity-providers"};
}
// GetIdentityProvider gets an identity provider.
rpc GetIdentityProvider(GetIdentityProviderRequest) returns (IdentityProvider) {
option (google.api.http) = {get: "/api/v1/{name=identity-providers/*}"};
option (google.api.method_signature) = "name";
}
// CreateIdentityProvider creates an identity provider.
rpc CreateIdentityProvider(CreateIdentityProviderRequest) returns (IdentityProvider) {
option (google.api.http) = {
post: "/api/v1/identity-providers"
body: "identity_provider"
};
option (google.api.method_signature) = "identity_provider";
}
// UpdateIdentityProvider updates an identity provider.
rpc UpdateIdentityProvider(UpdateIdentityProviderRequest) returns (IdentityProvider) {
option (google.api.http) = {
patch: "/api/v1/{identity_provider.name=identity-providers/*}"
body: "identity_provider"
};
option (google.api.method_signature) = "identity_provider,update_mask";
}
// DeleteIdentityProvider deletes an identity provider.
rpc DeleteIdentityProvider(DeleteIdentityProviderRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=identity-providers/*}"};
option (google.api.method_signature) = "name";
}
}
message IdentityProvider {
option (google.api.resource) = {
type: "memos.api.v1/IdentityProvider"
pattern: "identity-providers/{idp}"
name_field: "name"
singular: "identityProvider"
plural: "identityProviders"
};
// The resource name of the identity provider.
// Format: identity-providers/{idp}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// Required. The type of the identity provider.
Type type = 2 [(google.api.field_behavior) = REQUIRED];
// Required. The display title of the identity provider.
string title = 3 [(google.api.field_behavior) = REQUIRED];
// Optional. Filter applied to user identifiers.
string identifier_filter = 4 [(google.api.field_behavior) = OPTIONAL];
// Required. Configuration for the identity provider.
IdentityProviderConfig config = 5 [(google.api.field_behavior) = REQUIRED];
enum Type {
TYPE_UNSPECIFIED = 0;
// OAuth2 identity provider.
OAUTH2 = 1;
}
}
message IdentityProviderConfig {
oneof config {
OAuth2Config oauth2_config = 1;
}
}
message FieldMapping {
string identifier = 1;
string display_name = 2;
string email = 3;
string avatar_url = 4;
}
message OAuth2Config {
string client_id = 1;
string client_secret = 2;
string auth_url = 3;
string token_url = 4;
string user_info_url = 5;
repeated string scopes = 6;
FieldMapping field_mapping = 7;
}
message ListIdentityProvidersRequest {}
message ListIdentityProvidersResponse {
// The list of identity providers.
repeated IdentityProvider identity_providers = 1;
}
message GetIdentityProviderRequest {
// Required. The resource name of the identity provider to get.
// Format: identity-providers/{idp}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/IdentityProvider"}
];
}
message CreateIdentityProviderRequest {
// Required. The identity provider to create.
IdentityProvider identity_provider = 1 [(google.api.field_behavior) = REQUIRED];
// Optional. The ID to use for the identity provider, which will become the final component of the resource name.
// If not provided, the system will generate one.
string identity_provider_id = 2 [(google.api.field_behavior) = OPTIONAL];
}
message UpdateIdentityProviderRequest {
// Required. The identity provider to update.
IdentityProvider identity_provider = 1 [(google.api.field_behavior) = REQUIRED];
// Required. The update mask applies to the resource. Only the top level fields of
// IdentityProvider are supported.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
}
message DeleteIdentityProviderRequest {
// Required. The resource name of the identity provider to delete.
// Format: identity-providers/{idp}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/IdentityProvider"}
];
}

View File

@@ -0,0 +1,181 @@
syntax = "proto3";
package memos.api.v1;
import "api/v1/user_service.proto";
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/field_mask.proto";
option go_package = "gen/api/v1";
service InstanceService {
// Gets the instance profile.
rpc GetInstanceProfile(GetInstanceProfileRequest) returns (InstanceProfile) {
option (google.api.http) = {get: "/api/v1/instance/profile"};
}
// Gets an instance setting.
rpc GetInstanceSetting(GetInstanceSettingRequest) returns (InstanceSetting) {
option (google.api.http) = {get: "/api/v1/{name=instance/settings/*}"};
option (google.api.method_signature) = "name";
}
// Updates an instance setting.
rpc UpdateInstanceSetting(UpdateInstanceSettingRequest) returns (InstanceSetting) {
option (google.api.http) = {
patch: "/api/v1/{setting.name=instance/settings/*}"
body: "setting"
};
option (google.api.method_signature) = "setting,update_mask";
}
}
// Instance profile message containing basic instance information.
message InstanceProfile {
// Version is the current version of instance.
string version = 2;
// Demo indicates if the instance is in demo mode.
bool demo = 3;
// Instance URL is the URL of the instance.
string instance_url = 6;
// The first administrator who set up this instance.
// When null, instance requires initial setup (creating the first admin account).
User admin = 7;
}
// Request for instance profile.
message GetInstanceProfileRequest {}
// An instance setting resource.
message InstanceSetting {
option (google.api.resource) = {
type: "memos.api.v1/InstanceSetting"
pattern: "instance/settings/{setting}"
singular: "instanceSetting"
plural: "instanceSettings"
};
// The name of the instance setting.
// Format: instance/settings/{setting}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
oneof value {
GeneralSetting general_setting = 2;
StorageSetting storage_setting = 3;
MemoRelatedSetting memo_related_setting = 4;
}
// Enumeration of instance setting keys.
enum Key {
KEY_UNSPECIFIED = 0;
// GENERAL is the key for general settings.
GENERAL = 1;
// STORAGE is the key for storage settings.
STORAGE = 2;
// MEMO_RELATED is the key for memo related settings.
MEMO_RELATED = 3;
}
// General instance settings configuration.
message GeneralSetting {
// disallow_user_registration disallows user registration.
bool disallow_user_registration = 2;
// disallow_password_auth disallows password authentication.
bool disallow_password_auth = 3;
// additional_script is the additional script.
string additional_script = 4;
// additional_style is the additional style.
string additional_style = 5;
// custom_profile is the custom profile.
CustomProfile custom_profile = 6;
// week_start_day_offset is the week start day offset from Sunday.
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday.
int32 week_start_day_offset = 7;
// disallow_change_username disallows changing username.
bool disallow_change_username = 8;
// disallow_change_nickname disallows changing nickname.
bool disallow_change_nickname = 9;
// Custom profile configuration for instance branding.
message CustomProfile {
string title = 1;
string description = 2;
string logo_url = 3;
}
}
// Storage configuration settings for instance attachments.
message StorageSetting {
// Storage type enumeration for different storage backends.
enum StorageType {
STORAGE_TYPE_UNSPECIFIED = 0;
// DATABASE is the database storage type.
DATABASE = 1;
// LOCAL is the local storage type.
LOCAL = 2;
// S3 is the S3 storage type.
S3 = 3;
}
// storage_type is the storage type.
StorageType storage_type = 1;
// The template of file path.
// e.g. assets/{timestamp}_{filename}
string filepath_template = 2;
// The max upload size in megabytes.
int64 upload_size_limit_mb = 3;
// S3 configuration for cloud storage backend.
// Reference: https://developers.cloudflare.com/r2/examples/aws/aws-sdk-go/
message S3Config {
string access_key_id = 1;
string access_key_secret = 2;
string endpoint = 3;
string region = 4;
string bucket = 5;
bool use_path_style = 6;
}
// The S3 config.
S3Config s3_config = 4;
}
// Memo-related instance settings and policies.
message MemoRelatedSetting {
// disallow_public_visibility disallows set memo as public visibility.
bool disallow_public_visibility = 1;
// display_with_update_time orders and displays memo with update time.
bool display_with_update_time = 2;
// content_length_limit is the limit of content length. Unit is byte.
int32 content_length_limit = 3;
// enable_double_click_edit enables editing on double click.
bool enable_double_click_edit = 4;
// reactions is the list of reactions.
repeated string reactions = 7;
}
}
// Request message for GetInstanceSetting method.
message GetInstanceSettingRequest {
// The resource name of the instance setting.
// Format: instance/settings/{setting}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/InstanceSetting"}
];
}
// Request message for UpdateInstanceSetting method.
message UpdateInstanceSettingRequest {
// The instance setting resource which replaces the resource on the server.
InstanceSetting setting = 1 [(google.api.field_behavior) = REQUIRED];
// The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = OPTIONAL];
}

View File

@@ -0,0 +1,511 @@
syntax = "proto3";
package memos.api.v1;
import "api/v1/attachment_service.proto";
import "api/v1/common.proto";
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
option go_package = "gen/api/v1";
service MemoService {
// CreateMemo creates a memo.
rpc CreateMemo(CreateMemoRequest) returns (Memo) {
option (google.api.http) = {
post: "/api/v1/memos"
body: "memo"
};
option (google.api.method_signature) = "memo";
}
// ListMemos lists memos with pagination and filter.
rpc ListMemos(ListMemosRequest) returns (ListMemosResponse) {
option (google.api.http) = {get: "/api/v1/memos"};
option (google.api.method_signature) = "";
}
// GetMemo gets a memo.
rpc GetMemo(GetMemoRequest) returns (Memo) {
option (google.api.http) = {get: "/api/v1/{name=memos/*}"};
option (google.api.method_signature) = "name";
}
// UpdateMemo updates a memo.
rpc UpdateMemo(UpdateMemoRequest) returns (Memo) {
option (google.api.http) = {
patch: "/api/v1/{memo.name=memos/*}"
body: "memo"
};
option (google.api.method_signature) = "memo,update_mask";
}
// DeleteMemo deletes a memo.
rpc DeleteMemo(DeleteMemoRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=memos/*}"};
option (google.api.method_signature) = "name";
}
// SetMemoAttachments sets attachments for a memo.
rpc SetMemoAttachments(SetMemoAttachmentsRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
patch: "/api/v1/{name=memos/*}/attachments"
body: "*"
};
option (google.api.method_signature) = "name";
}
// ListMemoAttachments lists attachments for a memo.
rpc ListMemoAttachments(ListMemoAttachmentsRequest) returns (ListMemoAttachmentsResponse) {
option (google.api.http) = {get: "/api/v1/{name=memos/*}/attachments"};
option (google.api.method_signature) = "name";
}
// SetMemoRelations sets relations for a memo.
rpc SetMemoRelations(SetMemoRelationsRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
patch: "/api/v1/{name=memos/*}/relations"
body: "*"
};
option (google.api.method_signature) = "name";
}
// ListMemoRelations lists relations for a memo.
rpc ListMemoRelations(ListMemoRelationsRequest) returns (ListMemoRelationsResponse) {
option (google.api.http) = {get: "/api/v1/{name=memos/*}/relations"};
option (google.api.method_signature) = "name";
}
// CreateMemoComment creates a comment for a memo.
rpc CreateMemoComment(CreateMemoCommentRequest) returns (Memo) {
option (google.api.http) = {
post: "/api/v1/{name=memos/*}/comments"
body: "comment"
};
option (google.api.method_signature) = "name,comment";
}
// ListMemoComments lists comments for a memo.
rpc ListMemoComments(ListMemoCommentsRequest) returns (ListMemoCommentsResponse) {
option (google.api.http) = {get: "/api/v1/{name=memos/*}/comments"};
option (google.api.method_signature) = "name";
}
// ListMemoReactions lists reactions for a memo.
rpc ListMemoReactions(ListMemoReactionsRequest) returns (ListMemoReactionsResponse) {
option (google.api.http) = {get: "/api/v1/{name=memos/*}/reactions"};
option (google.api.method_signature) = "name";
}
// UpsertMemoReaction upserts a reaction for a memo.
rpc UpsertMemoReaction(UpsertMemoReactionRequest) returns (Reaction) {
option (google.api.http) = {
post: "/api/v1/{name=memos/*}/reactions"
body: "*"
};
option (google.api.method_signature) = "name";
}
// DeleteMemoReaction deletes a reaction for a memo.
rpc DeleteMemoReaction(DeleteMemoReactionRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=memos/*/reactions/*}"};
option (google.api.method_signature) = "name";
}
}
enum Visibility {
VISIBILITY_UNSPECIFIED = 0;
PRIVATE = 1;
PROTECTED = 2;
PUBLIC = 3;
}
message Reaction {
option (google.api.resource) = {
type: "memos.api.v1/Reaction"
pattern: "memos/{memo}/reactions/{reaction}"
name_field: "name"
singular: "reaction"
plural: "reactions"
};
// The resource name of the reaction.
// Format: memos/{memo}/reactions/{reaction}
string name = 1 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.field_behavior) = IDENTIFIER
];
// The resource name of the creator.
// Format: users/{user}
string creator = 2 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// The resource name of the content.
// For memo reactions, this should be the memo's resource name.
// Format: memos/{memo}
string content_id = 3 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Required. The type of reaction (e.g., "👍", "❤️", "😄").
string reaction_type = 4 [(google.api.field_behavior) = REQUIRED];
// Output only. The creation timestamp.
google.protobuf.Timestamp create_time = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
}
message Memo {
option (google.api.resource) = {
type: "memos.api.v1/Memo"
pattern: "memos/{memo}"
name_field: "name"
singular: "memo"
plural: "memos"
};
// The resource name of the memo.
// Format: memos/{memo}, memo is the user defined id or uuid.
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// The state of the memo.
State state = 2 [(google.api.field_behavior) = REQUIRED];
// The name of the creator.
// Format: users/{user}
string creator = 3 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// The creation timestamp.
// If not set on creation, the server will set it to the current time.
google.protobuf.Timestamp create_time = 4 [(google.api.field_behavior) = OPTIONAL];
// The last update timestamp.
// If not set on creation, the server will set it to the current time.
google.protobuf.Timestamp update_time = 5 [(google.api.field_behavior) = OPTIONAL];
// The display timestamp of the memo.
google.protobuf.Timestamp display_time = 6 [(google.api.field_behavior) = OPTIONAL];
// Required. The content of the memo in Markdown format.
string content = 7 [(google.api.field_behavior) = REQUIRED];
// The visibility of the memo.
Visibility visibility = 9 [(google.api.field_behavior) = REQUIRED];
// Output only. The tags extracted from the content.
repeated string tags = 10 [(google.api.field_behavior) = OUTPUT_ONLY];
// Whether the memo is pinned.
bool pinned = 11 [(google.api.field_behavior) = OPTIONAL];
// Optional. The attachments of the memo.
repeated Attachment attachments = 12 [(google.api.field_behavior) = OPTIONAL];
// Optional. The relations of the memo.
repeated MemoRelation relations = 13 [(google.api.field_behavior) = OPTIONAL];
// Output only. The reactions to the memo.
repeated Reaction reactions = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
// Output only. The computed properties of the memo.
Property property = 15 [(google.api.field_behavior) = OUTPUT_ONLY];
// Output only. The name of the parent memo.
// Format: memos/{memo}
optional string parent = 16 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Output only. The snippet of the memo content. Plain text only.
string snippet = 17 [(google.api.field_behavior) = OUTPUT_ONLY];
// Optional. The location of the memo.
optional Location location = 18 [(google.api.field_behavior) = OPTIONAL];
// Computed properties of a memo.
message Property {
bool has_link = 1;
bool has_task_list = 2;
bool has_code = 3;
bool has_incomplete_tasks = 4;
}
}
message Location {
// A placeholder text for the location.
string placeholder = 1 [(google.api.field_behavior) = OPTIONAL];
// The latitude of the location.
double latitude = 2 [(google.api.field_behavior) = OPTIONAL];
// The longitude of the location.
double longitude = 3 [(google.api.field_behavior) = OPTIONAL];
}
message CreateMemoRequest {
// Required. The memo to create.
Memo memo = 1 [(google.api.field_behavior) = REQUIRED];
// Optional. The memo ID to use for this memo.
// If empty, a unique ID will be generated.
string memo_id = 2 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemosRequest {
// Optional. The maximum number of memos to return.
// The service may return fewer than this value.
// If unspecified, at most 50 memos will be returned.
// The maximum value is 1000; values above 1000 will be coerced to 1000.
int32 page_size = 1 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token, received from a previous `ListMemos` call.
// Provide this to retrieve the subsequent page.
string page_token = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. The state of the memos to list.
// Default to `NORMAL`. Set to `ARCHIVED` to list archived memos.
State state = 3 [(google.api.field_behavior) = OPTIONAL];
// Optional. The order to sort results by.
// Default to "display_time desc".
// Supports comma-separated list of fields following AIP-132.
// Example: "pinned desc, display_time desc" or "create_time asc"
// Supported fields: pinned, display_time, create_time, update_time, name
string order_by = 4 [(google.api.field_behavior) = OPTIONAL];
// Optional. Filter to apply to the list results.
// Filter is a CEL expression to filter memos.
// Refer to `Shortcut.filter`.
string filter = 5 [(google.api.field_behavior) = OPTIONAL];
// Optional. If true, show deleted memos in the response.
bool show_deleted = 6 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemosResponse {
// The list of memos.
repeated Memo memos = 1;
// A token that can be sent as `page_token` to retrieve the next page.
// If this field is omitted, there are no subsequent pages.
string next_page_token = 2;
}
message GetMemoRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
}
message UpdateMemoRequest {
// Required. The memo to update.
// The `name` field is required.
Memo memo = 1 [(google.api.field_behavior) = REQUIRED];
// Required. The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
}
message DeleteMemoRequest {
// Required. The resource name of the memo to delete.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Optional. If set to true, the memo will be deleted even if it has associated data.
bool force = 2 [(google.api.field_behavior) = OPTIONAL];
}
message SetMemoAttachmentsRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Required. The attachments to set for the memo.
repeated Attachment attachments = 2 [(google.api.field_behavior) = REQUIRED];
}
message ListMemoAttachmentsRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Optional. The maximum number of attachments to return.
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token for pagination.
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemoAttachmentsResponse {
// The list of attachments.
repeated Attachment attachments = 1;
// A token for the next page of results.
string next_page_token = 2;
}
message MemoRelation {
// The memo in the relation.
Memo memo = 1 [(google.api.field_behavior) = REQUIRED];
// The related memo.
Memo related_memo = 2 [(google.api.field_behavior) = REQUIRED];
// The type of the relation.
enum Type {
TYPE_UNSPECIFIED = 0;
REFERENCE = 1;
COMMENT = 2;
}
Type type = 3 [(google.api.field_behavior) = REQUIRED];
// Memo reference in relations.
message Memo {
// The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Output only. The snippet of the memo content. Plain text only.
string snippet = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
}
}
message SetMemoRelationsRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Required. The relations to set for the memo.
repeated MemoRelation relations = 2 [(google.api.field_behavior) = REQUIRED];
}
message ListMemoRelationsRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Optional. The maximum number of relations to return.
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token for pagination.
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemoRelationsResponse {
// The list of relations.
repeated MemoRelation relations = 1;
// A token for the next page of results.
string next_page_token = 2;
}
message CreateMemoCommentRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Required. The comment to create.
Memo comment = 2 [(google.api.field_behavior) = REQUIRED];
// Optional. The comment ID to use.
string comment_id = 3 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemoCommentsRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Optional. The maximum number of comments to return.
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token for pagination.
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
// Optional. The order to sort results by.
string order_by = 4 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemoCommentsResponse {
// The list of comment memos.
repeated Memo memos = 1;
// A token for the next page of results.
string next_page_token = 2;
// The total count of comments.
int32 total_size = 3;
}
message ListMemoReactionsRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Optional. The maximum number of reactions to return.
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token for pagination.
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}
message ListMemoReactionsResponse {
// The list of reactions.
repeated Reaction reactions = 1;
// A token for the next page of results.
string next_page_token = 2;
// The total count of reactions.
int32 total_size = 3;
}
message UpsertMemoReactionRequest {
// Required. The resource name of the memo.
// Format: memos/{memo}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Memo"}
];
// Required. The reaction to upsert.
Reaction reaction = 2 [(google.api.field_behavior) = REQUIRED];
}
message DeleteMemoReactionRequest {
// Required. The resource name of the reaction to delete.
// Format: memos/{memo}/reactions/{reaction}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Reaction"}
];
}

View File

@@ -0,0 +1,124 @@
syntax = "proto3";
package memos.api.v1;
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
option go_package = "gen/api/v1";
service ShortcutService {
// ListShortcuts returns a list of shortcuts for a user.
rpc ListShortcuts(ListShortcutsRequest) returns (ListShortcutsResponse) {
option (google.api.http) = {get: "/api/v1/{parent=users/*}/shortcuts"};
option (google.api.method_signature) = "parent";
}
// GetShortcut gets a shortcut by name.
rpc GetShortcut(GetShortcutRequest) returns (Shortcut) {
option (google.api.http) = {get: "/api/v1/{name=users/*/shortcuts/*}"};
option (google.api.method_signature) = "name";
}
// CreateShortcut creates a new shortcut for a user.
rpc CreateShortcut(CreateShortcutRequest) returns (Shortcut) {
option (google.api.http) = {
post: "/api/v1/{parent=users/*}/shortcuts"
body: "shortcut"
};
option (google.api.method_signature) = "parent,shortcut";
}
// UpdateShortcut updates a shortcut for a user.
rpc UpdateShortcut(UpdateShortcutRequest) returns (Shortcut) {
option (google.api.http) = {
patch: "/api/v1/{shortcut.name=users/*/shortcuts/*}"
body: "shortcut"
};
option (google.api.method_signature) = "shortcut,update_mask";
}
// DeleteShortcut deletes a shortcut for a user.
rpc DeleteShortcut(DeleteShortcutRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=users/*/shortcuts/*}"};
option (google.api.method_signature) = "name";
}
}
message Shortcut {
option (google.api.resource) = {
type: "memos.api.v1/Shortcut"
pattern: "users/{user}/shortcuts/{shortcut}"
singular: "shortcut"
plural: "shortcuts"
};
// The resource name of the shortcut.
// Format: users/{user}/shortcuts/{shortcut}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// The title of the shortcut.
string title = 2 [(google.api.field_behavior) = REQUIRED];
// The filter expression for the shortcut.
string filter = 3 [(google.api.field_behavior) = OPTIONAL];
}
message ListShortcutsRequest {
// Required. The parent resource where shortcuts are listed.
// Format: users/{user}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {child_type: "memos.api.v1/Shortcut"}
];
}
message ListShortcutsResponse {
// The list of shortcuts.
repeated Shortcut shortcuts = 1;
}
message GetShortcutRequest {
// Required. The resource name of the shortcut to retrieve.
// Format: users/{user}/shortcuts/{shortcut}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Shortcut"}
];
}
message CreateShortcutRequest {
// Required. The parent resource where this shortcut will be created.
// Format: users/{user}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {child_type: "memos.api.v1/Shortcut"}
];
// Required. The shortcut to create.
Shortcut shortcut = 2 [(google.api.field_behavior) = REQUIRED];
// Optional. If set, validate the request, but do not actually create the shortcut.
bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
}
message UpdateShortcutRequest {
// Required. The shortcut resource which replaces the resource on the server.
Shortcut shortcut = 1 [(google.api.field_behavior) = REQUIRED];
// Optional. The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = OPTIONAL];
}
message DeleteShortcutRequest {
// Required. The resource name of the shortcut to delete.
// Format: users/{user}/shortcuts/{shortcut}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/Shortcut"}
];
}

View File

@@ -0,0 +1,673 @@
syntax = "proto3";
package memos.api.v1;
import "api/v1/common.proto";
import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
option go_package = "gen/api/v1";
service UserService {
// ListUsers returns a list of users.
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
option (google.api.http) = {get: "/api/v1/users"};
}
// GetUser gets a user by ID or username.
// Supports both numeric IDs and username strings:
// - users/{id} (e.g., users/101)
// - users/{username} (e.g., users/steven)
rpc GetUser(GetUserRequest) returns (User) {
option (google.api.http) = {get: "/api/v1/{name=users/*}"};
option (google.api.method_signature) = "name";
}
// CreateUser creates a new user.
rpc CreateUser(CreateUserRequest) returns (User) {
option (google.api.http) = {
post: "/api/v1/users"
body: "user"
};
option (google.api.method_signature) = "user";
}
// UpdateUser updates a user.
rpc UpdateUser(UpdateUserRequest) returns (User) {
option (google.api.http) = {
patch: "/api/v1/{user.name=users/*}"
body: "user"
};
option (google.api.method_signature) = "user,update_mask";
}
// DeleteUser deletes a user.
rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=users/*}"};
option (google.api.method_signature) = "name";
}
// ListAllUserStats returns statistics for all users.
rpc ListAllUserStats(ListAllUserStatsRequest) returns (ListAllUserStatsResponse) {
option (google.api.http) = {get: "/api/v1/users:stats"};
}
// GetUserStats returns statistics for a specific user.
rpc GetUserStats(GetUserStatsRequest) returns (UserStats) {
option (google.api.http) = {get: "/api/v1/{name=users/*}:getStats"};
option (google.api.method_signature) = "name";
}
// GetUserSetting returns the user setting.
rpc GetUserSetting(GetUserSettingRequest) returns (UserSetting) {
option (google.api.http) = {get: "/api/v1/{name=users/*/settings/*}"};
option (google.api.method_signature) = "name";
}
// UpdateUserSetting updates the user setting.
rpc UpdateUserSetting(UpdateUserSettingRequest) returns (UserSetting) {
option (google.api.http) = {
patch: "/api/v1/{setting.name=users/*/settings/*}"
body: "setting"
};
option (google.api.method_signature) = "setting,update_mask";
}
// ListUserSettings returns a list of user settings.
rpc ListUserSettings(ListUserSettingsRequest) returns (ListUserSettingsResponse) {
option (google.api.http) = {get: "/api/v1/{parent=users/*}/settings"};
option (google.api.method_signature) = "parent";
}
// ListPersonalAccessTokens returns a list of Personal Access Tokens (PATs) for a user.
// PATs are long-lived tokens for API/script access, distinct from short-lived JWT access tokens.
rpc ListPersonalAccessTokens(ListPersonalAccessTokensRequest) returns (ListPersonalAccessTokensResponse) {
option (google.api.http) = {get: "/api/v1/{parent=users/*}/personalAccessTokens"};
option (google.api.method_signature) = "parent";
}
// CreatePersonalAccessToken creates a new Personal Access Token for a user.
// The token value is only returned once upon creation.
rpc CreatePersonalAccessToken(CreatePersonalAccessTokenRequest) returns (CreatePersonalAccessTokenResponse) {
option (google.api.http) = {
post: "/api/v1/{parent=users/*}/personalAccessTokens"
body: "*"
};
}
// DeletePersonalAccessToken deletes a Personal Access Token.
rpc DeletePersonalAccessToken(DeletePersonalAccessTokenRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=users/*/personalAccessTokens/*}"};
option (google.api.method_signature) = "name";
}
// ListUserWebhooks returns a list of webhooks for a user.
rpc ListUserWebhooks(ListUserWebhooksRequest) returns (ListUserWebhooksResponse) {
option (google.api.http) = {get: "/api/v1/{parent=users/*}/webhooks"};
option (google.api.method_signature) = "parent";
}
// CreateUserWebhook creates a new webhook for a user.
rpc CreateUserWebhook(CreateUserWebhookRequest) returns (UserWebhook) {
option (google.api.http) = {
post: "/api/v1/{parent=users/*}/webhooks"
body: "webhook"
};
option (google.api.method_signature) = "parent,webhook";
}
// UpdateUserWebhook updates an existing webhook for a user.
rpc UpdateUserWebhook(UpdateUserWebhookRequest) returns (UserWebhook) {
option (google.api.http) = {
patch: "/api/v1/{webhook.name=users/*/webhooks/*}"
body: "webhook"
};
option (google.api.method_signature) = "webhook,update_mask";
}
// DeleteUserWebhook deletes a webhook for a user.
rpc DeleteUserWebhook(DeleteUserWebhookRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=users/*/webhooks/*}"};
option (google.api.method_signature) = "name";
}
// ListUserNotifications lists notifications for a user.
rpc ListUserNotifications(ListUserNotificationsRequest) returns (ListUserNotificationsResponse) {
option (google.api.http) = {get: "/api/v1/{parent=users/*}/notifications"};
option (google.api.method_signature) = "parent";
}
// UpdateUserNotification updates a notification.
rpc UpdateUserNotification(UpdateUserNotificationRequest) returns (UserNotification) {
option (google.api.http) = {
patch: "/api/v1/{notification.name=users/*/notifications/*}"
body: "notification"
};
option (google.api.method_signature) = "notification,update_mask";
}
// DeleteUserNotification deletes a notification.
rpc DeleteUserNotification(DeleteUserNotificationRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{name=users/*/notifications/*}"};
option (google.api.method_signature) = "name";
}
}
message User {
option (google.api.resource) = {
type: "memos.api.v1/User"
pattern: "users/{user}"
name_field: "name"
singular: "user"
plural: "users"
};
// The resource name of the user.
// Format: users/{user}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// The role of the user.
Role role = 2 [(google.api.field_behavior) = REQUIRED];
// Required. The unique username for login.
string username = 3 [(google.api.field_behavior) = REQUIRED];
// Optional. The email address of the user.
string email = 4 [(google.api.field_behavior) = OPTIONAL];
// Optional. The display name of the user.
string display_name = 5 [(google.api.field_behavior) = OPTIONAL];
// Optional. The avatar URL of the user.
string avatar_url = 6 [(google.api.field_behavior) = OPTIONAL];
// Optional. The description of the user.
string description = 7 [(google.api.field_behavior) = OPTIONAL];
// Input only. The password for the user.
string password = 8 [(google.api.field_behavior) = INPUT_ONLY];
// The state of the user.
State state = 9 [(google.api.field_behavior) = REQUIRED];
// Output only. The creation timestamp.
google.protobuf.Timestamp create_time = 10 [(google.api.field_behavior) = OUTPUT_ONLY];
// Output only. The last update timestamp.
google.protobuf.Timestamp update_time = 11 [(google.api.field_behavior) = OUTPUT_ONLY];
// User role enumeration.
enum Role {
ROLE_UNSPECIFIED = 0;
// Admin role with system access.
ADMIN = 2;
// User role with limited access.
USER = 3;
}
}
message ListUsersRequest {
// Optional. The maximum number of users to return.
// The service may return fewer than this value.
// If unspecified, at most 50 users will be returned.
// The maximum value is 1000; values above 1000 will be coerced to 1000.
int32 page_size = 1 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token, received from a previous `ListUsers` call.
// Provide this to retrieve the subsequent page.
string page_token = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. Filter to apply to the list results.
// Example: "username == 'steven'"
// Supported operators: ==
// Supported fields: username
string filter = 3 [(google.api.field_behavior) = OPTIONAL];
// Optional. If true, show deleted users in the response.
bool show_deleted = 4 [(google.api.field_behavior) = OPTIONAL];
}
message ListUsersResponse {
// The list of users.
repeated User users = 1;
// A token that can be sent as `page_token` to retrieve the next page.
// If this field is omitted, there are no subsequent pages.
string next_page_token = 2;
// The total count of users (may be approximate).
int32 total_size = 3;
}
message GetUserRequest {
// Required. The resource name of the user.
// Supports both numeric IDs and username strings:
// - users/{id} (e.g., users/101)
// - users/{username} (e.g., users/steven)
// Format: users/{id_or_username}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// Optional. The fields to return in the response.
// If not specified, all fields are returned.
google.protobuf.FieldMask read_mask = 2 [(google.api.field_behavior) = OPTIONAL];
}
message CreateUserRequest {
// Required. The user to create.
User user = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.field_behavior) = INPUT_ONLY
];
// Optional. The user ID to use for this user.
// If empty, a unique ID will be generated.
// Must match the pattern [a-z0-9-]+
string user_id = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. If set, validate the request but don't actually create the user.
bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL];
// Optional. An idempotency token that can be used to ensure that multiple
// requests to create a user have the same result.
string request_id = 4 [(google.api.field_behavior) = OPTIONAL];
}
message UpdateUserRequest {
// Required. The user to update.
User user = 1 [(google.api.field_behavior) = REQUIRED];
// Required. The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
// Optional. If set to true, allows updating sensitive fields.
bool allow_missing = 3 [(google.api.field_behavior) = OPTIONAL];
}
message DeleteUserRequest {
// Required. The resource name of the user to delete.
// Format: users/{user}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// Optional. If set to true, the user will be deleted even if they have associated data.
bool force = 2 [(google.api.field_behavior) = OPTIONAL];
}
// User statistics messages
message UserStats {
option (google.api.resource) = {
type: "memos.api.v1/UserStats"
pattern: "users/{user}"
singular: "userStats"
plural: "userStats"
};
// The resource name of the user whose stats these are.
// Format: users/{user}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// The timestamps when the memos were displayed.
repeated google.protobuf.Timestamp memo_display_timestamps = 2;
// The stats of memo types.
MemoTypeStats memo_type_stats = 3;
// The count of tags.
map<string, int32> tag_count = 4;
// The pinned memos of the user.
repeated string pinned_memos = 5;
// Total memo count.
int32 total_memo_count = 6;
// Memo type statistics.
message MemoTypeStats {
int32 link_count = 1;
int32 code_count = 2;
int32 todo_count = 3;
int32 undo_count = 4;
}
}
message GetUserStatsRequest {
// Required. The resource name of the user.
// Format: users/{user}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
}
message ListAllUserStatsRequest {
// This endpoint doesn't take any parameters.
}
message ListAllUserStatsResponse {
// The list of user statistics.
repeated UserStats stats = 1;
}
// User settings message
message UserSetting {
option (google.api.resource) = {
type: "memos.api.v1/UserSetting"
pattern: "users/{user}/settings/{setting}"
singular: "userSetting"
plural: "userSettings"
};
// The name of the user setting.
// Format: users/{user}/settings/{setting}, {setting} is the key for the setting.
// For example, "users/123/settings/GENERAL" for general settings.
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
oneof value {
GeneralSetting general_setting = 2;
WebhooksSetting webhooks_setting = 5;
}
// Enumeration of user setting keys.
enum Key {
KEY_UNSPECIFIED = 0;
// GENERAL is the key for general user settings.
GENERAL = 1;
// WEBHOOKS is the key for user webhooks.
WEBHOOKS = 4;
}
// General user settings configuration.
message GeneralSetting {
// The preferred locale of the user.
string locale = 1 [(google.api.field_behavior) = OPTIONAL];
// The default visibility of the memo.
string memo_visibility = 3 [(google.api.field_behavior) = OPTIONAL];
// The preferred theme of the user.
// This references a CSS file in the web/public/themes/ directory.
// If not set, the default theme will be used.
string theme = 4 [(google.api.field_behavior) = OPTIONAL];
}
// User webhooks configuration.
message WebhooksSetting {
// List of user webhooks.
repeated UserWebhook webhooks = 1;
}
}
message GetUserSettingRequest {
// Required. The resource name of the user setting.
// Format: users/{user}/settings/{setting}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/UserSetting"}
];
}
message UpdateUserSettingRequest {
// Required. The user setting to update.
UserSetting setting = 1 [(google.api.field_behavior) = REQUIRED];
// Required. The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
}
// Request message for ListUserSettings method.
message ListUserSettingsRequest {
// Required. The parent resource whose settings will be listed.
// Format: users/{user}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// Optional. The maximum number of settings to return.
// The service may return fewer than this value.
// If unspecified, at most 50 settings will be returned.
// The maximum value is 1000; values above 1000 will be coerced to 1000.
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token, received from a previous `ListUserSettings` call.
// Provide this to retrieve the subsequent page.
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}
// Response message for ListUserSettings method.
message ListUserSettingsResponse {
// The list of user settings.
repeated UserSetting settings = 1;
// A token that can be sent as `page_token` to retrieve the next page.
// If this field is omitted, there are no subsequent pages.
string next_page_token = 2;
// The total count of settings (may be approximate).
int32 total_size = 3;
}
// PersonalAccessToken represents a long-lived token for API/script access.
// PATs are distinct from short-lived JWT access tokens used for session authentication.
message PersonalAccessToken {
option (google.api.resource) = {
type: "memos.api.v1/PersonalAccessToken"
pattern: "users/{user}/personalAccessTokens/{personal_access_token}"
singular: "personalAccessToken"
plural: "personalAccessTokens"
};
// The resource name of the personal access token.
// Format: users/{user}/personalAccessTokens/{personal_access_token}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
// The description of the token.
string description = 2 [(google.api.field_behavior) = OPTIONAL];
// Output only. The creation timestamp.
google.protobuf.Timestamp created_at = 3 [(google.api.field_behavior) = OUTPUT_ONLY];
// Optional. The expiration timestamp.
google.protobuf.Timestamp expires_at = 4 [(google.api.field_behavior) = OPTIONAL];
// Output only. The last used timestamp.
google.protobuf.Timestamp last_used_at = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
}
message ListPersonalAccessTokensRequest {
// Required. The parent resource whose personal access tokens will be listed.
// Format: users/{user}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// Optional. The maximum number of tokens to return.
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. A page token for pagination.
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}
message ListPersonalAccessTokensResponse {
// The list of personal access tokens.
repeated PersonalAccessToken personal_access_tokens = 1;
// A token for the next page of results.
string next_page_token = 2;
// The total count of personal access tokens.
int32 total_size = 3;
}
message CreatePersonalAccessTokenRequest {
// Required. The parent resource where this token will be created.
// Format: users/{user}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// Optional. Description of the personal access token.
string description = 2 [(google.api.field_behavior) = OPTIONAL];
// Optional. Expiration duration in days (0 = never expires).
int32 expires_in_days = 3 [(google.api.field_behavior) = OPTIONAL];
}
message CreatePersonalAccessTokenResponse {
// The personal access token metadata.
PersonalAccessToken personal_access_token = 1;
// The actual token value - only returned on creation.
// This is the only time the token value will be visible.
string token = 2;
}
message DeletePersonalAccessTokenRequest {
// Required. The resource name of the personal access token to delete.
// Format: users/{user}/personalAccessTokens/{personal_access_token}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/PersonalAccessToken"}
];
}
// UserWebhook represents a webhook owned by a user.
message UserWebhook {
// The name of the webhook.
// Format: users/{user}/webhooks/{webhook}
string name = 1;
// The URL to send the webhook to.
string url = 2;
// Optional. Human-readable name for the webhook.
string display_name = 3;
// The creation time of the webhook.
google.protobuf.Timestamp create_time = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
// The last update time of the webhook.
google.protobuf.Timestamp update_time = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
}
message ListUserWebhooksRequest {
// The parent user resource.
// Format: users/{user}
string parent = 1 [(google.api.field_behavior) = REQUIRED];
}
message ListUserWebhooksResponse {
// The list of webhooks.
repeated UserWebhook webhooks = 1;
}
message CreateUserWebhookRequest {
// The parent user resource.
// Format: users/{user}
string parent = 1 [(google.api.field_behavior) = REQUIRED];
// The webhook to create.
UserWebhook webhook = 2 [(google.api.field_behavior) = REQUIRED];
}
message UpdateUserWebhookRequest {
// The webhook to update.
UserWebhook webhook = 1 [(google.api.field_behavior) = REQUIRED];
// The list of fields to update.
google.protobuf.FieldMask update_mask = 2;
}
message DeleteUserWebhookRequest {
// The name of the webhook to delete.
// Format: users/{user}/webhooks/{webhook}
string name = 1 [(google.api.field_behavior) = REQUIRED];
}
message UserNotification {
option (google.api.resource) = {
type: "memos.api.v1/UserNotification"
pattern: "users/{user}/notifications/{notification}"
name_field: "name"
singular: "notification"
plural: "notifications"
};
// The resource name of the notification.
// Format: users/{user}/notifications/{notification}
string name = 1 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.field_behavior) = IDENTIFIER
];
// The sender of the notification.
// Format: users/{user}
string sender = 2 [
(google.api.field_behavior) = OUTPUT_ONLY,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
// The status of the notification.
Status status = 3 [(google.api.field_behavior) = OPTIONAL];
// The creation timestamp.
google.protobuf.Timestamp create_time = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
// The type of the notification.
Type type = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
// The activity ID associated with this notification.
optional int32 activity_id = 6 [(google.api.field_behavior) = OPTIONAL];
enum Status {
STATUS_UNSPECIFIED = 0;
UNREAD = 1;
ARCHIVED = 2;
}
enum Type {
TYPE_UNSPECIFIED = 0;
MEMO_COMMENT = 1;
}
}
message ListUserNotificationsRequest {
// The parent user resource.
// Format: users/{user}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/User"}
];
int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];
string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
string filter = 4 [(google.api.field_behavior) = OPTIONAL];
}
message ListUserNotificationsResponse {
repeated UserNotification notifications = 1;
string next_page_token = 2;
}
message UpdateUserNotificationRequest {
UserNotification notification = 1 [(google.api.field_behavior) = REQUIRED];
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED];
}
message DeleteUserNotificationRequest {
// Format: users/{user}/notifications/{notification}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/UserNotification"}
];
}