Files
larksuite__cli/internal/output/envelope_success.go
sang-neo03 59f6ad4900 fix(output): preserve non-data payloads in the api success envelope (#2601)
* fix: preserve non-data payload keys in SuccessEnvelopeData

When an API response uses a non-"data" key (e.g., /bot/v3/info returns
payload under "bot"), the previous implementation discarded the payload
and returned an empty object. Fall back to the envelope minus transport
fields (code, msg, data) so the business payload is preserved.

Fixes #2428

(cherry picked from commit a82585718c)

* fix(output): pass non-object bodies through and pin api envelope at command level

Follow-up to the cherry-picked fix for #2428: return nil bodies as {} and
non-object bodies untouched instead of collapsing them, align the new test
with its neighbours, and add cmd/api regression tests through the httpmock
path so the user-visible envelope is pinned where the bug was reported.

* test(output): pin null data with sibling payload, drop SDK-pinned array test

TestApiCmd_NonObjectBody_FailsLoudly asserted the SDK's pre-decode rejection
of non-object bodies, not the output-layer branch this PR added; reverting
that branch left it green. The unit test already covers the branch, so the
command-level copy is removed. Add a unit case for {"data": null, "bot": {..}},
which the previous code collapsed to {} and now returns as {"bot": {..}}.

* fix(output): normalize legacy bot payloads

---------

Co-authored-by: Wu Shuwen <108231307+dajiaohuang@users.noreply.github.com>
Co-authored-by: sang-neo03 <266690410+sang-neo03@users.noreply.github.com>
2026-09-03 01:14:22 +08:00

71 lines
2.1 KiB
Go

// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package output
import "io"
// SuccessEnvelopeOptions configures the shortcut-compatible success envelope.
type SuccessEnvelopeOptions struct {
CommandPath string
Identity string
DryRun bool
JqExpr string
Out io.Writer
ErrOut io.Writer
}
// SuccessEnvelopeData extracts the business payload for the standard success
// envelope from a Lark API response. Outer code/msg fields are transport
// protocol details and are intentionally not exposed as business data.
//
// Most endpoints wrap the payload in "data". The legacy /open-apis/bot/v3/info
// endpoint uses "bot" as that payload container; normalize its sole business
// field to the same data shape. Other non-data responses fall back to everything
// except the transport fields. A non-object body is passed through untouched so
// this function never collapses a payload to {}.
func SuccessEnvelopeData(result interface{}) interface{} {
if result == nil {
return map[string]interface{}{}
}
m, ok := result.(map[string]interface{})
if !ok {
return result
}
if data, ok := m["data"]; ok && data != nil {
return data
}
payload := make(map[string]interface{}, len(m))
for k, v := range m {
if k == "code" || k == "msg" || k == "data" {
continue
}
payload[k] = v
}
if len(payload) == 1 {
if bot, ok := payload["bot"].(map[string]interface{}); ok {
return bot
}
}
return payload
}
// WriteSuccessEnvelope emits the standard success envelope used by shortcuts.
// JSON output carries content-safety alerts inside the envelope. When jq is
// applied, the alert may be filtered away, so warn mode also writes stderr.
func WriteSuccessEnvelope(data interface{}, opts SuccessEnvelopeOptions) error {
return NewEmitter(EmitterConfig{
Out: opts.Out,
ErrOut: opts.ErrOut,
CommandPath: opts.CommandPath,
Identity: opts.Identity,
NoticeProvider: GetNotice,
}).Success(data, EmitOptions{
Format: "",
Raw: false,
JQ: opts.JqExpr,
DryRun: opts.DryRun,
JQSafetyWarning: true,
})
}