package app import ( "context" "errors" "fmt" "github.com/openmeterio/openmeter/openmeter/customer" "github.com/openmeterio/openmeter/pkg/models" "github.com/openmeterio/openmeter/pkg/pagination" ) // App represents an installed app type App interface { GetAppBase() AppBase GetID() AppID GetType() AppType GetName() string GetDescription() *string GetStatus() AppStatus GetMetadata() models.Metadata GetListing() MarketplaceListing GetEventAppData() (EventAppData, error) UpdateAppConfig(ctx context.Context, input AppConfigUpdate) error // ValidateCapabilities validates if the app can run for the given capabilities ValidateCapabilities(capabilities ...CapabilityType) error // Customer data GetCustomerData(ctx context.Context, input GetAppInstanceCustomerDataInput) (CustomerData, error) UpsertCustomerData(ctx context.Context, input UpsertAppInstanceCustomerDataInput) error DeleteCustomerData(ctx context.Context, input DeleteAppInstanceCustomerDataInput) error } type GetAppInstanceCustomerDataInput struct { CustomerID customer.CustomerID } func (i GetAppInstanceCustomerDataInput) Validate() error { if err := i.CustomerID.Validate(); err != nil { return err } return nil } type UpsertAppInstanceCustomerDataInput struct { CustomerID customer.CustomerID Data CustomerData } func (i UpsertAppInstanceCustomerDataInput) Validate() error { if err := i.CustomerID.Validate(); err != nil { return err } if err := i.Data.Validate(); err != nil { return err } return nil } type DeleteAppInstanceCustomerDataInput struct { CustomerID customer.CustomerID } func (i DeleteAppInstanceCustomerDataInput) Validate() error { if err := i.CustomerID.Validate(); err != nil { return err } return nil } // GetAppInput is the input for getting an installed app type GetAppInput = AppID type AppConfigUpdate interface { models.Validator } // UpdateAppInput is the input for setting an app as default for a type type UpdateAppInput struct { AppID AppID Name string Description *string Default bool Metadata *map[string]string AppConfigUpdate AppConfigUpdate } func (i UpdateAppInput) Validate() error { if err := i.AppID.Validate(); err != nil { return fmt.Errorf("error validating app ID: %w", err) } // Required fields if i.Name == "" { return errors.New("name is required") } if i.Metadata != nil { for k, v := range *i.Metadata { if k == "" { return errors.New("metadata key is required") } if v == "" { return errors.New("metadata value is required") } } } if i.AppConfigUpdate != nil { if err := i.AppConfigUpdate.Validate(); err != nil { return fmt.Errorf("error validating app entity update: %w", err) } } return nil } // CreateAppInput is the input for creating an app type CreateAppInput struct { // AppID is optional. If not provided, a new AppID will be generated by the database ID *AppID Namespace string Name string Description string Type AppType } func (i CreateAppInput) Validate() error { if i.Namespace == "" { return errors.New("namespace is required") } if i.Name == "" { return errors.New("name is required") } return nil } // ListAppInput is the input for listing installed apps type ListAppInput struct { Namespace string pagination.Page AppIDs []AppID Type *AppType IncludeDeleted bool // Only list apps that has data for the given customer CustomerID *customer.CustomerID } func (i ListAppInput) Validate() error { var errs []error if i.Namespace == "" { errs = append(errs, models.NewGenericValidationError( errors.New("namespace is required"), )) } if i.CustomerID != nil { if err := i.CustomerID.Validate(); err != nil { errs = append(errs, models.NewGenericValidationError( fmt.Errorf("error validating customer id: %w", err), )) } if i.CustomerID.Namespace != i.Namespace { errs = append(errs, models.NewGenericValidationError( fmt.Errorf("customer id namespace %s does not match app namespace %s", i.CustomerID.Namespace, i.Namespace), )) } } if len(i.AppIDs) > 0 { for _, appID := range i.AppIDs { if appID.Namespace != i.Namespace { errs = append(errs, models.NewGenericValidationError( fmt.Errorf("app id namespace %s does not match app namespace %s", appID.Namespace, i.Namespace), )) } if err := appID.Validate(); err != nil { errs = append(errs, models.NewGenericValidationError( fmt.Errorf("error validating app id: %w", err), )) } } } return errors.Join(errs...) } // UpdateAppStatusInput is the input for updating an app status type UpdateAppStatusInput struct { ID AppID Status AppStatus } func (i UpdateAppStatusInput) Validate() error { if err := i.ID.Validate(); err != nil { return err } if i.Status == "" { return errors.New("status is required") } return nil }