jsonshape

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package jsonshape provides protocol-neutral JSON size and shape preflight using encoding/json.Decoder.Token. It is shared by frontend request-body guards and tool-call schema/argument hardening. Errors never include payload bytes, keys, or values. Request envelopes keep duplicate-member acceptance; tool schema and tool argument profiles reject duplicate names.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Error

type Error struct {
	Kind   Kind
	Reason MalformedReason
	Limit  int
	Value  int
	Msg    string
	// contains filtered or unexported fields
}

Error is a typed JSON shape guard failure. Msg must never include payload, keys, or values from the scanned input.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type Event

type Event struct {
	Type     EventType
	Offset   int64
	Length   int64
	Span     Span
	Depth    int
	Key      string
	Path     []string
	TopLevel bool
}

Event describes a syntactic token event in the JSON stream. Giant scalar string contents are never retained in Event.

func (Event) IsTopLevelKey

func (e Event) IsTopLevelKey(key string) bool

IsTopLevelKey reports whether the event is an immediate member of the root object matching key.

type EventHandler

type EventHandler interface {
	OnEvent(e Event) error
}

EventHandler receives stream events during scanning.

type EventHandlerFunc

type EventHandlerFunc func(e Event) error

EventHandlerFunc is an adapter to allow ordinary functions as EventHandler.

func (EventHandlerFunc) OnEvent

func (f EventHandlerFunc) OnEvent(e Event) error

type EventType

type EventType uint8

EventType represents the syntactic token event observed during scanning.

const (
	EventNone EventType = iota
	EventObjectStart
	EventObjectEnd
	EventArrayStart
	EventArrayEnd
	EventKey
	EventString
	EventNumber
	EventTrue
	EventFalse
	EventNull
)

type Kind

type Kind string

Kind classifies guard failures with stable, payload-free labels.

const (
	KindTooLarge      Kind = "too_large"
	KindMalformed     Kind = "malformed"
	KindTooDeep       Kind = "too_deep"
	KindTooManyTokens Kind = "too_many_tokens"
	KindTooManyItems  Kind = "too_many_items"
	KindStringTooLong Kind = "string_too_long"
	KindKeyTooLong    Kind = "key_too_long"
	KindNumberTooLong Kind = "number_too_long"
	KindDuplicateName Kind = "duplicate_name"
	KindInvalidUTF8   Kind = "invalid_utf8"
	KindCanceled      Kind = "canceled"
)

func Classify

func Classify(err error) Kind

Classify returns the guard kind for typed guard errors.

type Limits

type Limits struct {
	MaxBytes             int64
	MaxDepth             int
	MaxTokens            int
	MaxArrayElems        int
	MaxObjectKeys        int
	MaxStringBytes       int
	MaxKeyBytes          int
	MaxNumberBytes       int
	RejectDuplicateNames bool
}

Limits bounds JSON size and structural complexity before decode/use. Zero or negative numeric fields are filled by NormalizeLimits / NormalizeWithDefaults. RejectDuplicateNames is never normalized: false means accept duplicate object member names (encoding/json last-wins semantics); true means reject them. Full profiles set the flag explicitly; partial Limits keep the zero value (false).

func NormalizeLimits

func NormalizeLimits(limits Limits) Limits

NormalizeLimits fills zero or negative numeric fields from RequestEnvelopeLimits. Frontend request-envelope callers may keep using this. Schema and tool-argument call sites must instead normalize with ToolSchemaLimits or ToolArgumentsLimits via NormalizeWithDefaults or Limits.Normalized. RejectDuplicateNames is left as-is (RequestEnvelope defaults false when callers omit it).

func NormalizeWithDefaults

func NormalizeWithDefaults(limits, defaults Limits) Limits

NormalizeWithDefaults fills zero or negative numeric fields from defaults. RejectDuplicateNames is not copied from defaults: callers that need rejection must set it on the input Limits (profiles do). Pass ToolSchemaLimits or ToolArgumentsLimits as defaults for those profiles; do not rely on NormalizeLimits (envelope) for schema/args paths.

func RequestEnvelopeLimits

func RequestEnvelopeLimits() Limits

RequestEnvelopeLimits matches historical frontend jsonguard defaults: 8 MiB, depth 128, high fan-out, and RejectDuplicateNames=false so accepted multimodal envelopes keep encoding/json last-wins duplicate-member semantics.

func ToolArgumentsLimits

func ToolArgumentsLimits() Limits

ToolArgumentsLimits matches the 64 KiB tool-arguments byte default with depth 64, bounded fan-out/number length, and RejectDuplicateNames=true. toolcallrepair adapts MaxBytes from MaxArgsBytes and keeps MaxDepth from this profile.

func ToolSchemaLimits

func ToolSchemaLimits() Limits

ToolSchemaLimits matches tool-call-repair schema defaults (256 KiB / depth 32 / 4096 semantic nodes / 1024 members) and rejects duplicate member names. MaxTokens is an 8x-nodes token budget; structural node caps remain in toolcallrepair pre-scan. Local $ref depth stays separate.

func (Limits) Normalized

func (limits Limits) Normalized(defaults Limits) Limits

Normalized returns limits with zero or negative numeric fields filled from defaults.

type MalformedReason

type MalformedReason string

MalformedReason identifies the stable structural reason for malformed JSON.

const (
	MalformedEmpty             MalformedReason = "empty"
	MalformedSyntax            MalformedReason = "syntax"
	MalformedMultipleValues    MalformedReason = "multiple_values"
	MalformedUnexpectedClosing MalformedReason = "unexpected_closing"
	MalformedIncomplete        MalformedReason = "incomplete"
	MalformedTrailingData      MalformedReason = "trailing_data"
	MalformedObjectValue       MalformedReason = "object_value_without_key"
)

type Option

type Option func(*Scanner)

Option configures a Scanner.

func WithEventHandler

func WithEventHandler(h EventHandler) Option

WithEventHandler registers an event handler on the scanner.

func WithStringWriterResolver

func WithStringWriterResolver(r StringWriterResolver) Option

WithStringWriterResolver configures a resolver for streaming string values.

func WithTrackedTopLevelSpans

func WithTrackedTopLevelSpans(keys ...string) Option

WithTrackedTopLevelSpans configures the scanner to record exact spans for selected top-level keys.

type Result

type Result struct {
	Bytes    int
	Tokens   int
	MaxDepth int
}

Result reports basic facts gathered during token-level scanning.

func Preflight

func Preflight(data []byte, limits Limits) (Result, error)

Preflight validates JSON size and shape using encoding/json.Decoder.Token.

func PreflightWithContext

func PreflightWithContext(ctx context.Context, data []byte, limits Limits) (Result, error)

PreflightWithContext is Preflight with cancellation checks at token boundaries.

type Scanner

type Scanner struct {
	// contains filtered or unexported fields
}

Scanner performs incremental JSON safety scanning and token event emission.

func NewScanner

func NewScanner(ctx context.Context, limits Limits, opts ...Option) *Scanner

NewScanner constructs an incremental JSON safety scanner with normalized limits.

func (*Scanner) End

func (s *Scanner) End() (Result, error)

End is an alias for Finish.

func (*Scanner) Feed

func (s *Scanner) Feed(chunk []byte) error

Feed processes an incremental chunk of JSON bytes.

func (*Scanner) Finish

func (s *Scanner) Finish() (Result, error)

Finish signals end-of-stream and validates that the JSON document is complete.

func (*Scanner) Result

func (s *Scanner) Result() Result

Result returns the current validation facts.

func (*Scanner) SetEventHandler

func (s *Scanner) SetEventHandler(h EventHandler)

SetEventHandler sets or updates the event handler.

func (*Scanner) TopLevelSpan

func (s *Scanner) TopLevelSpan(key string) (Span, bool)

TopLevelSpan returns the recorded raw span for the selected top-level key.

func (*Scanner) TopLevelSpans

func (s *Scanner) TopLevelSpans() map[string]Span

TopLevelSpans returns all recorded top-level spans.

type Span

type Span struct {
	Offset int64
	Length int64
}

Span represents an exact raw byte range [Offset, Offset+Length) in the source stream.

func (Span) End

func (s Span) End() (int64, error)

End returns the exclusive end offset using checked int64 math.

func (Span) Validate

func (s Span) Validate() error

Validate rejects negative bounds and checked-int64 overflow.

type StringContext

type StringContext struct {
	Key      string
	Path     []string
	TopLevel bool
}

StringContext describes the syntactic position of a string value being scanned.

type StringWriterResolver

type StringWriterResolver func(ctx StringContext) (io.Writer, error)

StringWriterResolver resolves an optional io.Writer to receive unescaped string bytes as they are decoded during scanning. If the resolved writer implements io.Closer, it will be closed when the string ends or scanning terminates.

type TopLevelSpanTracker

type TopLevelSpanTracker struct {
	// contains filtered or unexported fields
}

TopLevelSpanTracker collects exact raw byte spans for selected top-level object values. It discriminates nested keys and values, recording only immediate root-object values.

func NewTopLevelSpanTracker

func NewTopLevelSpanTracker(keys ...string) *TopLevelSpanTracker

NewTopLevelSpanTracker creates a tracker for the provided top-level keys.

func (*TopLevelSpanTracker) Count

func (t *TopLevelSpanTracker) Count(key string) int

Count returns the number of times a top-level value was recorded for the given key.

func (*TopLevelSpanTracker) HasDuplicate

func (t *TopLevelSpanTracker) HasDuplicate(key string) bool

HasDuplicate reports whether more than one top-level value was encountered for the given key.

func (*TopLevelSpanTracker) OnEvent

func (t *TopLevelSpanTracker) OnEvent(e Event) error

OnEvent implements EventHandler.

func (*TopLevelSpanTracker) Span

func (t *TopLevelSpanTracker) Span(key string) (Span, bool)

Span returns the recorded raw byte span for the given top-level key.

func (*TopLevelSpanTracker) Spans

func (t *TopLevelSpanTracker) Spans() map[string]Span

Spans returns a copy of all recorded top-level spans.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL