handleUpdateMessage applies a labels delta (PATCH v1/agents/{email}/messages/{id}; replaced the now-removed legacy v1 PATCH). This is a per-agent operation, so an agent-scoped credential may label its own messages — it goes through resolveOwnedAgent (which pins an agent-scoped credential to its boun
(ctx context.Context, in *updateMessageInput)
| 414 | // agent.NormalizeAndValidateLabelList so they can't drift from the legacy |
| 415 | // surface; the store enforces the per-message cap. |
| 416 | func (s *Server) handleUpdateMessage(ctx context.Context, in *updateMessageInput) (*updateMessageOutput, error) { |
| 417 | ag, err := s.resolveOwnedAgent(ctx, in.Address) |
| 418 | if err != nil { |
| 419 | return nil, err |
| 420 | } |
| 421 | if s.deps.ModifyMessageLabels == nil { |
| 422 | return nil, NewError(http.StatusInternalServerError, "internal_error", "label update unavailable") |
| 423 | } |
| 424 | add, verr := agent.NormalizeAndValidateLabelList(in.Body.AddLabels, "add") |
| 425 | if verr != nil { |
| 426 | return nil, NewError(http.StatusBadRequest, "invalid_request", verr.Error()) |
| 427 | } |
| 428 | remove, verr := agent.NormalizeAndValidateLabelList(in.Body.RemoveLabels, "remove") |
| 429 | if verr != nil { |
| 430 | return nil, NewError(http.StatusBadRequest, "invalid_request", verr.Error()) |
| 431 | } |
| 432 | final, err := s.deps.ModifyMessageLabels(ctx, in.ID, ag.ID, add, remove) |
| 433 | if err != nil { |
| 434 | switch { |
| 435 | case errors.Is(err, identity.ErrMessageNotFound): |
| 436 | return nil, NewError(http.StatusNotFound, "not_found", "message not found") |
| 437 | case errors.Is(err, identity.ErrLabelLimitExceeded): |
| 438 | return nil, NewError(http.StatusBadRequest, "invalid_request", |
| 439 | fmt.Sprintf("label limit exceeded — a message may carry at most %d labels", identity.MaxLabelsPerMessage)) |
| 440 | default: |
| 441 | return nil, NewError(http.StatusInternalServerError, "internal_error", "failed to update labels") |
| 442 | } |
| 443 | } |
| 444 | return &updateMessageOutput{Body: UpdateMessageResultView{MessageID: in.ID, Labels: orEmptyStrings(final)}}, nil |
| 445 | } |
| 446 | |
| 447 | // handleListMessages ports the legacy list handler: same filter semantics |
| 448 | // and defaults, but the standardized cursor envelope. Validation failures |
nothing calls this directly
no test coverage detected