mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: events for dependencies (#4864)
This commit is contained in:
		
							parent
							
								
									011aea226c
								
							
						
					
					
						commit
						fbc571dffc
					
				@ -82,6 +82,7 @@ export const useDependentFeaturesApi = (project: string) => {
 | 
				
			|||||||
        makeRequest,
 | 
					        makeRequest,
 | 
				
			||||||
        setToastData,
 | 
					        setToastData,
 | 
				
			||||||
        formatUnknownError,
 | 
					        formatUnknownError,
 | 
				
			||||||
 | 
					        project,
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        addDependency: useCallback(addDependency, callbackDeps),
 | 
					        addDependency: useCallback(addDependency, callbackDeps),
 | 
				
			||||||
 | 
				
			|||||||
@ -161,7 +161,7 @@
 | 
				
			|||||||
    "stoppable": "^1.1.0",
 | 
					    "stoppable": "^1.1.0",
 | 
				
			||||||
    "ts-toolbelt": "^9.6.0",
 | 
					    "ts-toolbelt": "^9.6.0",
 | 
				
			||||||
    "type-is": "^1.6.18",
 | 
					    "type-is": "^1.6.18",
 | 
				
			||||||
    "unleash-client": "4.1.1",
 | 
					    "unleash-client": "4.2.0-beta.0",
 | 
				
			||||||
    "uuid": "^9.0.0"
 | 
					    "uuid": "^9.0.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,24 +4,53 @@ import { DependentFeaturesStore } from './dependent-features-store';
 | 
				
			|||||||
import { DependentFeaturesReadModel } from './dependent-features-read-model';
 | 
					import { DependentFeaturesReadModel } from './dependent-features-read-model';
 | 
				
			||||||
import { FakeDependentFeaturesStore } from './fake-dependent-features-store';
 | 
					import { FakeDependentFeaturesStore } from './fake-dependent-features-store';
 | 
				
			||||||
import { FakeDependentFeaturesReadModel } from './fake-dependent-features-read-model';
 | 
					import { FakeDependentFeaturesReadModel } from './fake-dependent-features-read-model';
 | 
				
			||||||
 | 
					import EventStore from '../../db/event-store';
 | 
				
			||||||
 | 
					import { IUnleashConfig } from '../../types';
 | 
				
			||||||
 | 
					import { EventService } from '../../services';
 | 
				
			||||||
 | 
					import FeatureTagStore from '../../db/feature-tag-store';
 | 
				
			||||||
 | 
					import FakeEventStore from '../../../test/fixtures/fake-event-store';
 | 
				
			||||||
 | 
					import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createDependentFeaturesService = (
 | 
					export const createDependentFeaturesService = (
 | 
				
			||||||
    db: Db,
 | 
					    db: Db,
 | 
				
			||||||
 | 
					    config: IUnleashConfig,
 | 
				
			||||||
): DependentFeaturesService => {
 | 
					): DependentFeaturesService => {
 | 
				
			||||||
 | 
					    const { getLogger, eventBus } = config;
 | 
				
			||||||
 | 
					    const eventStore = new EventStore(db, getLogger);
 | 
				
			||||||
 | 
					    const featureTagStore = new FeatureTagStore(db, eventBus, getLogger);
 | 
				
			||||||
 | 
					    const eventService = new EventService(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            eventStore,
 | 
				
			||||||
 | 
					            featureTagStore,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        config,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    const dependentFeaturesStore = new DependentFeaturesStore(db);
 | 
					    const dependentFeaturesStore = new DependentFeaturesStore(db);
 | 
				
			||||||
    const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
 | 
					    const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
 | 
				
			||||||
    return new DependentFeaturesService(
 | 
					    return new DependentFeaturesService(
 | 
				
			||||||
        dependentFeaturesStore,
 | 
					        dependentFeaturesStore,
 | 
				
			||||||
        dependentFeaturesReadModel,
 | 
					        dependentFeaturesReadModel,
 | 
				
			||||||
 | 
					        eventService,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createFakeDependentFeaturesService =
 | 
					export const createFakeDependentFeaturesService = (
 | 
				
			||||||
    (): DependentFeaturesService => {
 | 
					    config: IUnleashConfig,
 | 
				
			||||||
 | 
					): DependentFeaturesService => {
 | 
				
			||||||
 | 
					    const eventStore = new FakeEventStore();
 | 
				
			||||||
 | 
					    const featureTagStore = new FakeFeatureTagStore();
 | 
				
			||||||
 | 
					    const eventService = new EventService(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            eventStore,
 | 
				
			||||||
 | 
					            featureTagStore,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        config,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    const dependentFeaturesStore = new FakeDependentFeaturesStore();
 | 
					    const dependentFeaturesStore = new FakeDependentFeaturesStore();
 | 
				
			||||||
    const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
 | 
					    const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
 | 
				
			||||||
    return new DependentFeaturesService(
 | 
					    return new DependentFeaturesService(
 | 
				
			||||||
        dependentFeaturesStore,
 | 
					        dependentFeaturesStore,
 | 
				
			||||||
        dependentFeaturesReadModel,
 | 
					        dependentFeaturesReadModel,
 | 
				
			||||||
 | 
					        eventService,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    };
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -21,12 +21,17 @@ import { IAuthRequest } from '../../routes/unleash-types';
 | 
				
			|||||||
import { InvalidOperationError } from '../../error';
 | 
					import { InvalidOperationError } from '../../error';
 | 
				
			||||||
import { DependentFeaturesService } from './dependent-features-service';
 | 
					import { DependentFeaturesService } from './dependent-features-service';
 | 
				
			||||||
import { TransactionCreator, UnleashTransaction } from '../../db/transaction';
 | 
					import { TransactionCreator, UnleashTransaction } from '../../db/transaction';
 | 
				
			||||||
 | 
					import { extractUsernameFromUser } from '../../util';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface FeatureParams {
 | 
					interface ProjectParams {
 | 
				
			||||||
 | 
					    projectId: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface FeatureParams extends ProjectParams {
 | 
				
			||||||
    child: string;
 | 
					    child: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface DeleteDependencyParams {
 | 
					interface DeleteDependencyParams extends ProjectParams {
 | 
				
			||||||
    child: string;
 | 
					    child: string;
 | 
				
			||||||
    parent: string;
 | 
					    parent: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -167,18 +172,22 @@ export default class DependentFeaturesController extends Controller {
 | 
				
			|||||||
        req: IAuthRequest<FeatureParams, any, CreateDependentFeatureSchema>,
 | 
					        req: IAuthRequest<FeatureParams, any, CreateDependentFeatureSchema>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { child } = req.params;
 | 
					        const { child, projectId } = req.params;
 | 
				
			||||||
        const { variants, enabled, feature } = req.body;
 | 
					        const { variants, enabled, feature } = req.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
					        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
				
			||||||
            await this.startTransaction(async (tx) =>
 | 
					            await this.startTransaction(async (tx) =>
 | 
				
			||||||
                this.transactionalDependentFeaturesService(
 | 
					                this.transactionalDependentFeaturesService(
 | 
				
			||||||
                    tx,
 | 
					                    tx,
 | 
				
			||||||
                ).upsertFeatureDependency(child, {
 | 
					                ).upsertFeatureDependency(
 | 
				
			||||||
 | 
					                    { child, projectId },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
                        variants,
 | 
					                        variants,
 | 
				
			||||||
                        enabled,
 | 
					                        enabled,
 | 
				
			||||||
                        feature,
 | 
					                        feature,
 | 
				
			||||||
                }),
 | 
					                    },
 | 
				
			||||||
 | 
					                    extractUsernameFromUser(req.user),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            res.status(200).end();
 | 
					            res.status(200).end();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -192,13 +201,17 @@ export default class DependentFeaturesController extends Controller {
 | 
				
			|||||||
        req: IAuthRequest<DeleteDependencyParams, any, any>,
 | 
					        req: IAuthRequest<DeleteDependencyParams, any, any>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { child, parent } = req.params;
 | 
					        const { child, parent, projectId } = req.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
					        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
				
			||||||
            await this.dependentFeaturesService.deleteFeatureDependency({
 | 
					            await this.dependentFeaturesService.deleteFeatureDependency(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
                    parent,
 | 
					                    parent,
 | 
				
			||||||
                    child,
 | 
					                    child,
 | 
				
			||||||
            });
 | 
					                },
 | 
				
			||||||
 | 
					                projectId,
 | 
				
			||||||
 | 
					                extractUsernameFromUser(req.user),
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
            res.status(200).end();
 | 
					            res.status(200).end();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            throw new InvalidOperationError(
 | 
					            throw new InvalidOperationError(
 | 
				
			||||||
@ -211,11 +224,13 @@ export default class DependentFeaturesController extends Controller {
 | 
				
			|||||||
        req: IAuthRequest<FeatureParams, any, any>,
 | 
					        req: IAuthRequest<FeatureParams, any, any>,
 | 
				
			||||||
        res: Response,
 | 
					        res: Response,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { child } = req.params;
 | 
					        const { child, projectId } = req.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
					        if (this.config.flagResolver.isEnabled('dependentFeatures')) {
 | 
				
			||||||
            await this.dependentFeaturesService.deleteFeatureDependencies(
 | 
					            await this.dependentFeaturesService.deleteFeatureDependencies(
 | 
				
			||||||
                child,
 | 
					                child,
 | 
				
			||||||
 | 
					                projectId,
 | 
				
			||||||
 | 
					                extractUsernameFromUser(req.user),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            res.status(200).end();
 | 
					            res.status(200).end();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -3,23 +3,29 @@ import { CreateDependentFeatureSchema } from '../../openapi';
 | 
				
			|||||||
import { IDependentFeaturesStore } from './dependent-features-store-type';
 | 
					import { IDependentFeaturesStore } from './dependent-features-store-type';
 | 
				
			||||||
import { FeatureDependency, FeatureDependencyId } from './dependent-features';
 | 
					import { FeatureDependency, FeatureDependencyId } from './dependent-features';
 | 
				
			||||||
import { IDependentFeaturesReadModel } from './dependent-features-read-model-type';
 | 
					import { IDependentFeaturesReadModel } from './dependent-features-read-model-type';
 | 
				
			||||||
 | 
					import { EventService } from '../../services';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class DependentFeaturesService {
 | 
					export class DependentFeaturesService {
 | 
				
			||||||
    private dependentFeaturesStore: IDependentFeaturesStore;
 | 
					    private dependentFeaturesStore: IDependentFeaturesStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private dependentFeaturesReadModel: IDependentFeaturesReadModel;
 | 
					    private dependentFeaturesReadModel: IDependentFeaturesReadModel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private eventService: EventService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        dependentFeaturesStore: IDependentFeaturesStore,
 | 
					        dependentFeaturesStore: IDependentFeaturesStore,
 | 
				
			||||||
        dependentFeaturesReadModel: IDependentFeaturesReadModel,
 | 
					        dependentFeaturesReadModel: IDependentFeaturesReadModel,
 | 
				
			||||||
 | 
					        eventService: EventService,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        this.dependentFeaturesStore = dependentFeaturesStore;
 | 
					        this.dependentFeaturesStore = dependentFeaturesStore;
 | 
				
			||||||
        this.dependentFeaturesReadModel = dependentFeaturesReadModel;
 | 
					        this.dependentFeaturesReadModel = dependentFeaturesReadModel;
 | 
				
			||||||
 | 
					        this.eventService = eventService;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async upsertFeatureDependency(
 | 
					    async upsertFeatureDependency(
 | 
				
			||||||
        child: string,
 | 
					        { child, projectId }: { child: string; projectId: string },
 | 
				
			||||||
        dependentFeature: CreateDependentFeatureSchema,
 | 
					        dependentFeature: CreateDependentFeatureSchema,
 | 
				
			||||||
 | 
					        user: string,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { enabled, feature: parent, variants } = dependentFeature;
 | 
					        const { enabled, feature: parent, variants } = dependentFeature;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,16 +52,46 @@ export class DependentFeaturesService {
 | 
				
			|||||||
                      variants,
 | 
					                      variants,
 | 
				
			||||||
                  };
 | 
					                  };
 | 
				
			||||||
        await this.dependentFeaturesStore.upsert(featureDependency);
 | 
					        await this.dependentFeaturesStore.upsert(featureDependency);
 | 
				
			||||||
 | 
					        await this.eventService.storeEvent({
 | 
				
			||||||
 | 
					            type: 'feature-dependency-added',
 | 
				
			||||||
 | 
					            project: projectId,
 | 
				
			||||||
 | 
					            featureName: child,
 | 
				
			||||||
 | 
					            createdBy: user,
 | 
				
			||||||
 | 
					            data: {
 | 
				
			||||||
 | 
					                feature: parent,
 | 
				
			||||||
 | 
					                enabled: featureDependency.enabled,
 | 
				
			||||||
 | 
					                ...(variants !== undefined && { variants }),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async deleteFeatureDependency(
 | 
					    async deleteFeatureDependency(
 | 
				
			||||||
        dependency: FeatureDependencyId,
 | 
					        dependency: FeatureDependencyId,
 | 
				
			||||||
 | 
					        projectId: string,
 | 
				
			||||||
 | 
					        user: string,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        await this.dependentFeaturesStore.delete(dependency);
 | 
					        await this.dependentFeaturesStore.delete(dependency);
 | 
				
			||||||
 | 
					        await this.eventService.storeEvent({
 | 
				
			||||||
 | 
					            type: 'feature-dependency-removed',
 | 
				
			||||||
 | 
					            project: projectId,
 | 
				
			||||||
 | 
					            featureName: dependency.child,
 | 
				
			||||||
 | 
					            createdBy: user,
 | 
				
			||||||
 | 
					            data: { feature: dependency.parent },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async deleteFeatureDependencies(feature: string): Promise<void> {
 | 
					    async deleteFeatureDependencies(
 | 
				
			||||||
 | 
					        feature: string,
 | 
				
			||||||
 | 
					        projectId: string,
 | 
				
			||||||
 | 
					        user: string,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
        await this.dependentFeaturesStore.deleteAll(feature);
 | 
					        await this.dependentFeaturesStore.deleteAll(feature);
 | 
				
			||||||
 | 
					        await this.eventService.storeEvent({
 | 
				
			||||||
 | 
					            type: 'feature-dependencies-removed',
 | 
				
			||||||
 | 
					            project: projectId,
 | 
				
			||||||
 | 
					            featureName: feature,
 | 
				
			||||||
 | 
					            createdBy: user,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getParentOptions(feature: string): Promise<string[]> {
 | 
					    async getParentOptions(feature: string): Promise<string[]> {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,9 +6,16 @@ import {
 | 
				
			|||||||
} from '../../../test/e2e/helpers/test-helper';
 | 
					} from '../../../test/e2e/helpers/test-helper';
 | 
				
			||||||
import getLogger from '../../../test/fixtures/no-logger';
 | 
					import getLogger from '../../../test/fixtures/no-logger';
 | 
				
			||||||
import { CreateDependentFeatureSchema } from '../../openapi';
 | 
					import { CreateDependentFeatureSchema } from '../../openapi';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    FEATURE_DEPENDENCIES_REMOVED,
 | 
				
			||||||
 | 
					    FEATURE_DEPENDENCY_ADDED,
 | 
				
			||||||
 | 
					    FEATURE_DEPENDENCY_REMOVED,
 | 
				
			||||||
 | 
					    IEventStore,
 | 
				
			||||||
 | 
					} from '../../types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let app: IUnleashTest;
 | 
					let app: IUnleashTest;
 | 
				
			||||||
let db: ITestDb;
 | 
					let db: ITestDb;
 | 
				
			||||||
 | 
					let eventStore: IEventStore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
beforeAll(async () => {
 | 
					beforeAll(async () => {
 | 
				
			||||||
    db = await dbInit('dependent_features', getLogger);
 | 
					    db = await dbInit('dependent_features', getLogger);
 | 
				
			||||||
@ -24,8 +31,14 @@ beforeAll(async () => {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        db.rawDatabase,
 | 
					        db.rawDatabase,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    eventStore = db.stores.eventStore;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getRecordedEventTypesForDependencies = async () =>
 | 
				
			||||||
 | 
					    (await eventStore.getEvents())
 | 
				
			||||||
 | 
					        .map((event) => event.type)
 | 
				
			||||||
 | 
					        .filter((type) => type.includes('depend'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
afterAll(async () => {
 | 
					afterAll(async () => {
 | 
				
			||||||
    await app.destroy();
 | 
					    await app.destroy();
 | 
				
			||||||
    await db.destroy();
 | 
					    await db.destroy();
 | 
				
			||||||
@ -95,6 +108,13 @@ test('should add and delete feature dependencies', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    await deleteFeatureDependency(child, parent); // single
 | 
					    await deleteFeatureDependency(child, parent); // single
 | 
				
			||||||
    await deleteFeatureDependencies(child); // all
 | 
					    await deleteFeatureDependencies(child); // all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(await getRecordedEventTypesForDependencies()).toStrictEqual([
 | 
				
			||||||
 | 
					        FEATURE_DEPENDENCIES_REMOVED,
 | 
				
			||||||
 | 
					        FEATURE_DEPENDENCY_REMOVED,
 | 
				
			||||||
 | 
					        FEATURE_DEPENDENCY_ADDED,
 | 
				
			||||||
 | 
					        FEATURE_DEPENDENCY_ADDED,
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('should not allow to add a parent dependency to a feature that already has children', async () => {
 | 
					test('should not allow to add a parent dependency to a feature that already has children', async () => {
 | 
				
			||||||
 | 
				
			|||||||
@ -328,10 +328,10 @@ export const createServices = (
 | 
				
			|||||||
    const eventAnnouncerService = new EventAnnouncerService(stores, config);
 | 
					    const eventAnnouncerService = new EventAnnouncerService(stores, config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const dependentFeaturesService = db
 | 
					    const dependentFeaturesService = db
 | 
				
			||||||
        ? createDependentFeaturesService(db)
 | 
					        ? createDependentFeaturesService(db, config)
 | 
				
			||||||
        : createFakeDependentFeaturesService();
 | 
					        : createFakeDependentFeaturesService(config);
 | 
				
			||||||
    const transactionalDependentFeaturesService = (txDb: Knex.Transaction) =>
 | 
					    const transactionalDependentFeaturesService = (txDb: Knex.Transaction) =>
 | 
				
			||||||
        createDependentFeaturesService(txDb);
 | 
					        createDependentFeaturesService(txDb, config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        accessService,
 | 
					        accessService,
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,10 @@ export const APPLICATION_CREATED = 'application-created' as const;
 | 
				
			|||||||
export const FEATURE_CREATED = 'feature-created' as const;
 | 
					export const FEATURE_CREATED = 'feature-created' as const;
 | 
				
			||||||
export const FEATURE_DELETED = 'feature-deleted' as const;
 | 
					export const FEATURE_DELETED = 'feature-deleted' as const;
 | 
				
			||||||
export const FEATURE_UPDATED = 'feature-updated' as const;
 | 
					export const FEATURE_UPDATED = 'feature-updated' as const;
 | 
				
			||||||
 | 
					export const FEATURE_DEPENDENCY_ADDED = 'feature-dependency-added' as const;
 | 
				
			||||||
 | 
					export const FEATURE_DEPENDENCY_REMOVED = 'feature-dependency-removed' as const;
 | 
				
			||||||
 | 
					export const FEATURE_DEPENDENCIES_REMOVED =
 | 
				
			||||||
 | 
					    'feature-dependencies-removed' as const;
 | 
				
			||||||
export const FEATURE_METADATA_UPDATED = 'feature-metadata-updated' as const;
 | 
					export const FEATURE_METADATA_UPDATED = 'feature-metadata-updated' as const;
 | 
				
			||||||
export const FEATURE_VARIANTS_UPDATED = 'feature-variants-updated' as const;
 | 
					export const FEATURE_VARIANTS_UPDATED = 'feature-variants-updated' as const;
 | 
				
			||||||
export const FEATURE_ENVIRONMENT_VARIANTS_UPDATED =
 | 
					export const FEATURE_ENVIRONMENT_VARIANTS_UPDATED =
 | 
				
			||||||
@ -249,6 +253,9 @@ export const IEventTypes = [
 | 
				
			|||||||
    SERVICE_ACCOUNT_DELETED,
 | 
					    SERVICE_ACCOUNT_DELETED,
 | 
				
			||||||
    SERVICE_ACCOUNT_UPDATED,
 | 
					    SERVICE_ACCOUNT_UPDATED,
 | 
				
			||||||
    FEATURE_POTENTIALLY_STALE_ON,
 | 
					    FEATURE_POTENTIALLY_STALE_ON,
 | 
				
			||||||
 | 
					    FEATURE_DEPENDENCY_ADDED,
 | 
				
			||||||
 | 
					    FEATURE_DEPENDENCY_REMOVED,
 | 
				
			||||||
 | 
					    FEATURE_DEPENDENCIES_REMOVED,
 | 
				
			||||||
] as const;
 | 
					] as const;
 | 
				
			||||||
export type IEventType = typeof IEventTypes[number];
 | 
					export type IEventType = typeof IEventTypes[number];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -62,8 +62,9 @@ beforeAll(async () => {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
    // depend on enabled feature with variant
 | 
					    // depend on enabled feature with variant
 | 
				
			||||||
    await app.services.dependentFeaturesService.upsertFeatureDependency(
 | 
					    await app.services.dependentFeaturesService.upsertFeatureDependency(
 | 
				
			||||||
        'featureY',
 | 
					        { child: 'featureY', projectId: 'default' },
 | 
				
			||||||
        { feature: 'featureX', variants: ['featureXVariant'] },
 | 
					        { feature: 'featureX', variants: ['featureXVariant'] },
 | 
				
			||||||
 | 
					        'test',
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await app.services.featureToggleServiceV2.archiveToggle(
 | 
					    await app.services.featureToggleServiceV2.archiveToggle(
 | 
				
			||||||
 | 
				
			|||||||
@ -7899,10 +7899,10 @@ universalify@^0.1.0:
 | 
				
			|||||||
  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
 | 
					  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
 | 
				
			||||||
  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
 | 
					  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unleash-client@4.1.1:
 | 
					unleash-client@4.2.0-beta.0:
 | 
				
			||||||
  version "4.1.1"
 | 
					  version "4.2.0-beta.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/unleash-client/-/unleash-client-4.1.1.tgz#ad3e90853f98885bbb4746af813514e6d1e7dee9"
 | 
					  resolved "https://registry.yarnpkg.com/unleash-client/-/unleash-client-4.2.0-beta.0.tgz#62d4615d1e55255696c09938a12a02224262279c"
 | 
				
			||||||
  integrity sha512-cliJJ82unQauip8/7TQhJbvuHMgBIrM167672uV5RmeD7buluAHm1x0BmYjqsXMpE3MX06m05EzpRz62H90puQ==
 | 
					  integrity sha512-Rhq1ahtXU47FyMZJ1f3Wrjr7rpU5V0noGwfxMj9+79NoksiA9NcmqnP2qeZF0hmE3trLDk8q3hj7NmVIR6RjPA==
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    ip "^1.1.8"
 | 
					    ip "^1.1.8"
 | 
				
			||||||
    make-fetch-happen "^10.2.1"
 | 
					    make-fetch-happen "^10.2.1"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user