Files
dingtalk-workspace-cli/pkg/authretry/authretry.go
xianfeng wang bbca507792 feat(discovery): MCP discovery service abstraction with positional params, examples, defaults, and schema v3 extensions (#156)
* discovery

* discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* discovery example and default

* position param

* Fix test

* dev auto login

* fix test

* fix conflict
2026-04-24 14:08:17 +08:00

75 lines
2.6 KiB
Go

// Copyright 2026 Alibaba Group
// 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.
// Package authretry exposes the AuthRefreshRequired marker error used by
// edition overlays (in separate Go modules) to signal "the current access
// token was rejected by the server; please run a force-refresh and retry".
//
// The package has no dependencies beyond the standard library so it can be
// imported by both the runner (internal/app) and external overlays without
// creating import cycles with packages such as pkg/runtimetoken.
package authretry
import (
stderrors "errors"
)
// AuthRefreshRequired is a marker error returned by overlays (typically from
// the edition's ClassifyToolResult or OnAuthError hook) to ask the runner to
// perform a one-shot ForceRefresh of the access token and retry the current
// invocation.
//
// Open-source code paths never produce this type, so the runner's retry
// branch is a no-op for editions that don't opt in.
type AuthRefreshRequired struct {
// Cause is the underlying user-facing error. The runner returns Cause
// (not the wrapper) when refresh fails or the retry budget is exhausted,
// so end users always see the original diagnostic instead of an internal
// "auth refresh required" message.
Cause error
}
// Error returns the underlying cause's message, or a generic fallback when
// Cause is nil.
func (e *AuthRefreshRequired) Error() string {
if e == nil || e.Cause == nil {
return "authentication refresh required"
}
return e.Cause.Error()
}
// Unwrap exposes the underlying cause to errors.Is / errors.As.
func (e *AuthRefreshRequired) Unwrap() error {
if e == nil {
return nil
}
return e.Cause
}
// As walks the error chain and returns the first *AuthRefreshRequired it
// finds, along with true. Returns nil, false otherwise.
//
// Use this instead of a plain errors.As when callers care about acting on
// the marker (force-refresh + retry) rather than just identifying the
// underlying error class.
func As(err error) (*AuthRefreshRequired, bool) {
if err == nil {
return nil, false
}
var target *AuthRefreshRequired
if stderrors.As(err, &target) {
return target, true
}
return nil, false
}