package store import ( "context" "encoding/json" ) // PackageStore manages the unified package registry (surfaces + extensions). // Replaces SurfaceRegistryStore and ExtensionStore (v0.28.7). type PackageStore interface { // ── Lifecycle (from SurfaceRegistryStore) ──────────── // Seed upserts a package at startup. Does NOT overwrite the enabled // flag if the row already exists (admin toggle survives restarts). // Called by the page engine for core surfaces. Seed(ctx context.Context, id, title, source string, manifest map[string]any) error // List returns all registered packages, ordered by source then title. List(ctx context.Context) ([]PackageRegistration, error) // Get returns a single package by ID (slug). Get(ctx context.Context, id string) (*PackageRegistration, error) // SetEnabled toggles a package's enabled state. SetEnabled(ctx context.Context, id string, enabled bool) error // SetStatus transitions a package's lifecycle status. // Valid statuses: active, pending_review, suspended. SetStatus(ctx context.Context, id string, status string) error // Delete removes a non-core package. Core packages cannot be deleted. Delete(ctx context.Context, id string) error // ListEnabled returns IDs of all enabled packages. // Used by the page engine for nav rendering, not exposed via HTTP. ListEnabled(ctx context.Context) ([]string, error) // ── Extended lifecycle ─────────────────────────────── // Create inserts a new package with all fields. Used by the install // handler for .pkg uploads. Create(ctx context.Context, pkg *PackageRegistration) error // Update modifies mutable fields on an existing package. Update(ctx context.Context, id string, pkg *PackageRegistration) error // ListByType returns packages filtered by type (surface, extension, full). ListByType(ctx context.Context, pkgType string) ([]PackageRegistration, error) // ListEnabledByType returns enabled packages of a given type. ListEnabledByType(ctx context.Context, pkgType string) ([]PackageRegistration, error) // ── Extension runtime (from ExtensionStore) ───────── // ListForUser returns enabled extension/full packages with per-user // settings overlay from package_user_settings. System packages are // always included (users can't disable them). ListForUser(ctx context.Context, userID string) ([]UserPackage, error) // GetUserSettings returns per-user settings for a specific package. GetUserSettings(ctx context.Context, pkgID, userID string) (*PackageUserSettings, error) // SetUserSettings upserts per-user settings for a package. SetUserSettings(ctx context.Context, s *PackageUserSettings) error // DeleteUserSettings removes per-user settings, reverting to defaults. DeleteUserSettings(ctx context.Context, pkgID, userID string) error // ── Scoped visibility (v0.30.0) ──────────────── // ListVisiblePackages returns packages visible to the given user: // global packages + team packages for user's teams + personal packages. ListVisiblePackages(ctx context.Context, userID string) ([]PackageRegistration, error) // ── Package lifecycle (v0.30.0) ───────────────── // SetSchemaVersion updates the current schema version for a package. SetSchemaVersion(ctx context.Context, id string, version int) error // GetPackageSettings returns the admin-configured package-level settings. GetPackageSettings(ctx context.Context, id string) (json.RawMessage, error) // SetPackageSettings stores admin-configured package-level settings. SetPackageSettings(ctx context.Context, id string, settings json.RawMessage) error // ── Team-level settings (v0.2.0) ───────────────── // GetTeamSettings returns team-scoped overrides for a package. GetTeamSettings(ctx context.Context, pkgID, teamID string) (json.RawMessage, error) // SetTeamSettings upserts team-scoped overrides for a package. SetTeamSettings(ctx context.Context, pkgID, teamID string, settings json.RawMessage) error // DeleteTeamSettings removes team-scoped overrides, reverting to global defaults. DeleteTeamSettings(ctx context.Context, pkgID, teamID string) error } // PackageRegistration is a row from the packages table. type PackageRegistration struct { ID string `json:"id" db:"id"` Title string `json:"title" db:"title"` Type string `json:"type" db:"type"` Version string `json:"version" db:"version"` Description string `json:"description" db:"description"` Author string `json:"author" db:"author"` Tier string `json:"tier" db:"tier"` IsSystem bool `json:"is_system" db:"is_system"` Scope string `json:"scope" db:"scope"` TeamID *string `json:"team_id,omitempty" db:"team_id"` InstalledBy *string `json:"installed_by,omitempty" db:"installed_by"` Manifest map[string]any `json:"manifest" db:"manifest"` Enabled bool `json:"enabled" db:"enabled"` Status string `json:"status" db:"status"` SchemaVersion int `json:"schema_version" db:"schema_version"` PackageSettings json.RawMessage `json:"package_settings" db:"package_settings"` Source string `json:"source" db:"source"` InstalledAt string `json:"installed_at" db:"installed_at"` UpdatedAt string `json:"updated_at" db:"updated_at"` } // UserPackage combines package info with per-user settings for API responses. // Returned by ListForUser for the /extensions endpoint. type UserPackage struct { PackageRegistration UserEnabled *bool `json:"user_enabled,omitempty"` UserSettings *json.RawMessage `json:"user_settings,omitempty"` } // PackageUserSettings stores per-user overrides for a package. type PackageUserSettings struct { PackageID string `json:"package_id" db:"package_id"` UserID string `json:"user_id" db:"user_id"` Settings json.RawMessage `json:"settings" db:"settings"` IsEnabled bool `json:"is_enabled" db:"is_enabled"` } // PackageTeamSettings stores team-scoped overrides for a package (v0.2.0). type PackageTeamSettings struct { PackageID string `json:"package_id" db:"package_id"` TeamID string `json:"team_id" db:"team_id"` Settings json.RawMessage `json:"settings" db:"settings"` UpdatedAt string `json:"updated_at" db:"updated_at"` }