Documentation
¶
Overview ¶
Package customsession provides dynamic session payload transformation and dynamic additional fields management.
Index ¶
- Constants
- Variables
- func PreserveResponseHeaders(w http.ResponseWriter, src http.Header)
- type AdditionalFieldDefinition
- type AdditionalFieldsConfig
- type Config
- type CustomSessionData
- type FieldType
- type MemoryRepository
- func (m *MemoryRepository) GetCustomSessionFields(ctx context.Context, sessionID string) (map[string]any, error)
- func (m *MemoryRepository) GetCustomUserFields(ctx context.Context, userID string) (map[string]any, error)
- func (m *MemoryRepository) SaveCustomSessionFields(ctx context.Context, sessionID string, fields map[string]any) error
- func (m *MemoryRepository) SaveCustomUserFields(ctx context.Context, userID string, fields map[string]any) error
- type Option
- func WithFilterUnregisteredFields(filter bool) Option
- func WithMutateListDeviceSessions(mutate bool) Option
- func WithSessionAdditionalFields(fields ...AdditionalFieldDefinition) Option
- func WithTransformFunc(fn TransformSessionFunc) Option
- func WithUserAdditionalFields(fields ...AdditionalFieldDefinition) Option
- type Plugin
- func (p *Plugin) Config() Config
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) Repository() Repository
- func (p *Plugin) SanitizePayload(payload any) any
- func (p *Plugin) ServeGetCustomSession(w http.ResponseWriter, r *http.Request, sessionData *dto.SessionData)
- func (p *Plugin) SessionInterceptor(next http.Handler) http.Handler
- func (p *Plugin) TransformSession(ctx context.Context, sessionData *dto.SessionData, req *http.Request) (any, error)
- type Repository
- type TransformEventPayload
- type TransformSessionFunc
Constants ¶
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 ¶
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 ¶
WithFilterUnregisteredFields enables or disables strict filtering of unregistered extra fields.
func WithMutateListDeviceSessions ¶
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) Repository ¶
func (p *Plugin) Repository() Repository
Repository returns the underlying persistence repository instance.
func (*Plugin) SanitizePayload ¶
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 ¶
SessionInterceptor creates an HTTP middleware that intercepts responses on GET /get-session and applies dynamic session transformation.
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.