Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions lib/node/pl-client/proto/plapi/plapiproto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ service Platform {
}
rpc ListUserResources(AuthAPI.ListUserResources.Request) returns (stream AuthAPI.ListUserResources.Response) {}

rpc ListUsers(AuthAPI.ListUsers.Request) returns (AuthAPI.ListUsers.Response) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Unlike other unary RPCs in the Platform service, ListUsers is missing the google.api.http option. If this RPC needs to be accessible via the REST gateway (e.g., for the admin panel or external REST clients), please add the appropriate HTTP option.

Example:

rpc ListUsers(AuthAPI.ListUsers.Request) returns (AuthAPI.ListUsers.Response) {
  option (google.api.http) = {
    get: "/v1/users"
  };
}
Suggested change
rpc ListUsers(AuthAPI.ListUsers.Request) returns (AuthAPI.ListUsers.Response) {}
rpc ListUsers(AuthAPI.ListUsers.Request) returns (AuthAPI.ListUsers.Response) {
option (google.api.http) = {
get: "/v1/users"
};
}


//
// Other stuff
//
Expand All @@ -275,6 +277,28 @@ service Platform {
rpc License(MaintenanceAPI.License.Request) returns (MaintenanceAPI.License.Response) {
option (google.api.http) = {get: "/v1/license"};
}

//
// Command bus (admin panel and future extension points)
//
// Query dispatches a named read-only command. The server opens a read
// transaction, runs the registered handler, and returns a JSON result.
// The dispatcher enforces per-command role requirements before running.
rpc Query(CommandAPI.Command) returns (CommandAPI.CommandResult) {
option (google.api.http) = {
post: "/v1/command/query"
body: "*"
};
}
// Mutation dispatches a named write command. The server opens a write
// transaction, runs the registered handler, and commits on success.
// The dispatcher enforces per-command role requirements before running.
rpc Mutation(CommandAPI.Command) returns (CommandAPI.CommandResult) {
option (google.api.http) = {
post: "/v1/command/mutation"
body: "*"
};
}
}

// Platform transactions at the API level are implemented as bidirectional
Expand Down Expand Up @@ -483,6 +507,7 @@ message TxAPI {

AuthAPI.GrantAccess.Request grant_access = 410; // grant access to a resource within transaction
AuthAPI.RevokeAccess.Request revoke_access = 411; // revoke access to a resource within transaction
AuthAPI.ListGrants.Request list_grants = 412; // list grants on a resource within transaction
}
}

Expand Down Expand Up @@ -585,6 +610,7 @@ message TxAPI {

AuthAPI.GrantAccess.Response grant_access = 410;
AuthAPI.RevokeAccess.Response revoke_access = 411;
AuthAPI.ListGrants.TxResponse list_grants = 412;
}

google.rpc.Status error = 3;
Expand Down Expand Up @@ -1866,6 +1892,10 @@ message AuthAPI {
message Response {
Grant grant = 1; // one per stream message
}

message TxResponse {
repeated Grant grants = 1; // all grants for the resource in a single transactional response
}
}

message Grant {
Expand Down Expand Up @@ -1948,6 +1978,23 @@ message AuthAPI {
Grant.Permissions permissions = 4;
}
}

message User {
// login is the stable identifier of the user — the grant target and the
// GetUserRoot key. Further fields (e.g. first name, last name, email) may
// be added later without breaking compatibility.
string login = 1;
}

message ListUsers {
message Request {}

// Lists users known to the server. A user becomes known on first login;
// provisioned users who have never logged in do not appear.
message Response {
repeated User users = 1;
}
}
Comment on lines +1989 to +1997

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ListUsers RPC currently returns all users in a single unpaginated list. If the number of users grows large, this can lead to performance bottlenecks, high memory usage, or exceeding gRPC message size limits.

Consider adding pagination fields (such as limit and offset/after or page tokens) to ListUsers.Request and ListUsers.Response to ensure the API scales efficiently.

}

message MiscAPI {
Expand Down Expand Up @@ -2021,6 +2068,38 @@ message MaintenanceAPI {
}
}

// CommandAPI groups all message types used by the command-bus RPCs
// (Query and Mutation). The proto contract is frozen; future commands
// are added by registering new handler names on the server — no proto
// changes are needed.
message CommandAPI {
// Command carries a named command with an optional JSON payload.
message Command {
// name identifies the registered handler (e.g. "users.list").
// Must be non-empty.
string name = 1;
// payload is an opaque JSON object passed verbatim to the handler.
// May be empty when a command takes no arguments.
bytes payload = 2;
Comment on lines +2081 to +2083

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since Query and Mutation are exposed via REST transcoding (google.api.http), using bytes for payload will cause the JSON transcoder to expect a base64-encoded string instead of a raw JSON object. This makes the REST API less intuitive to consume.

To allow clients to pass raw JSON objects directly, consider importing google/protobuf/struct.proto and using google.protobuf.Value or google.protobuf.Struct instead of bytes.

}

// CmdError is a structured application-level error returned inside
// CommandResult. It is separate from gRPC status codes, which are
// reserved for transport-level failures.
message CmdError {
string message = 1;
string code = 2;
}

// CommandResult carries the JSON response from a handler and any
// application-level errors it produced.
message CommandResult {
// data is the JSON-encoded result. Empty when errors is non-empty.
bytes data = 1;
Comment on lines +2097 to +2098

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since Query and Mutation are exposed via REST transcoding (google.api.http), using bytes for data in CommandResult will cause the JSON transcoder to return a base64-encoded string instead of a raw JSON object.

To allow clients to receive raw JSON objects directly, consider importing google/protobuf/struct.proto and using google.protobuf.Value or google.protobuf.Struct instead of bytes.

repeated CmdError errors = 2;
}
}

message Util {
message Deprecated {}
}
Loading
Loading