customsession

package
v0.27.2 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package customsession provides dynamic session payload transformation and dynamic additional fields management.

Index

Constants

View Source
const (
	// EventTransformBefore is emitted immediately before executing session transformation logic.
	EventTransformBefore = "customsession:transform:before"

	// EventTransformAfter is emitted immediately after a successful session transformation.
	EventTransformAfter = "customsession:transform:after"

	// EventTransformError is emitted when session transformation encounters an error.
	EventTransformError = "customsession:transform:error"
)

Event constants for CustomSession plugin lifecycle hooks.

Variables

View Source
var (
	// ErrSessionNotFound is returned when a requested session entity does not exist in storage.
	ErrSessionNotFound = errors.New("customsession: session not found")

	// ErrInvalidTransformResult is returned when a transform callback returns an incompatible data structure.
	ErrInvalidTransformResult = errors.New("customsession: invalid transform result")

	// ErrRepositoryRequired is returned when an operation requires persistent storage but no repository was supplied.
	ErrRepositoryRequired = errors.New("customsession: repository implementation required")
)

Functions

func PreserveResponseHeaders

func PreserveResponseHeaders(w http.ResponseWriter, src http.Header)

PreserveResponseHeaders copies custom headers and Set-Cookie headers from a source Header map to a ResponseWriter.

Types

type AdditionalFieldDefinition

type AdditionalFieldDefinition struct {
	Name         string             `json:"name"`
	Type         FieldType          `json:"type"`
	Required     bool               `json:"required"`
	DefaultValue any                `json:"defaultValue,omitempty"`
	Validator    func(val any) bool `json:"-"`
}

AdditionalFieldDefinition defines metadata, validation, and defaults for dynamic fields on User or Session entities.

type AdditionalFieldsConfig

type AdditionalFieldsConfig struct {
	UserFields    []AdditionalFieldDefinition `json:"userFields"`
	SessionFields []AdditionalFieldDefinition `json:"sessionFields"`
}

AdditionalFieldsConfig holds field definitions for user and session models.

type Config

type Config struct {
	// TransformFunc is an optional custom callback for dynamic session payload transformation.
	TransformFunc TransformSessionFunc

	// MutateListDeviceSessions controls whether session transformation is applied to GET /multi-session/list-device-sessions.
	// Default: false
	MutateListDeviceSessions bool

	// UserAdditionalFields contains definitions for dynamic fields on User entities.
	UserAdditionalFields []AdditionalFieldDefinition

	// SessionAdditionalFields contains definitions for dynamic fields on Session entities.
	SessionAdditionalFields []AdditionalFieldDefinition

	// FilterUnregisteredFields controls whether extra fields not explicitly registered in UserAdditionalFields/SessionAdditionalFields are omitted from response JSON.
	// Default: false
	FilterUnregisteredFields bool
}

Config defines the configuration parameters for the CustomSession plugin.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config struct initialized with recommended defaults.

type CustomSessionData

type CustomSessionData struct {
	User    *entity.User    `json:"user"`
	Session *entity.Session `json:"session"`
	plugin.ExtraContainer
}

CustomSessionData is the standard response container holding user, session, and dynamic extra payload fields.

type FieldType

type FieldType string

FieldType defines the supported data types for dynamic additional fields.

const (
	// FieldTypeString represents a text/string property.
	FieldTypeString FieldType = "string"
	// FieldTypeNumber represents a numeric (int, float) property.
	FieldTypeNumber FieldType = "number"
	// FieldTypeBoolean represents a boolean property.
	FieldTypeBoolean FieldType = "boolean"
	// FieldTypeDate represents a date/time property.
	FieldTypeDate FieldType = "date"
	// FieldTypeObject represents a complex object/map property.
	FieldTypeObject FieldType = "object"
)

type MemoryRepository

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

MemoryRepository provides a thread-safe in-memory implementation of the Repository interface.

func NewMemoryRepository

func NewMemoryRepository() *MemoryRepository

NewMemoryRepository initializes and returns a new thread-safe in-memory custom session repository.

func (*MemoryRepository) GetCustomSessionFields

func (m *MemoryRepository) GetCustomSessionFields(ctx context.Context, sessionID string) (map[string]any, error)

GetCustomSessionFields retrieves dynamic session fields from in-memory storage.

func (*MemoryRepository) GetCustomUserFields

func (m *MemoryRepository) GetCustomUserFields(ctx context.Context, userID string) (map[string]any, error)

GetCustomUserFields retrieves dynamic user fields from in-memory storage.

func (*MemoryRepository) SaveCustomSessionFields

func (m *MemoryRepository) SaveCustomSessionFields(ctx context.Context, sessionID string, fields map[string]any) error

SaveCustomSessionFields stores dynamic session fields in in-memory storage.

func (*MemoryRepository) SaveCustomUserFields

func (m *MemoryRepository) SaveCustomUserFields(ctx context.Context, userID string, fields map[string]any) error

SaveCustomUserFields stores dynamic user fields in in-memory storage.

type Option

type Option func(*Config)

Option defines a functional option type for configuring the plugin.

func WithFilterUnregisteredFields

func WithFilterUnregisteredFields(filter bool) Option

WithFilterUnregisteredFields enables or disables strict filtering of unregistered extra fields.

func WithMutateListDeviceSessions

func WithMutateListDeviceSessions(mutate bool) Option

WithMutateListDeviceSessions configures whether session transformation is also applied to device session listings.

func WithSessionAdditionalFields

func WithSessionAdditionalFields(fields ...AdditionalFieldDefinition) Option

WithSessionAdditionalFields registers custom additional field definitions for Session entities.

func WithTransformFunc

func WithTransformFunc(fn TransformSessionFunc) Option

WithTransformFunc configures a custom dynamic transformation callback for session payloads.

func WithUserAdditionalFields

func WithUserAdditionalFields(fields ...AdditionalFieldDefinition) Option

WithUserAdditionalFields registers custom additional field definitions for User entities.

type Plugin

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

Plugin implements the plugin.Plugin interface for dynamic session payload modification and dynamic fields management.

func New

func New(repo Repository, opts ...Option) *Plugin

New instantiates a new CustomSession plugin with the provided repository and options.

func (*Plugin) Config

func (p *Plugin) Config() Config

Config returns a copy of the active plugin configuration.

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique string identifier of the plugin.

func (*Plugin) Init

func (p *Plugin) Init(ctx *plugin.Context) error

Init initializes the plugin with the shared execution context.

func (*Plugin) Repository

func (p *Plugin) Repository() Repository

Repository returns the underlying persistence repository instance.

func (*Plugin) SanitizePayload

func (p *Plugin) SanitizePayload(payload any) any

SanitizePayload filters unregistered additional fields from session payloads when FilterUnregisteredFields is true.

func (*Plugin) ServeGetCustomSession

func (p *Plugin) ServeGetCustomSession(w http.ResponseWriter, r *http.Request, sessionData *dto.SessionData)

ServeGetCustomSession responds to GET /get-session requests with transformed session payloads.

func (*Plugin) SessionInterceptor

func (p *Plugin) SessionInterceptor(next http.Handler) http.Handler

SessionInterceptor creates an HTTP middleware that intercepts responses on GET /get-session and applies dynamic session transformation.

func (*Plugin) TransformSession

func (p *Plugin) TransformSession(ctx context.Context, sessionData *dto.SessionData, req *http.Request) (any, error)

TransformSession executes the dynamic session payload transformation logic, emitting lifecycle events across EventBus.

type Repository

type Repository interface {
	// GetCustomUserFields retrieves dynamic additional fields associated with a specific user ID.
	//
	// Function:
	//   Called during session transformation or user retrieval to load persisted extra metadata.
	//
	// Storage:
	//   Database (GORM / SQL) or Redis Cache-Aside.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - userID: Unique identifier of the target user.
	//
	// Returns:
	//   - map[string]any: Key-value map of dynamic user fields.
	//   - error: Database query error if execution fails.
	//
	// Example SQL:
	//   SELECT extra_fields FROM users WHERE id = $1 LIMIT 1;
	GetCustomUserFields(ctx context.Context, userID string) (map[string]any, error)

	// SaveCustomUserFields persists dynamic additional fields for a specific user ID.
	//
	// Function:
	//   Called when updating or initializing dynamic user attributes.
	//
	// Storage:
	//   Database (GORM / SQL).
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - userID: Unique identifier of the target user.
	//   - fields: Key-value map of dynamic extra fields to persist.
	//
	// Returns:
	//   - error: Database execution error if update fails.
	//
	// Example SQL:
	//   UPDATE users SET extra_fields = $2 WHERE id = $1;
	SaveCustomUserFields(ctx context.Context, userID string, fields map[string]any) error

	// GetCustomSessionFields retrieves dynamic additional fields associated with a specific session ID.
	//
	// Function:
	//   Called during session payload transformation to load custom session metadata.
	//
	// Storage:
	//   Database (GORM / SQL) or Redis Cache-Aside.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - sessionID: Unique identifier of the target active session.
	//
	// Returns:
	//   - map[string]any: Key-value map of dynamic session fields.
	//   - error: Database query error if execution fails.
	//
	// Example SQL:
	//   SELECT extra_fields FROM sessions WHERE id = $1 LIMIT 1;
	GetCustomSessionFields(ctx context.Context, sessionID string) (map[string]any, error)

	// SaveCustomSessionFields persists dynamic additional fields for a specific session ID.
	//
	// Function:
	//   Called when storing dynamic session attributes during sign-in or session updates.
	//
	// Storage:
	//   Database (GORM / SQL).
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - sessionID: Unique identifier of the target active session.
	//   - fields: Key-value map of dynamic extra fields to persist.
	//
	// Returns:
	//   - error: Database execution error if update fails.
	//
	// Example SQL:
	//   UPDATE sessions SET extra_fields = $2 WHERE id = $1;
	SaveCustomSessionFields(ctx context.Context, sessionID string, fields map[string]any) error
}

Repository defines the persistent storage contract required by the CustomSession plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, SQLite, MongoDB, GORM, Redis).

Implementation Example (GORM / database/sql):

type GormCustomSessionRepository struct {
	db *gorm.DB
}

func (r *GormCustomSessionRepository) GetCustomUserFields(ctx context.Context, userID string) (map[string]any, error) {
	var fields JSONBMap
	if err := r.db.WithContext(ctx).Table("users").Select("extra_fields").Where("id = ?", userID).Scan(&fields).Error; err != nil {
		return nil, err
	}
	return fields, nil
}

Storage and Caching Recommendation (Redis / Cache-Aside Strategy):

Because dynamic user and session custom fields may be read on every authenticated HTTP request, decorating your database repository with Redis or an in-memory Cache-Aside wrapper is recommended:

type CachedCustomSessionRepository struct {
	dbRepo customsession.Repository
	redis  *redis.Client
	ttl    time.Duration
}

func (r *CachedCustomSessionRepository) GetCustomUserFields(ctx context.Context, userID string) (map[string]any, error) {
	cacheKey := "user_fields:" + userID
	val, err := r.redis.Get(ctx, cacheKey).Bytes()
	if err == nil {
		var fields map[string]any
		if json.Unmarshal(val, &fields) == nil {
			return fields, nil
		}
	}
	fields, err := r.dbRepo.GetCustomUserFields(ctx, userID)
	if err != nil {
		return nil, err
	}
	bytes, _ := json.Marshal(fields)
	r.redis.Set(ctx, cacheKey, bytes, r.ttl)
	return fields, nil
}

type TransformEventPayload

type TransformEventPayload struct {
	// SessionData is the initial session and user payload before transformation.
	SessionData *dto.SessionData `json:"sessionData"`

	// TransformedData is the resulting payload produced by TransformSessionFunc.
	TransformedData any `json:"transformedData,omitempty"`

	// Request is the active HTTP request triggering the transformation.
	Request *http.Request `json:"-"`

	// Err contains any error encountered during transformation processing.
	Err error `json:"error,omitempty"`
}

TransformEventPayload holds event metadata dispatched across EventBus during transformation execution.

type TransformSessionFunc

type TransformSessionFunc func(ctx context.Context, sessionData *dto.SessionData, req *http.Request) (any, error)

TransformSessionFunc is the callback signature for transforming and enriching session response data dynamically per request.

Jump to

Keyboard shortcuts

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