lifecycle

package
v1.1.4 Latest Latest
Warning

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

Go to latest
Published: May 21, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package lifecycle provides the dormant-plugin state machine for the nSelf plugin license lifecycle. It handles active → dormant → expired transitions, persistent JSON state storage, and the 7-day default grace period.

TOCTOU protection: Save uses an atomic temp-file rename so concurrent CLI invocations cannot corrupt the store. The caller must ensure it holds the store in memory for only the duration of a single operation — no long-held in-memory caches — to avoid read/check/write races across processes.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DormantBanner

func DormantBanner(rec *Record, now time.Time) string

DormantBanner returns the user-facing warning text for a dormant plugin, showing the number of days remaining in the grace period. Returns an empty string if rec is nil or has no DormantSince timestamp.

Types

type Record

type Record struct {
	Name          string     `json:"name"`
	State         State      `json:"state"`
	LicenseExpiry time.Time  `json:"license_expiry"`
	DormantSince  *time.Time `json:"dormant_since,omitempty"`
	// GracePeriod is persisted per-record so that global config changes cannot
	// retroactively shorten a grace period already in progress.
	GracePeriod time.Duration `json:"grace_period"`
}

Record tracks a single plugin's license lifecycle state.

type State

type State string

State represents the current license lifecycle state of a plugin.

const (
	// StateActive means the plugin license is valid and the plugin runs normally.
	StateActive State = "active"
	// StateDormant means the license expired but the grace period is still active.
	// The plugin continues to function during this window with a daily warning banner.
	StateDormant State = "dormant"
	// StateExpired means the grace period is exhausted. The plugin is disabled and
	// queued for auto-removal on the next `nself build`.
	StateExpired State = "expired"

	// DefaultGracePeriod is the time a plugin stays dormant before auto-removal.
	DefaultGracePeriod = 7 * 24 * time.Hour
)

type Store

type Store struct {
	Version int                `json:"version"`
	Records map[string]*Record `json:"records"`
}

Store is the persistent state for all plugin lifecycle records. It is serialised to ~/.config/nself/plugin-lifecycle.json.

func Load

func Load() (*Store, error)

Load reads the persistent store from disk. If the file does not exist a new empty store is returned so the caller can populate it without special-casing first-run behaviour.

func (*Store) CheckExpiry

func (s *Store) CheckExpiry(now time.Time) (dormant, autoRemove []string)

CheckExpiry transitions plugins from active → dormant → expired based on now. It returns two slices:

  • dormant: plugins newly transitioned to StateDormant this call.
  • autoRemove: plugins transitioned to StateExpired (auto-removal candidates).

The caller must call Save after CheckExpiry to persist any transitions. Call MarkRenewal before CheckExpiry for any plugin whose license was renewed this session so it cannot immediately cycle back to expired.

func (*Store) MarkRenewal

func (s *Store) MarkRenewal(name string, newExpiry time.Time)

MarkRenewal transitions a plugin back to StateActive with a new expiry. If no record exists for name it is created. DormantSince is cleared so the grace period counter resets on the next CheckExpiry call.

func (*Store) Save

func (s *Store) Save() error

Save persists the store to disk using an atomic temp-file rename. The rename is the OS-level TOCTOU guard: either the full new content lands or the old file is untouched — there is no window where the file is partially written.

Jump to

Keyboard shortcuts

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