Offside

Referência de API

English · Voltar às docs

Todos os tipos públicos, em uma página. A documentação XML enviada com os pacotes é a versão autoritativa — esta página serve para consulta rápida.

Offside

Namespace Offside.

ErrorKind

public enum ErrorKind
{
    Unexpected, Unauthorized, Forbidden, TooManyRequests, Conflict,
    PreconditionFailed, Gone, Unprocessable, NotFound, Validation, BadRequest
}

O conjunto fechado de espécies de falha. Seleciona o status HTTP e o rank de severidade. A ordem de declaração não é a ordem de severidade — veja as tabelas de status e severidade.

Error

public sealed class Error : IEquatable<Error>
Membro Descrição
string Code { get; } Identificador estável e chave no catálogo de mensagens
ErrorKind Kind { get; } Espécie da falha
IReadOnlyDictionary<string, object?> Arguments { get; } Snapshot somente leitura dos valores do template
string? Field { get; } Campo culpado, quando atribuível
static Error NotFound(string resource, object? id = null) Código not_found
static Error Gone(string resource, object? id = null) Código gone
static Error Conflict(string resource, string? reason = null) Código conflict
static Error Validation(string field, string? code = null, object? attemptedValue = null) Código validation ou code; preenche Field
static Error BadRequest(string? reason = null) Código bad_request
static Error Unauthorized(string? reason = null) Código unauthorized
static Error Forbidden(string? reason = null) Código forbidden
static Error PreconditionFailed(string? reason = null) Código precondition_failed
static Error Unprocessable(string? reason = null) Código unprocessable
static Error TooManyRequests(string? reason = null) Código too_many_requests
static Error Unexpected(string? detail = null) Código unexpected; detail é apenas diagnóstico
static Error Custom(string code, ErrorKind kind, object? arguments = null, string? field = null) Erro de regra de negócio. Lança ArgumentException com código em branco
DomainException ToException() Escape hatch
bool Equals(Error?), operator ==, operator != Igualdade por valor, argumentos incluídos

O construtor é interno; a construção passa pelas factories.

Result

public readonly struct Result
Membro Descrição
bool IsSuccess { get; } / bool IsFailure { get; } Desfecho
IReadOnlyList<Error> Errors { get; } Erros na falha; vazio no sucesso
TOut Match<TOut>(Func<TOut> onSuccess, Func<IReadOnlyList<Error>, TOut> onFailure) Ramifica para um valor
static Result Success() Sucesso
static Result Failure(params Error[] errors) Falha. Lança ArgumentException se vazio
static Result Failure(IEnumerable<Error> errors) Falha a partir de uma sequência, copiada na hora
static Result Combine(params Result[] results) Funde, concatenando erros na ordem dos argumentos
static Result Combine<T>(params Result<T>[] results) Funde resultados com valor, descartando os valores

default(Result) é sucesso.

Result<T>

public readonly struct Result<T>
Membro Descrição
bool IsSuccess { get; } / bool IsFailure { get; } Desfecho
T Value { get; } O valor. Lança InvalidOperationException na falha
IReadOnlyList<Error> Errors { get; } Erros na falha; vazio no sucesso
bool TryGetValue(out T value) Leitura que não lança
TOut Match<TOut>(Func<T, TOut> onSuccess, Func<IReadOnlyList<Error>, TOut> onFailure) Ramifica para um valor
Result<TOut> Map<TOut>(Func<T, TOut> map) Transforma o valor; short-circuit na falha
Result<TOut> Bind<TOut>(Func<T, Result<TOut>> bind) Encadeia operação falível; short-circuit na falha
static Result<T> Success(T value) Sucesso
static Result<T> Failure(params Error[] errors) Falha. Lança ArgumentException se vazio
static Result<T> Failure(IEnumerable<Error> errors) Falha a partir de uma sequência, copiada na hora

Sem conversão implícita de T, e sem Apply — veja ausências deliberadas.

DomainException

public sealed class DomainException : Exception
{
    public IReadOnlyList<Error> Errors { get; }
    public DomainException(IReadOnlyList<Error> errors);
}

Message é o Code do primeiro erro. Produzida por Error.ToException().

IErrorMessageResolver

public interface IErrorMessageResolver
{
    string GetMessage(Error error, CultureInfo culture);
}

Implemente para buscar mensagens fora do JSON. Por convenção, devolva error.Code quando nenhuma mensagem for encontrada.

JsonErrorCatalog

public sealed class JsonErrorCatalog
{
    public CultureInfo Culture { get; }
    public Stream Json { get; }
    public JsonErrorCatalog(CultureInfo culture, Stream json);
}

Lança ArgumentNullException com cultura ou stream nulos.

JsonErrorMessageResolver

public sealed class JsonErrorMessageResolver : IErrorMessageResolver
{
    public JsonErrorMessageResolver(IEnumerable<JsonErrorCatalog> catalogs);
    public string GetMessage(Error error, CultureInfo culture);
}

Parseia todos os catálogos no construtor. Lança InvalidOperationException quando nenhum catálogo invariante é fornecido. Ordem de busca: cultura exata → pai → invariante; depois o próprio código.

OffsideOptions

public sealed class OffsideOptions
{
    public OffsideOptions AddJson(CultureInfo culture, string json);
    public OffsideOptions AddJson(CultureInfo culture, Stream json);
}

As duas sobrecargas recebem o conteúdo do catálogo, não um caminho. Fluente.

OffsideServiceCollectionExtensions

public static IServiceCollection AddOffside(this IServiceCollection services, Action<OffsideOptions> configure);

Constrói um JsonErrorMessageResolver de forma ansiosa e o registra como o singleton IErrorMessageResolver.

Offside.AspNetCore

Namespace Offside.AspNetCore.

OffsideAspNetCoreOptions

public sealed class OffsideAspNetCoreOptions
{
    public bool ExposeExceptionDetails { get; set; }
    public static OffsideAspNetCoreOptions FromEnvironment(IHostEnvironment environment);
}

ExposeExceptionDetails controla apenas o campo debug; o detail visível ao cliente em um 500 é sempre a mensagem genérica.

OffsideAspNetCoreServiceCollectionExtensions

public static IServiceCollection AddOffsideAspNetCore(this IServiceCollection services);

Registra OffsideAspNetCoreOptions como singleton, com ExposeExceptionDetails vindo de IHostEnvironment.IsDevelopment() quando há um presente, senão false.

OffsideProblem

public sealed class OffsideProblem
{
    public required string Type { get; init; }
    public required string Title { get; init; }
    public int Status { get; init; }
    public required string Detail { get; init; }
    public required string TraceId { get; init; }
    public string? Debug { get; init; }              // omitido do JSON quando nulo
    public required IReadOnlyList<Item> Errors { get; init; }

    public static OffsideProblem Create(
        IReadOnlyList<Error> errors,
        IErrorMessageResolver resolver,
        CultureInfo culture,
        string traceId,
        bool exposeExceptionDetails = false);

    public sealed class Item
    {
        public required string Code { get; init; }
        public required string Kind { get; init; }
        public required string Detail { get; init; }
        public string? Field { get; init; }
    }
}

Serializado como application/problem+json com nomes em camelCase. Veja o formato da resposta.

ResultHttpExtensions

public static class ResultHttpExtensions

Minimal APIs — sucesso é 204 No Content para Result, 200 OK com o valor para Result<T>:

IResult ToHttpResult(this Result result, IErrorMessageResolver resolver, bool exposeExceptionDetails = false);
IResult ToHttpResult(this Result result, IErrorMessageResolver resolver, CultureInfo culture, bool exposeExceptionDetails = false);
IResult ToHttpResult(this Result result, IErrorMessageResolver resolver, CultureInfo? culture, OffsideAspNetCoreOptions options);
IResult ToHttpResult(this Result result, HttpContext httpContext);

IResult ToHttpResult<T>(this Result<T> result, IErrorMessageResolver resolver, bool exposeExceptionDetails = false);
IResult ToHttpResult<T>(this Result<T> result, IErrorMessageResolver resolver, CultureInfo culture, bool exposeExceptionDetails = false);
IResult ToHttpResult<T>(this Result<T> result, IErrorMessageResolver resolver, CultureInfo? culture, OffsideAspNetCoreOptions options);
IResult ToHttpResult<T>(this Result<T> result, HttpContext httpContext);

Controllers MVC — sucesso é NoContentResult / OkObjectResult:

IActionResult ToActionResult(this Result result, IErrorMessageResolver resolver, CultureInfo culture, bool exposeExceptionDetails = false);
IActionResult ToActionResult(this Result result, IErrorMessageResolver resolver, CultureInfo? culture, OffsideAspNetCoreOptions options);

IActionResult ToActionResult<T>(this Result<T> result, IErrorMessageResolver resolver, bool exposeExceptionDetails = false);
IActionResult ToActionResult<T>(this Result<T> result, IErrorMessageResolver resolver, CultureInfo culture, bool exposeExceptionDetails = false);
IActionResult ToActionResult<T>(this Result<T> result, IErrorMessageResolver resolver, CultureInfo? culture, OffsideAspNetCoreOptions options);

Note a assimetria: não existe ToActionResult(this Result, IErrorMessageResolver, bool) para o Result unitário. Passe uma cultura, ou passe null pela sobrecarga com options.

Uma cultura null significa “derive do Accept-Language”. Todas as sobrecargas lançam ArgumentNullException com resolver, options ou HttpContext nulos.

Offside.Tool

Namespace Offside.Tool.

SkillInstaller

public sealed class SkillInstaller
{
    public const string CursorSkills = ".cursor/skills";
    public const string AgentsSkills = ".agents/skills";
    public const string ClaudeSkills = ".claude/skills";

    public SkillInstaller(string skillsSource);
    public static SkillInstaller FromToolLocation();
    public IReadOnlyList<string> Install(string projectRoot, bool force);
}

Install devolve todo caminho escrito, na ordem de escrita. Lança DirectoryNotFoundException quando a origem das skills ou uma pasta de skill esperada está faltando. Veja a página do CLI.