mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	refactor: add schemas to strategy controller (#1744)
* refactor: avoid duplicate feature strategy operationIds * refactor: fix flaky feature tests * refactor: remove duplicate controller error handling * refactor: unify feature strategy schemas * refactor: add schemas to strategy controller
This commit is contained in:
		
							parent
							
								
									e013a72ddd
								
							
						
					
					
						commit
						ac3f076a31
					
				@ -7,8 +7,8 @@ import { contextFieldSchema } from './spec/context-field-schema';
 | 
				
			|||||||
import { contextFieldsSchema } from './spec/context-fields-schema';
 | 
					import { contextFieldsSchema } from './spec/context-fields-schema';
 | 
				
			||||||
import { createApiTokenSchema } from './spec/create-api-token-schema';
 | 
					import { createApiTokenSchema } from './spec/create-api-token-schema';
 | 
				
			||||||
import { createFeatureSchema } from './spec/create-feature-schema';
 | 
					import { createFeatureSchema } from './spec/create-feature-schema';
 | 
				
			||||||
import { createStrategySchema } from './spec/create-strategy-schema';
 | 
					 | 
				
			||||||
import { createUserSchema } from './spec/create-user-schema';
 | 
					import { createUserSchema } from './spec/create-user-schema';
 | 
				
			||||||
 | 
					import { createFeatureStrategySchema } from './spec/create-feature-strategy-schema';
 | 
				
			||||||
import { environmentSchema } from './spec/environment-schema';
 | 
					import { environmentSchema } from './spec/environment-schema';
 | 
				
			||||||
import { environmentsSchema } from './spec/environments-schema';
 | 
					import { environmentsSchema } from './spec/environments-schema';
 | 
				
			||||||
import { featureEnvironmentSchema } from './spec/feature-environment-schema';
 | 
					import { featureEnvironmentSchema } from './spec/feature-environment-schema';
 | 
				
			||||||
@ -40,14 +40,13 @@ import { projectsSchema } from './spec/projects-schema';
 | 
				
			|||||||
import { roleSchema } from './spec/role-schema';
 | 
					import { roleSchema } from './spec/role-schema';
 | 
				
			||||||
import { sortOrderSchema } from './spec/sort-order-schema';
 | 
					import { sortOrderSchema } from './spec/sort-order-schema';
 | 
				
			||||||
import { splashSchema } from './spec/splash-schema';
 | 
					import { splashSchema } from './spec/splash-schema';
 | 
				
			||||||
import { strategySchema } from './spec/strategy-schema';
 | 
					 | 
				
			||||||
import { tagSchema } from './spec/tag-schema';
 | 
					import { tagSchema } from './spec/tag-schema';
 | 
				
			||||||
import { tagsSchema } from './spec/tags-schema';
 | 
					import { tagsSchema } from './spec/tags-schema';
 | 
				
			||||||
import { tagTypeSchema } from './spec/tag-type-schema';
 | 
					import { tagTypeSchema } from './spec/tag-type-schema';
 | 
				
			||||||
import { tagTypesSchema } from './spec/tag-types-schema';
 | 
					import { tagTypesSchema } from './spec/tag-types-schema';
 | 
				
			||||||
import { uiConfigSchema } from './spec/ui-config-schema';
 | 
					import { uiConfigSchema } from './spec/ui-config-schema';
 | 
				
			||||||
import { updateFeatureSchema } from './spec/update-feature-schema';
 | 
					import { updateFeatureSchema } from './spec/update-feature-schema';
 | 
				
			||||||
import { updateStrategySchema } from './spec/update-strategy-schema';
 | 
					import { updateFeatureStrategySchema } from './spec/update-feature-strategy-schema';
 | 
				
			||||||
import { updateApiTokenSchema } from './spec/update-api-token-schema';
 | 
					import { updateApiTokenSchema } from './spec/update-api-token-schema';
 | 
				
			||||||
import { updateTagTypeSchema } from './spec/update-tag-type-schema';
 | 
					import { updateTagTypeSchema } from './spec/update-tag-type-schema';
 | 
				
			||||||
import { upsertContextFieldSchema } from './spec/upsert-context-field-schema';
 | 
					import { upsertContextFieldSchema } from './spec/upsert-context-field-schema';
 | 
				
			||||||
@ -76,6 +75,9 @@ import { stateSchema } from './spec/state-schema';
 | 
				
			|||||||
import { featureTagSchema } from './spec/feature-tag-schema';
 | 
					import { featureTagSchema } from './spec/feature-tag-schema';
 | 
				
			||||||
import { exportParametersSchema } from './spec/export-parameters-schema';
 | 
					import { exportParametersSchema } from './spec/export-parameters-schema';
 | 
				
			||||||
import { emailSchema } from './spec/email-schema';
 | 
					import { emailSchema } from './spec/email-schema';
 | 
				
			||||||
 | 
					import { strategySchema } from './spec/strategy-schema';
 | 
				
			||||||
 | 
					import { strategiesSchema } from './spec/strategies-schema';
 | 
				
			||||||
 | 
					import { upsertStrategySchema } from './spec/upsert-strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// All schemas in `openapi/spec` should be listed here.
 | 
					// All schemas in `openapi/spec` should be listed here.
 | 
				
			||||||
export const schemas = {
 | 
					export const schemas = {
 | 
				
			||||||
@ -94,7 +96,7 @@ export const schemas = {
 | 
				
			|||||||
    contextFieldsSchema,
 | 
					    contextFieldsSchema,
 | 
				
			||||||
    createApiTokenSchema,
 | 
					    createApiTokenSchema,
 | 
				
			||||||
    createFeatureSchema,
 | 
					    createFeatureSchema,
 | 
				
			||||||
    createStrategySchema,
 | 
					    createFeatureStrategySchema,
 | 
				
			||||||
    createUserSchema,
 | 
					    createUserSchema,
 | 
				
			||||||
    emailSchema,
 | 
					    emailSchema,
 | 
				
			||||||
    environmentSchema,
 | 
					    environmentSchema,
 | 
				
			||||||
@ -132,6 +134,7 @@ export const schemas = {
 | 
				
			|||||||
    sortOrderSchema,
 | 
					    sortOrderSchema,
 | 
				
			||||||
    splashSchema,
 | 
					    splashSchema,
 | 
				
			||||||
    stateSchema,
 | 
					    stateSchema,
 | 
				
			||||||
 | 
					    strategiesSchema,
 | 
				
			||||||
    strategySchema,
 | 
					    strategySchema,
 | 
				
			||||||
    tagSchema,
 | 
					    tagSchema,
 | 
				
			||||||
    tagWithVersionSchema,
 | 
					    tagWithVersionSchema,
 | 
				
			||||||
@ -141,10 +144,11 @@ export const schemas = {
 | 
				
			|||||||
    tokenUserSchema,
 | 
					    tokenUserSchema,
 | 
				
			||||||
    uiConfigSchema,
 | 
					    uiConfigSchema,
 | 
				
			||||||
    updateFeatureSchema,
 | 
					    updateFeatureSchema,
 | 
				
			||||||
    updateStrategySchema,
 | 
					    updateFeatureStrategySchema,
 | 
				
			||||||
    updateApiTokenSchema,
 | 
					    updateApiTokenSchema,
 | 
				
			||||||
    updateTagTypeSchema,
 | 
					    updateTagTypeSchema,
 | 
				
			||||||
    upsertContextFieldSchema,
 | 
					    upsertContextFieldSchema,
 | 
				
			||||||
 | 
					    upsertStrategySchema,
 | 
				
			||||||
    validatePasswordSchema,
 | 
					    validatePasswordSchema,
 | 
				
			||||||
    validateTagTypeSchema,
 | 
					    validateTagTypeSchema,
 | 
				
			||||||
    updateUserSchema,
 | 
					    updateUserSchema,
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exports[`featureEnvironmentSchema empty 1`] = `
 | 
				
			||||||
 | 
					Object {
 | 
				
			||||||
 | 
					  "data": Object {},
 | 
				
			||||||
 | 
					  "errors": Array [
 | 
				
			||||||
 | 
					    Object {
 | 
				
			||||||
 | 
					      "instancePath": "",
 | 
				
			||||||
 | 
					      "keyword": "required",
 | 
				
			||||||
 | 
					      "message": "must have required property 'name'",
 | 
				
			||||||
 | 
					      "params": Object {
 | 
				
			||||||
 | 
					        "missingProperty": "name",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "schemaPath": "#/required",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "schema": "#/components/schemas/featureEnvironmentSchema",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					`;
 | 
				
			||||||
@ -17,13 +17,13 @@ Object {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "errors": Array [
 | 
					  "errors": Array [
 | 
				
			||||||
    Object {
 | 
					    Object {
 | 
				
			||||||
      "instancePath": "/strategies/0/constraints/0",
 | 
					      "instancePath": "/strategies/0",
 | 
				
			||||||
      "keyword": "required",
 | 
					      "keyword": "required",
 | 
				
			||||||
      "message": "must have required property 'operator'",
 | 
					      "message": "must have required property 'id'",
 | 
				
			||||||
      "params": Object {
 | 
					      "params": Object {
 | 
				
			||||||
        "missingProperty": "operator",
 | 
					        "missingProperty": "id",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "schemaPath": "#/components/schemas/constraintSchema/required",
 | 
					      "schemaPath": "#/required",
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "schema": "#/components/schemas/featureSchema",
 | 
					  "schema": "#/components/schemas/featureSchema",
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exports[`strategySchema 1`] = `
 | 
				
			||||||
 | 
					Object {
 | 
				
			||||||
 | 
					  "data": Object {},
 | 
				
			||||||
 | 
					  "errors": Array [
 | 
				
			||||||
 | 
					    Object {
 | 
				
			||||||
 | 
					      "instancePath": "",
 | 
				
			||||||
 | 
					      "keyword": "required",
 | 
				
			||||||
 | 
					      "message": "must have required property 'name'",
 | 
				
			||||||
 | 
					      "params": Object {
 | 
				
			||||||
 | 
					        "missingProperty": "name",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "schemaPath": "#/required",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "schema": "#/components/schemas/strategySchema",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					`;
 | 
				
			||||||
@ -2,8 +2,8 @@ import { FromSchema } from 'json-schema-to-ts';
 | 
				
			|||||||
import { parametersSchema } from './parameters-schema';
 | 
					import { parametersSchema } from './parameters-schema';
 | 
				
			||||||
import { constraintSchema } from './constraint-schema';
 | 
					import { constraintSchema } from './constraint-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createStrategySchema = {
 | 
					export const createFeatureStrategySchema = {
 | 
				
			||||||
    $id: '#/components/schemas/createStrategySchema',
 | 
					    $id: '#/components/schemas/createFeatureStrategySchema',
 | 
				
			||||||
    type: 'object',
 | 
					    type: 'object',
 | 
				
			||||||
    required: ['name'],
 | 
					    required: ['name'],
 | 
				
			||||||
    properties: {
 | 
					    properties: {
 | 
				
			||||||
@ -31,4 +31,6 @@ export const createStrategySchema = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
} as const;
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type CreateStrategySchema = FromSchema<typeof createStrategySchema>;
 | 
					export type CreateFeatureStrategySchema = FromSchema<
 | 
				
			||||||
 | 
					    typeof createFeatureStrategySchema
 | 
				
			||||||
 | 
					>;
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/lib/openapi/spec/feature-environment-schema.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/lib/openapi/spec/feature-environment-schema.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import { validateSchema } from '../validate';
 | 
				
			||||||
 | 
					import { FeatureEnvironmentSchema } from './feature-environment-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('featureEnvironmentSchema', () => {
 | 
				
			||||||
 | 
					    const data: FeatureEnvironmentSchema = {
 | 
				
			||||||
 | 
					        name: '',
 | 
				
			||||||
 | 
					        enabled: true,
 | 
				
			||||||
 | 
					        strategies: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                id: '',
 | 
				
			||||||
 | 
					                featureName: '',
 | 
				
			||||||
 | 
					                projectId: '',
 | 
				
			||||||
 | 
					                environment: '',
 | 
				
			||||||
 | 
					                strategyName: '',
 | 
				
			||||||
 | 
					                constraints: [{ contextName: '', operator: 'IN' }],
 | 
				
			||||||
 | 
					                parameters: { a: '' },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(
 | 
				
			||||||
 | 
					        validateSchema('#/components/schemas/featureEnvironmentSchema', data),
 | 
				
			||||||
 | 
					    ).toBeUndefined();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('featureEnvironmentSchema empty', () => {
 | 
				
			||||||
 | 
					    expect(
 | 
				
			||||||
 | 
					        validateSchema('#/components/schemas/featureEnvironmentSchema', {}),
 | 
				
			||||||
 | 
					    ).toMatchSnapshot();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { FromSchema } from 'json-schema-to-ts';
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
import { featureStrategySchema } from './feature-strategy-schema';
 | 
					 | 
				
			||||||
import { constraintSchema } from './constraint-schema';
 | 
					import { constraintSchema } from './constraint-schema';
 | 
				
			||||||
import { parametersSchema } from './parameters-schema';
 | 
					import { parametersSchema } from './parameters-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -24,13 +23,55 @@ export const featureEnvironmentSchema = {
 | 
				
			|||||||
        strategies: {
 | 
					        strategies: {
 | 
				
			||||||
            type: 'array',
 | 
					            type: 'array',
 | 
				
			||||||
            items: {
 | 
					            items: {
 | 
				
			||||||
                $ref: '#/components/schemas/featureStrategySchema',
 | 
					                type: 'object',
 | 
				
			||||||
 | 
					                additionalProperties: false,
 | 
				
			||||||
 | 
					                required: [
 | 
				
			||||||
 | 
					                    'id',
 | 
				
			||||||
 | 
					                    'featureName',
 | 
				
			||||||
 | 
					                    'projectId',
 | 
				
			||||||
 | 
					                    'environment',
 | 
				
			||||||
 | 
					                    'strategyName',
 | 
				
			||||||
 | 
					                    'constraints',
 | 
				
			||||||
 | 
					                    'parameters',
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                    id: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    featureName: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    projectId: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    environment: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    strategyName: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    sortOrder: {
 | 
				
			||||||
 | 
					                        type: 'number',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    createdAt: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                        format: 'date-time',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    constraints: {
 | 
				
			||||||
 | 
					                        type: 'array',
 | 
				
			||||||
 | 
					                        items: {
 | 
				
			||||||
 | 
					                            $ref: '#/components/schemas/constraintSchema',
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    parameters: {
 | 
				
			||||||
 | 
					                        $ref: '#/components/schemas/parametersSchema',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
        schemas: {
 | 
					        schemas: {
 | 
				
			||||||
            featureStrategySchema,
 | 
					 | 
				
			||||||
            constraintSchema,
 | 
					            constraintSchema,
 | 
				
			||||||
            parametersSchema,
 | 
					            parametersSchema,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ test('featureSchema', () => {
 | 
				
			|||||||
        name: 'a',
 | 
					        name: 'a',
 | 
				
			||||||
        strategies: [
 | 
					        strategies: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                id: 'a',
 | 
				
			||||||
                name: 'a',
 | 
					                name: 'a',
 | 
				
			||||||
                constraints: [
 | 
					                constraints: [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
import { FromSchema } from 'json-schema-to-ts';
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
import { variantSchema } from './variant-schema';
 | 
					import { variantSchema } from './variant-schema';
 | 
				
			||||||
import { strategySchema } from './strategy-schema';
 | 
					 | 
				
			||||||
import { constraintSchema } from './constraint-schema';
 | 
					import { constraintSchema } from './constraint-schema';
 | 
				
			||||||
import { overrideSchema } from './override-schema';
 | 
					import { overrideSchema } from './override-schema';
 | 
				
			||||||
import { parametersSchema } from './parameters-schema';
 | 
					import { parametersSchema } from './parameters-schema';
 | 
				
			||||||
import { environmentSchema } from './environment-schema';
 | 
					import { environmentSchema } from './environment-schema';
 | 
				
			||||||
 | 
					import { featureStrategySchema } from './feature-strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const featureSchema = {
 | 
					export const featureSchema = {
 | 
				
			||||||
    $id: '#/components/schemas/featureSchema',
 | 
					    $id: '#/components/schemas/featureSchema',
 | 
				
			||||||
@ -55,7 +55,7 @@ export const featureSchema = {
 | 
				
			|||||||
        strategies: {
 | 
					        strategies: {
 | 
				
			||||||
            type: 'array',
 | 
					            type: 'array',
 | 
				
			||||||
            items: {
 | 
					            items: {
 | 
				
			||||||
                $ref: '#/components/schemas/strategySchema',
 | 
					                $ref: '#/components/schemas/featureStrategySchema',
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        variants: {
 | 
					        variants: {
 | 
				
			||||||
@ -71,7 +71,7 @@ export const featureSchema = {
 | 
				
			|||||||
            environmentSchema,
 | 
					            environmentSchema,
 | 
				
			||||||
            overrideSchema,
 | 
					            overrideSchema,
 | 
				
			||||||
            parametersSchema,
 | 
					            parametersSchema,
 | 
				
			||||||
            strategySchema,
 | 
					            featureStrategySchema,
 | 
				
			||||||
            variantSchema,
 | 
					            variantSchema,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,7 @@ export const featureStrategySchema = {
 | 
				
			|||||||
    $id: '#/components/schemas/featureStrategySchema',
 | 
					    $id: '#/components/schemas/featureStrategySchema',
 | 
				
			||||||
    type: 'object',
 | 
					    type: 'object',
 | 
				
			||||||
    additionalProperties: false,
 | 
					    additionalProperties: false,
 | 
				
			||||||
    required: [
 | 
					    required: ['name', 'id'],
 | 
				
			||||||
        'id',
 | 
					 | 
				
			||||||
        'featureName',
 | 
					 | 
				
			||||||
        'strategyName',
 | 
					 | 
				
			||||||
        'constraints',
 | 
					 | 
				
			||||||
        'parameters',
 | 
					 | 
				
			||||||
        'environment',
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    properties: {
 | 
					    properties: {
 | 
				
			||||||
        id: {
 | 
					        id: {
 | 
				
			||||||
            type: 'string',
 | 
					            type: 'string',
 | 
				
			||||||
@ -21,23 +14,6 @@ export const featureStrategySchema = {
 | 
				
			|||||||
        name: {
 | 
					        name: {
 | 
				
			||||||
            type: 'string',
 | 
					            type: 'string',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        createdAt: {
 | 
					 | 
				
			||||||
            type: 'string',
 | 
					 | 
				
			||||||
            format: 'date-time',
 | 
					 | 
				
			||||||
            nullable: true,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        featureName: {
 | 
					 | 
				
			||||||
            type: 'string',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        projectId: {
 | 
					 | 
				
			||||||
            type: 'string',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        environment: {
 | 
					 | 
				
			||||||
            type: 'string',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        strategyName: {
 | 
					 | 
				
			||||||
            type: 'string',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        sortOrder: {
 | 
					        sortOrder: {
 | 
				
			||||||
            type: 'number',
 | 
					            type: 'number',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ import { parametersSchema } from './parameters-schema';
 | 
				
			|||||||
import { variantSchema } from './variant-schema';
 | 
					import { variantSchema } from './variant-schema';
 | 
				
			||||||
import { overrideSchema } from './override-schema';
 | 
					import { overrideSchema } from './override-schema';
 | 
				
			||||||
import { constraintSchema } from './constraint-schema';
 | 
					import { constraintSchema } from './constraint-schema';
 | 
				
			||||||
import { strategySchema } from './strategy-schema';
 | 
					import { featureStrategySchema } from './feature-strategy-schema';
 | 
				
			||||||
import { environmentSchema } from './environment-schema';
 | 
					import { environmentSchema } from './environment-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const featuresSchema = {
 | 
					export const featuresSchema = {
 | 
				
			||||||
@ -30,7 +30,7 @@ export const featuresSchema = {
 | 
				
			|||||||
            featureSchema,
 | 
					            featureSchema,
 | 
				
			||||||
            overrideSchema,
 | 
					            overrideSchema,
 | 
				
			||||||
            parametersSchema,
 | 
					            parametersSchema,
 | 
				
			||||||
            strategySchema,
 | 
					            featureStrategySchema,
 | 
				
			||||||
            variantSchema,
 | 
					            variantSchema,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ import { FromSchema } from 'json-schema-to-ts';
 | 
				
			|||||||
import { parametersSchema } from './parameters-schema';
 | 
					import { parametersSchema } from './parameters-schema';
 | 
				
			||||||
import { variantSchema } from './variant-schema';
 | 
					import { variantSchema } from './variant-schema';
 | 
				
			||||||
import { overrideSchema } from './override-schema';
 | 
					import { overrideSchema } from './override-schema';
 | 
				
			||||||
import { strategySchema } from './strategy-schema';
 | 
					import { featureStrategySchema } from './feature-strategy-schema';
 | 
				
			||||||
import { featureSchema } from './feature-schema';
 | 
					import { featureSchema } from './feature-schema';
 | 
				
			||||||
import { constraintSchema } from './constraint-schema';
 | 
					import { constraintSchema } from './constraint-schema';
 | 
				
			||||||
import { environmentSchema } from './environment-schema';
 | 
					import { environmentSchema } from './environment-schema';
 | 
				
			||||||
@ -53,7 +53,7 @@ export const healthOverviewSchema = {
 | 
				
			|||||||
            featureSchema,
 | 
					            featureSchema,
 | 
				
			||||||
            overrideSchema,
 | 
					            overrideSchema,
 | 
				
			||||||
            parametersSchema,
 | 
					            parametersSchema,
 | 
				
			||||||
            strategySchema,
 | 
					            featureStrategySchema,
 | 
				
			||||||
            variantSchema,
 | 
					            variantSchema,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
import { FromSchema } from 'json-schema-to-ts';
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
import { featureSchema } from './feature-schema';
 | 
					import { featureSchema } from './feature-schema';
 | 
				
			||||||
import { strategySchema } from './strategy-schema';
 | 
					 | 
				
			||||||
import { tagSchema } from './tag-schema';
 | 
					import { tagSchema } from './tag-schema';
 | 
				
			||||||
import { tagTypeSchema } from './tag-type-schema';
 | 
					import { tagTypeSchema } from './tag-type-schema';
 | 
				
			||||||
import { featureTagSchema } from './feature-tag-schema';
 | 
					import { featureTagSchema } from './feature-tag-schema';
 | 
				
			||||||
@ -10,6 +9,7 @@ import { featureEnvironmentSchema } from './feature-environment-schema';
 | 
				
			|||||||
import { environmentSchema } from './environment-schema';
 | 
					import { environmentSchema } from './environment-schema';
 | 
				
			||||||
import { segmentSchema } from './segment-schema';
 | 
					import { segmentSchema } from './segment-schema';
 | 
				
			||||||
import { featureStrategySegmentSchema } from './feature-strategy-segment-schema';
 | 
					import { featureStrategySegmentSchema } from './feature-strategy-segment-schema';
 | 
				
			||||||
 | 
					import { strategySchema } from './strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const stateSchema = {
 | 
					export const stateSchema = {
 | 
				
			||||||
    $id: '#/components/schemas/stateSchema',
 | 
					    $id: '#/components/schemas/stateSchema',
 | 
				
			||||||
@ -90,7 +90,6 @@ export const stateSchema = {
 | 
				
			|||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
        schemas: {
 | 
					        schemas: {
 | 
				
			||||||
            featureSchema,
 | 
					            featureSchema,
 | 
				
			||||||
            strategySchema,
 | 
					 | 
				
			||||||
            tagSchema,
 | 
					            tagSchema,
 | 
				
			||||||
            tagTypeSchema,
 | 
					            tagTypeSchema,
 | 
				
			||||||
            featureTagSchema,
 | 
					            featureTagSchema,
 | 
				
			||||||
@ -100,6 +99,7 @@ export const stateSchema = {
 | 
				
			|||||||
            environmentSchema,
 | 
					            environmentSchema,
 | 
				
			||||||
            segmentSchema,
 | 
					            segmentSchema,
 | 
				
			||||||
            featureStrategySegmentSchema,
 | 
					            featureStrategySegmentSchema,
 | 
				
			||||||
 | 
					            strategySchema,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
} as const;
 | 
					} as const;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										27
									
								
								src/lib/openapi/spec/strategies-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/lib/openapi/spec/strategies-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					import { strategySchema } from './strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const strategiesSchema = {
 | 
				
			||||||
 | 
					    $id: '#/components/schemas/strategiesSchema',
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    additionalProperties: false,
 | 
				
			||||||
 | 
					    required: ['version', 'strategies'],
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					        version: {
 | 
				
			||||||
 | 
					            type: 'integer',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        strategies: {
 | 
				
			||||||
 | 
					            type: 'array',
 | 
				
			||||||
 | 
					            items: {
 | 
				
			||||||
 | 
					                $ref: '#/components/schemas/strategySchema',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        schemas: {
 | 
				
			||||||
 | 
					            strategySchema,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type StrategiesSchema = FromSchema<typeof strategiesSchema>;
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/lib/openapi/spec/strategy-schema.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/lib/openapi/spec/strategy-schema.test.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					import { validateSchema } from '../validate';
 | 
				
			||||||
 | 
					import { StrategySchema } from './strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('strategySchema', () => {
 | 
				
			||||||
 | 
					    const data: StrategySchema = {
 | 
				
			||||||
 | 
					        description: '',
 | 
				
			||||||
 | 
					        name: '',
 | 
				
			||||||
 | 
					        displayName: '',
 | 
				
			||||||
 | 
					        editable: false,
 | 
				
			||||||
 | 
					        deprecated: false,
 | 
				
			||||||
 | 
					        parameters: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                name: '',
 | 
				
			||||||
 | 
					                type: '',
 | 
				
			||||||
 | 
					                description: '',
 | 
				
			||||||
 | 
					                required: true,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(
 | 
				
			||||||
 | 
					        validateSchema('#/components/schemas/strategySchema', data),
 | 
				
			||||||
 | 
					    ).toBeUndefined();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(
 | 
				
			||||||
 | 
					        validateSchema('#/components/schemas/strategySchema', {}),
 | 
				
			||||||
 | 
					    ).toMatchSnapshot();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -1,38 +1,57 @@
 | 
				
			|||||||
import { FromSchema } from 'json-schema-to-ts';
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
import { constraintSchema } from './constraint-schema';
 | 
					 | 
				
			||||||
import { parametersSchema } from './parameters-schema';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const strategySchema = {
 | 
					export const strategySchema = {
 | 
				
			||||||
    $id: '#/components/schemas/strategySchema',
 | 
					    $id: '#/components/schemas/strategySchema',
 | 
				
			||||||
    type: 'object',
 | 
					    type: 'object',
 | 
				
			||||||
    additionalProperties: false,
 | 
					    additionalProperties: false,
 | 
				
			||||||
    required: ['name'],
 | 
					    required: [
 | 
				
			||||||
 | 
					        'name',
 | 
				
			||||||
 | 
					        'displayName',
 | 
				
			||||||
 | 
					        'description',
 | 
				
			||||||
 | 
					        'editable',
 | 
				
			||||||
 | 
					        'deprecated',
 | 
				
			||||||
 | 
					        'parameters',
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
    properties: {
 | 
					    properties: {
 | 
				
			||||||
        id: {
 | 
					 | 
				
			||||||
            type: 'string',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        name: {
 | 
					        name: {
 | 
				
			||||||
            type: 'string',
 | 
					            type: 'string',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        sortOrder: {
 | 
					        displayName: {
 | 
				
			||||||
            type: 'number',
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					            nullable: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        constraints: {
 | 
					        description: {
 | 
				
			||||||
            type: 'array',
 | 
					            type: 'string',
 | 
				
			||||||
            items: {
 | 
					        },
 | 
				
			||||||
                $ref: '#/components/schemas/constraintSchema',
 | 
					        editable: {
 | 
				
			||||||
            },
 | 
					            type: 'boolean',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        deprecated: {
 | 
				
			||||||
 | 
					            type: 'boolean',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        parameters: {
 | 
					        parameters: {
 | 
				
			||||||
            $ref: '#/components/schemas/parametersSchema',
 | 
					            type: 'array',
 | 
				
			||||||
        },
 | 
					            items: {
 | 
				
			||||||
    },
 | 
					                type: 'object',
 | 
				
			||||||
    components: {
 | 
					                additionalProperties: false,
 | 
				
			||||||
        schemas: {
 | 
					                properties: {
 | 
				
			||||||
            constraintSchema,
 | 
					                    name: {
 | 
				
			||||||
            parametersSchema,
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    type: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    description: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    required: {
 | 
				
			||||||
 | 
					                        type: 'boolean',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    components: {},
 | 
				
			||||||
} as const;
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type StrategySchema = FromSchema<typeof strategySchema>;
 | 
					export type StrategySchema = FromSchema<typeof strategySchema>;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								src/lib/openapi/spec/update-feature-strategy-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/lib/openapi/spec/update-feature-strategy-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					import { parametersSchema } from './parameters-schema';
 | 
				
			||||||
 | 
					import { constraintSchema } from './constraint-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const updateFeatureStrategySchema = {
 | 
				
			||||||
 | 
					    $id: '#/components/schemas/updateFeatureStrategySchema',
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					        name: {
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        sortOrder: {
 | 
				
			||||||
 | 
					            type: 'number',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        constraints: {
 | 
				
			||||||
 | 
					            type: 'array',
 | 
				
			||||||
 | 
					            items: {
 | 
				
			||||||
 | 
					                $ref: '#/components/schemas/constraintSchema',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        parameters: {
 | 
				
			||||||
 | 
					            $ref: '#/components/schemas/parametersSchema',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        schemas: {
 | 
				
			||||||
 | 
					            constraintSchema,
 | 
				
			||||||
 | 
					            parametersSchema,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type UpdateFeatureStrategySchema = FromSchema<
 | 
				
			||||||
 | 
					    typeof updateFeatureStrategySchema
 | 
				
			||||||
 | 
					>;
 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
import { FromSchema } from 'json-schema-to-ts';
 | 
					 | 
				
			||||||
import { strategySchema } from './strategy-schema';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const updateStrategySchema = {
 | 
					 | 
				
			||||||
    ...strategySchema,
 | 
					 | 
				
			||||||
    $id: '#/components/schemas/updateStrategySchema',
 | 
					 | 
				
			||||||
    required: [],
 | 
					 | 
				
			||||||
    components: {},
 | 
					 | 
				
			||||||
} as const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export type UpdateStrategySchema = FromSchema<typeof updateStrategySchema>;
 | 
					 | 
				
			||||||
							
								
								
									
										41
									
								
								src/lib/openapi/spec/upsert-strategy-schema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/lib/openapi/spec/upsert-strategy-schema.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					import { FromSchema } from 'json-schema-to-ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const upsertStrategySchema = {
 | 
				
			||||||
 | 
					    $id: '#/components/schemas/upsertStrategySchema',
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    required: ['name'],
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					        name: {
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        description: {
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        editable: {
 | 
				
			||||||
 | 
					            type: 'boolean',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        parameters: {
 | 
				
			||||||
 | 
					            type: 'array',
 | 
				
			||||||
 | 
					            items: {
 | 
				
			||||||
 | 
					                type: 'object',
 | 
				
			||||||
 | 
					                properties: {
 | 
				
			||||||
 | 
					                    name: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    type: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    description: {
 | 
				
			||||||
 | 
					                        type: 'string',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    required: {
 | 
				
			||||||
 | 
					                        type: 'boolean',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {},
 | 
				
			||||||
 | 
					} as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type UpsertStrategySchema = FromSchema<typeof upsertStrategySchema>;
 | 
				
			||||||
@ -22,15 +22,15 @@ import {
 | 
				
			|||||||
    featureSchema,
 | 
					    featureSchema,
 | 
				
			||||||
    FeatureSchema,
 | 
					    FeatureSchema,
 | 
				
			||||||
} from '../../../openapi/spec/feature-schema';
 | 
					} from '../../../openapi/spec/feature-schema';
 | 
				
			||||||
import { StrategySchema } from '../../../openapi/spec/strategy-schema';
 | 
					import { FeatureStrategySchema } from '../../../openapi/spec/feature-strategy-schema';
 | 
				
			||||||
import { ParametersSchema } from '../../../openapi/spec/parameters-schema';
 | 
					import { ParametersSchema } from '../../../openapi/spec/parameters-schema';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    featuresSchema,
 | 
					    featuresSchema,
 | 
				
			||||||
    FeaturesSchema,
 | 
					    FeaturesSchema,
 | 
				
			||||||
} from '../../../openapi/spec/features-schema';
 | 
					} from '../../../openapi/spec/features-schema';
 | 
				
			||||||
import { UpdateFeatureSchema } from '../../../openapi/spec/update-feature-schema';
 | 
					import { UpdateFeatureSchema } from '../../../openapi/spec/update-feature-schema';
 | 
				
			||||||
import { UpdateStrategySchema } from '../../../openapi/spec/update-strategy-schema';
 | 
					import { UpdateFeatureStrategySchema } from '../../../openapi/spec/update-feature-strategy-schema';
 | 
				
			||||||
import { CreateStrategySchema } from '../../../openapi/spec/create-strategy-schema';
 | 
					import { CreateFeatureStrategySchema } from '../../../openapi/spec/create-feature-strategy-schema';
 | 
				
			||||||
import { serializeDates } from '../../../types/serialize-dates';
 | 
					import { serializeDates } from '../../../types/serialize-dates';
 | 
				
			||||||
import { OpenApiService } from '../../../services/openapi-service';
 | 
					import { OpenApiService } from '../../../services/openapi-service';
 | 
				
			||||||
import { createRequestSchema, createResponseSchema } from '../../../openapi';
 | 
					import { createRequestSchema, createResponseSchema } from '../../../openapi';
 | 
				
			||||||
@ -133,13 +133,15 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        this.route({
 | 
					        this.route({
 | 
				
			||||||
            method: 'get',
 | 
					            method: 'get',
 | 
				
			||||||
            path: PATH_STRATEGIES,
 | 
					            path: PATH_STRATEGIES,
 | 
				
			||||||
            handler: this.getStrategies,
 | 
					            handler: this.getFeatureStrategies,
 | 
				
			||||||
            permission: NONE,
 | 
					            permission: NONE,
 | 
				
			||||||
            middleware: [
 | 
					            middleware: [
 | 
				
			||||||
                openApiService.validPath({
 | 
					                openApiService.validPath({
 | 
				
			||||||
                    tags: ['admin'],
 | 
					                    tags: ['admin'],
 | 
				
			||||||
                    operationId: 'getStrategies',
 | 
					                    operationId: 'getFeatureStrategies',
 | 
				
			||||||
                    responses: { 200: createResponseSchema('strategySchema') },
 | 
					                    responses: {
 | 
				
			||||||
 | 
					                        200: createResponseSchema('featureStrategySchema'),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -147,13 +149,15 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        this.route({
 | 
					        this.route({
 | 
				
			||||||
            method: 'post',
 | 
					            method: 'post',
 | 
				
			||||||
            path: PATH_STRATEGIES,
 | 
					            path: PATH_STRATEGIES,
 | 
				
			||||||
            handler: this.addStrategy,
 | 
					            handler: this.addFeatureStrategy,
 | 
				
			||||||
            permission: CREATE_FEATURE_STRATEGY,
 | 
					            permission: CREATE_FEATURE_STRATEGY,
 | 
				
			||||||
            middleware: [
 | 
					            middleware: [
 | 
				
			||||||
                openApiService.validPath({
 | 
					                openApiService.validPath({
 | 
				
			||||||
                    tags: ['admin'],
 | 
					                    tags: ['admin'],
 | 
				
			||||||
                    operationId: 'addStrategy',
 | 
					                    operationId: 'addFeatureStrategy',
 | 
				
			||||||
                    requestBody: createRequestSchema('createStrategySchema'),
 | 
					                    requestBody: createRequestSchema(
 | 
				
			||||||
 | 
					                        'createFeatureStrategySchema',
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                    responses: {
 | 
					                    responses: {
 | 
				
			||||||
                        200: createResponseSchema('featureStrategySchema'),
 | 
					                        200: createResponseSchema('featureStrategySchema'),
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
@ -164,12 +168,12 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        this.route({
 | 
					        this.route({
 | 
				
			||||||
            method: 'get',
 | 
					            method: 'get',
 | 
				
			||||||
            path: PATH_STRATEGY,
 | 
					            path: PATH_STRATEGY,
 | 
				
			||||||
            handler: this.getStrategy,
 | 
					            handler: this.getFeatureStrategy,
 | 
				
			||||||
            permission: NONE,
 | 
					            permission: NONE,
 | 
				
			||||||
            middleware: [
 | 
					            middleware: [
 | 
				
			||||||
                openApiService.validPath({
 | 
					                openApiService.validPath({
 | 
				
			||||||
                    tags: ['admin'],
 | 
					                    tags: ['admin'],
 | 
				
			||||||
                    operationId: 'getStrategy',
 | 
					                    operationId: 'getFeatureStrategy',
 | 
				
			||||||
                    responses: {
 | 
					                    responses: {
 | 
				
			||||||
                        200: createResponseSchema('featureStrategySchema'),
 | 
					                        200: createResponseSchema('featureStrategySchema'),
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
@ -180,28 +184,31 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        this.route({
 | 
					        this.route({
 | 
				
			||||||
            method: 'put',
 | 
					            method: 'put',
 | 
				
			||||||
            path: PATH_STRATEGY,
 | 
					            path: PATH_STRATEGY,
 | 
				
			||||||
            handler: this.updateStrategy,
 | 
					            handler: this.updateFeatureStrategy,
 | 
				
			||||||
            permission: UPDATE_FEATURE_STRATEGY,
 | 
					            permission: UPDATE_FEATURE_STRATEGY,
 | 
				
			||||||
            middleware: [
 | 
					            middleware: [
 | 
				
			||||||
                openApiService.validPath({
 | 
					                openApiService.validPath({
 | 
				
			||||||
                    tags: ['admin'],
 | 
					                    tags: ['admin'],
 | 
				
			||||||
                    operationId: 'updateStrategy',
 | 
					                    operationId: 'updateFeatureStrategy',
 | 
				
			||||||
                    requestBody: createRequestSchema('updateStrategySchema'),
 | 
					                    requestBody: createRequestSchema(
 | 
				
			||||||
 | 
					                        'updateFeatureStrategySchema',
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                    responses: {
 | 
					                    responses: {
 | 
				
			||||||
                        200: createResponseSchema('featureStrategySchema'),
 | 
					                        200: createResponseSchema('featureStrategySchema'),
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.route({
 | 
					        this.route({
 | 
				
			||||||
            method: 'patch',
 | 
					            method: 'patch',
 | 
				
			||||||
            path: PATH_STRATEGY,
 | 
					            path: PATH_STRATEGY,
 | 
				
			||||||
            handler: this.patchStrategy,
 | 
					            handler: this.patchFeatureStrategy,
 | 
				
			||||||
            permission: UPDATE_FEATURE_STRATEGY,
 | 
					            permission: UPDATE_FEATURE_STRATEGY,
 | 
				
			||||||
            middleware: [
 | 
					            middleware: [
 | 
				
			||||||
                openApiService.validPath({
 | 
					                openApiService.validPath({
 | 
				
			||||||
                    tags: ['admin'],
 | 
					                    tags: ['admin'],
 | 
				
			||||||
                    operationId: 'patchStrategy',
 | 
					                    operationId: 'patchFeatureStrategy',
 | 
				
			||||||
                    requestBody: createRequestSchema('patchesSchema'),
 | 
					                    requestBody: createRequestSchema('patchesSchema'),
 | 
				
			||||||
                    responses: {
 | 
					                    responses: {
 | 
				
			||||||
                        200: createResponseSchema('featureStrategySchema'),
 | 
					                        200: createResponseSchema('featureStrategySchema'),
 | 
				
			||||||
@ -213,11 +220,11 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
            method: 'delete',
 | 
					            method: 'delete',
 | 
				
			||||||
            path: PATH_STRATEGY,
 | 
					            path: PATH_STRATEGY,
 | 
				
			||||||
            acceptAnyContentType: true,
 | 
					            acceptAnyContentType: true,
 | 
				
			||||||
            handler: this.deleteStrategy,
 | 
					            handler: this.deleteFeatureStrategy,
 | 
				
			||||||
            permission: DELETE_FEATURE_STRATEGY,
 | 
					            permission: DELETE_FEATURE_STRATEGY,
 | 
				
			||||||
            middleware: [
 | 
					            middleware: [
 | 
				
			||||||
                openApiService.validPath({
 | 
					                openApiService.validPath({
 | 
				
			||||||
                    operationId: 'deleteStrategy',
 | 
					                    operationId: 'deleteFeatureStrategy',
 | 
				
			||||||
                    tags: ['admin'],
 | 
					                    tags: ['admin'],
 | 
				
			||||||
                    responses: { 200: emptyResponse },
 | 
					                    responses: { 200: emptyResponse },
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
@ -516,9 +523,13 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).end();
 | 
					        res.status(200).end();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async addStrategy(
 | 
					    async addFeatureStrategy(
 | 
				
			||||||
        req: IAuthRequest<FeatureStrategyParams, any, CreateStrategySchema>,
 | 
					        req: IAuthRequest<
 | 
				
			||||||
        res: Response<StrategySchema>,
 | 
					            FeatureStrategyParams,
 | 
				
			||||||
 | 
					            any,
 | 
				
			||||||
 | 
					            CreateFeatureStrategySchema
 | 
				
			||||||
 | 
					        >,
 | 
				
			||||||
 | 
					        res: Response<FeatureStrategySchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { projectId, featureName, environment } = req.params;
 | 
					        const { projectId, featureName, environment } = req.params;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
@ -530,9 +541,9 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).json(strategy);
 | 
					        res.status(200).json(strategy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getStrategies(
 | 
					    async getFeatureStrategies(
 | 
				
			||||||
        req: Request<FeatureStrategyParams, any, any, any>,
 | 
					        req: Request<FeatureStrategyParams, any, any, any>,
 | 
				
			||||||
        res: Response<StrategySchema[]>,
 | 
					        res: Response<FeatureStrategySchema[]>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { projectId, featureName, environment } = req.params;
 | 
					        const { projectId, featureName, environment } = req.params;
 | 
				
			||||||
        const featureStrategies =
 | 
					        const featureStrategies =
 | 
				
			||||||
@ -544,9 +555,9 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).json(featureStrategies);
 | 
					        res.status(200).json(featureStrategies);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async updateStrategy(
 | 
					    async updateFeatureStrategy(
 | 
				
			||||||
        req: IAuthRequest<StrategyIdParams, any, UpdateStrategySchema>,
 | 
					        req: IAuthRequest<StrategyIdParams, any, UpdateFeatureStrategySchema>,
 | 
				
			||||||
        res: Response<StrategySchema>,
 | 
					        res: Response<FeatureStrategySchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { strategyId, environment, projectId, featureName } = req.params;
 | 
					        const { strategyId, environment, projectId, featureName } = req.params;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
@ -559,9 +570,9 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).json(updatedStrategy);
 | 
					        res.status(200).json(updatedStrategy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async patchStrategy(
 | 
					    async patchFeatureStrategy(
 | 
				
			||||||
        req: IAuthRequest<StrategyIdParams, any, Operation[], any>,
 | 
					        req: IAuthRequest<StrategyIdParams, any, Operation[], any>,
 | 
				
			||||||
        res: Response<StrategySchema>,
 | 
					        res: Response<FeatureStrategySchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { strategyId, projectId, environment, featureName } = req.params;
 | 
					        const { strategyId, projectId, environment, featureName } = req.params;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
@ -577,9 +588,9 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).json(updatedStrategy);
 | 
					        res.status(200).json(updatedStrategy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getStrategy(
 | 
					    async getFeatureStrategy(
 | 
				
			||||||
        req: IAuthRequest<StrategyIdParams, any, any, any>,
 | 
					        req: IAuthRequest<StrategyIdParams, any, any, any>,
 | 
				
			||||||
        res: Response<StrategySchema>,
 | 
					        res: Response<FeatureStrategySchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        this.logger.info('Getting strategy');
 | 
					        this.logger.info('Getting strategy');
 | 
				
			||||||
        const { strategyId } = req.params;
 | 
					        const { strategyId } = req.params;
 | 
				
			||||||
@ -588,7 +599,7 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
        res.status(200).json(strategy);
 | 
					        res.status(200).json(strategy);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async deleteStrategy(
 | 
					    async deleteFeatureStrategy(
 | 
				
			||||||
        req: IAuthRequest<StrategyIdParams, any, any, any>,
 | 
					        req: IAuthRequest<StrategyIdParams, any, any, any>,
 | 
				
			||||||
        res: Response<void>,
 | 
					        res: Response<void>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
@ -612,7 +623,7 @@ export default class ProjectFeaturesController extends Controller {
 | 
				
			|||||||
            { name: string; value: string | number },
 | 
					            { name: string; value: string | number },
 | 
				
			||||||
            any
 | 
					            any
 | 
				
			||||||
        >,
 | 
					        >,
 | 
				
			||||||
        res: Response<StrategySchema>,
 | 
					        res: Response<FeatureStrategySchema>,
 | 
				
			||||||
    ): Promise<void> {
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const { strategyId, environment, projectId, featureName } = req.params;
 | 
					        const { strategyId, environment, projectId, featureName } = req.params;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -54,8 +54,8 @@ test('require a name when creating a new strategy', async () => {
 | 
				
			|||||||
        .send({})
 | 
					        .send({})
 | 
				
			||||||
        .expect(400)
 | 
					        .expect(400)
 | 
				
			||||||
        .expect((res) => {
 | 
					        .expect((res) => {
 | 
				
			||||||
            expect(res.body.details[0].message === '"name" is required').toBe(
 | 
					            expect(res.body.validation[0].message).toEqual(
 | 
				
			||||||
                true,
 | 
					                "should have required property 'name'",
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -2,18 +2,28 @@ import { IUnleashConfig } from '../../types/option';
 | 
				
			|||||||
import { IUnleashServices } from '../../types/services';
 | 
					import { IUnleashServices } from '../../types/services';
 | 
				
			||||||
import StrategyService from '../../services/strategy-service';
 | 
					import StrategyService from '../../services/strategy-service';
 | 
				
			||||||
import { Logger } from '../../logger';
 | 
					import { Logger } from '../../logger';
 | 
				
			||||||
 | 
					 | 
				
			||||||
import Controller from '../controller';
 | 
					import Controller from '../controller';
 | 
				
			||||||
 | 
					 | 
				
			||||||
import { extractUsername } from '../../util/extract-user';
 | 
					import { extractUsername } from '../../util/extract-user';
 | 
				
			||||||
import { handleErrors } from '../util';
 | 
					 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    DELETE_STRATEGY,
 | 
					    DELETE_STRATEGY,
 | 
				
			||||||
    CREATE_STRATEGY,
 | 
					    CREATE_STRATEGY,
 | 
				
			||||||
    UPDATE_STRATEGY,
 | 
					    UPDATE_STRATEGY,
 | 
				
			||||||
 | 
					    NONE,
 | 
				
			||||||
} from '../../types/permissions';
 | 
					} from '../../types/permissions';
 | 
				
			||||||
import { Request, Response } from 'express';
 | 
					import { Request, Response } from 'express';
 | 
				
			||||||
import { IAuthRequest } from '../unleash-types';
 | 
					import { IAuthRequest } from '../unleash-types';
 | 
				
			||||||
 | 
					import { OpenApiService } from '../../services/openapi-service';
 | 
				
			||||||
 | 
					import { emptyResponse } from '../../openapi/spec/empty-response';
 | 
				
			||||||
 | 
					import { createRequestSchema, createResponseSchema } from '../../openapi';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    strategySchema,
 | 
				
			||||||
 | 
					    StrategySchema,
 | 
				
			||||||
 | 
					} from '../../openapi/spec/strategy-schema';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    strategiesSchema,
 | 
				
			||||||
 | 
					    StrategiesSchema,
 | 
				
			||||||
 | 
					} from '../../openapi/spec/strategies-schema';
 | 
				
			||||||
 | 
					import { UpsertStrategySchema } from '../../openapi/spec/upsert-strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const version = 1;
 | 
					const version = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -22,112 +32,210 @@ class StrategyController extends Controller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private strategyService: StrategyService;
 | 
					    private strategyService: StrategyService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private openApiService: OpenApiService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(
 | 
					    constructor(
 | 
				
			||||||
        config: IUnleashConfig,
 | 
					        config: IUnleashConfig,
 | 
				
			||||||
        { strategyService }: Pick<IUnleashServices, 'strategyService'>,
 | 
					        {
 | 
				
			||||||
 | 
					            strategyService,
 | 
				
			||||||
 | 
					            openApiService,
 | 
				
			||||||
 | 
					        }: Pick<IUnleashServices, 'strategyService' | 'openApiService'>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        super(config);
 | 
					        super(config);
 | 
				
			||||||
        this.logger = config.getLogger('/admin-api/strategy.js');
 | 
					        this.logger = config.getLogger('/admin-api/strategy.js');
 | 
				
			||||||
        this.strategyService = strategyService;
 | 
					        this.strategyService = strategyService;
 | 
				
			||||||
 | 
					        this.openApiService = openApiService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.get('/', this.getAllStrategies);
 | 
					        this.route({
 | 
				
			||||||
        this.get('/:name', this.getStrategy);
 | 
					            method: 'get',
 | 
				
			||||||
        this.delete('/:name', this.removeStrategy, DELETE_STRATEGY);
 | 
					            path: '',
 | 
				
			||||||
        this.post('/', this.createStrategy, CREATE_STRATEGY);
 | 
					            handler: this.getAllStrategies,
 | 
				
			||||||
        this.put('/:strategyName', this.updateStrategy, UPDATE_STRATEGY);
 | 
					            permission: NONE,
 | 
				
			||||||
        this.post(
 | 
					            middleware: [
 | 
				
			||||||
            '/:strategyName/deprecate',
 | 
					                openApiService.validPath({
 | 
				
			||||||
            this.deprecateStrategy,
 | 
					                    tags: ['admin'],
 | 
				
			||||||
            UPDATE_STRATEGY,
 | 
					                    operationId: 'getAllStrategies',
 | 
				
			||||||
        );
 | 
					                    responses: {
 | 
				
			||||||
        this.post(
 | 
					                        200: createResponseSchema('strategiesSchema'),
 | 
				
			||||||
            '/:strategyName/reactivate',
 | 
					                    },
 | 
				
			||||||
            this.reactivateStrategy,
 | 
					                }),
 | 
				
			||||||
            UPDATE_STRATEGY,
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'get',
 | 
				
			||||||
 | 
					            path: '/:name',
 | 
				
			||||||
 | 
					            handler: this.getStrategy,
 | 
				
			||||||
 | 
					            permission: NONE,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['admin'],
 | 
				
			||||||
 | 
					                    operationId: 'getStrategy',
 | 
				
			||||||
 | 
					                    responses: { 200: createResponseSchema('strategySchema') },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'delete',
 | 
				
			||||||
 | 
					            path: '/:name',
 | 
				
			||||||
 | 
					            handler: this.removeStrategy,
 | 
				
			||||||
 | 
					            permission: DELETE_STRATEGY,
 | 
				
			||||||
 | 
					            acceptAnyContentType: true,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['admin'],
 | 
				
			||||||
 | 
					                    operationId: 'removeStrategy',
 | 
				
			||||||
 | 
					                    responses: { 200: emptyResponse },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'post',
 | 
				
			||||||
 | 
					            path: '',
 | 
				
			||||||
 | 
					            handler: this.createStrategy,
 | 
				
			||||||
 | 
					            permission: CREATE_STRATEGY,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['admin'],
 | 
				
			||||||
 | 
					                    operationId: 'createStrategy',
 | 
				
			||||||
 | 
					                    requestBody: createRequestSchema('upsertStrategySchema'),
 | 
				
			||||||
 | 
					                    responses: { 201: emptyResponse },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'put',
 | 
				
			||||||
 | 
					            path: '/:strategyName',
 | 
				
			||||||
 | 
					            handler: this.updateStrategy,
 | 
				
			||||||
 | 
					            permission: UPDATE_STRATEGY,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['admin'],
 | 
				
			||||||
 | 
					                    operationId: 'updateStrategy',
 | 
				
			||||||
 | 
					                    requestBody: createRequestSchema('upsertStrategySchema'),
 | 
				
			||||||
 | 
					                    responses: { 200: emptyResponse },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'post',
 | 
				
			||||||
 | 
					            path: '/:strategyName/deprecate',
 | 
				
			||||||
 | 
					            handler: this.deprecateStrategy,
 | 
				
			||||||
 | 
					            permission: UPDATE_STRATEGY,
 | 
				
			||||||
 | 
					            acceptAnyContentType: true,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['admin'],
 | 
				
			||||||
 | 
					                    operationId: 'deprecateStrategy',
 | 
				
			||||||
 | 
					                    responses: { 200: emptyResponse },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.route({
 | 
				
			||||||
 | 
					            method: 'post',
 | 
				
			||||||
 | 
					            path: '/:strategyName/reactivate',
 | 
				
			||||||
 | 
					            handler: this.reactivateStrategy,
 | 
				
			||||||
 | 
					            permission: UPDATE_STRATEGY,
 | 
				
			||||||
 | 
					            acceptAnyContentType: true,
 | 
				
			||||||
 | 
					            middleware: [
 | 
				
			||||||
 | 
					                openApiService.validPath({
 | 
				
			||||||
 | 
					                    tags: ['admin'],
 | 
				
			||||||
 | 
					                    operationId: 'reactivateStrategy',
 | 
				
			||||||
 | 
					                    responses: { 200: emptyResponse },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async getAllStrategies(
 | 
				
			||||||
 | 
					        req: Request,
 | 
				
			||||||
 | 
					        res: Response<StrategiesSchema>,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
 | 
					        const strategies = await this.strategyService.getStrategies();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.openApiService.respondWithValidation(
 | 
				
			||||||
 | 
					            200,
 | 
				
			||||||
 | 
					            res,
 | 
				
			||||||
 | 
					            strategiesSchema.$id,
 | 
				
			||||||
 | 
					            { version, strategies },
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getAllStrategies(req: Request, res: Response): Promise<void> {
 | 
					    async getStrategy(
 | 
				
			||||||
        try {
 | 
					        req: Request,
 | 
				
			||||||
            const strategies = await this.strategyService.getStrategies();
 | 
					        res: Response<StrategySchema>,
 | 
				
			||||||
            res.json({ version, strategies });
 | 
					    ): Promise<void> {
 | 
				
			||||||
        } catch (err) {
 | 
					        const strategy = await this.strategyService.getStrategy(
 | 
				
			||||||
            handleErrors(res, this.logger, err);
 | 
					            req.params.name,
 | 
				
			||||||
        }
 | 
					        );
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getStrategy(req: Request, res: Response): Promise<void> {
 | 
					        this.openApiService.respondWithValidation(
 | 
				
			||||||
        try {
 | 
					            200,
 | 
				
			||||||
            const { name } = req.params;
 | 
					            res,
 | 
				
			||||||
            const strategy = await this.strategyService.getStrategy(name);
 | 
					            strategySchema.$id,
 | 
				
			||||||
            res.json(strategy).end();
 | 
					            strategy,
 | 
				
			||||||
        } catch (err) {
 | 
					        );
 | 
				
			||||||
            res.status(404).json({ error: 'Could not find strategy' });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async removeStrategy(req: IAuthRequest, res: Response): Promise<void> {
 | 
					    async removeStrategy(req: IAuthRequest, res: Response): Promise<void> {
 | 
				
			||||||
        const strategyName = req.params.name;
 | 
					        const strategyName = req.params.name;
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        await this.strategyService.removeStrategy(strategyName, userName);
 | 
				
			||||||
            await this.strategyService.removeStrategy(strategyName, userName);
 | 
					        res.status(200).end();
 | 
				
			||||||
            res.status(200).end();
 | 
					 | 
				
			||||||
        } catch (error) {
 | 
					 | 
				
			||||||
            handleErrors(res, this.logger, error);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async createStrategy(req: IAuthRequest, res: Response): Promise<void> {
 | 
					    async createStrategy(
 | 
				
			||||||
 | 
					        req: IAuthRequest<unknown, UpsertStrategySchema>,
 | 
				
			||||||
 | 
					        res: Response<void>,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
        try {
 | 
					
 | 
				
			||||||
            await this.strategyService.createStrategy(req.body, userName);
 | 
					        await this.strategyService.createStrategy(req.body, userName);
 | 
				
			||||||
            res.status(201).end();
 | 
					        res.status(201).end();
 | 
				
			||||||
        } catch (error) {
 | 
					 | 
				
			||||||
            handleErrors(res, this.logger, error);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async updateStrategy(req: IAuthRequest, res: Response): Promise<void> {
 | 
					    async updateStrategy(
 | 
				
			||||||
 | 
					        req: IAuthRequest<unknown, UpsertStrategySchema>,
 | 
				
			||||||
 | 
					        res: Response<void>,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
        try {
 | 
					
 | 
				
			||||||
            await this.strategyService.updateStrategy(req.body, userName);
 | 
					        await this.strategyService.updateStrategy(req.body, userName);
 | 
				
			||||||
            res.status(200).end();
 | 
					        res.status(200).end();
 | 
				
			||||||
        } catch (error) {
 | 
					 | 
				
			||||||
            handleErrors(res, this.logger, error);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async deprecateStrategy(req: IAuthRequest, res: Response): Promise<void> {
 | 
					    async deprecateStrategy(
 | 
				
			||||||
 | 
					        req: IAuthRequest,
 | 
				
			||||||
 | 
					        res: Response<void>,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
        const { strategyName } = req.params;
 | 
					        const { strategyName } = req.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (strategyName === 'default') {
 | 
					        if (strategyName === 'default') {
 | 
				
			||||||
            res.status(403).end();
 | 
					            res.status(403).end();
 | 
				
			||||||
        } else {
 | 
					            return;
 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                await this.strategyService.deprecateStrategy(
 | 
					 | 
				
			||||||
                    strategyName,
 | 
					 | 
				
			||||||
                    userName,
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                res.status(200).end();
 | 
					 | 
				
			||||||
            } catch (error) {
 | 
					 | 
				
			||||||
                handleErrors(res, this.logger, error);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await this.strategyService.deprecateStrategy(strategyName, userName);
 | 
				
			||||||
 | 
					        res.status(200).end();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async reactivateStrategy(req: IAuthRequest, res: Response): Promise<void> {
 | 
					    async reactivateStrategy(
 | 
				
			||||||
 | 
					        req: IAuthRequest,
 | 
				
			||||||
 | 
					        res: Response<void>,
 | 
				
			||||||
 | 
					    ): Promise<void> {
 | 
				
			||||||
        const userName = extractUsername(req);
 | 
					        const userName = extractUsername(req);
 | 
				
			||||||
        const { strategyName } = req.params;
 | 
					        const { strategyName } = req.params;
 | 
				
			||||||
        try {
 | 
					
 | 
				
			||||||
            await this.strategyService.reactivateStrategy(
 | 
					        await this.strategyService.reactivateStrategy(strategyName, userName);
 | 
				
			||||||
                strategyName,
 | 
					        res.status(200).end();
 | 
				
			||||||
                userName,
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
            res.status(200).end();
 | 
					 | 
				
			||||||
        } catch (error) {
 | 
					 | 
				
			||||||
            handleErrors(res, this.logger, error);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default StrategyController;
 | 
					export default StrategyController;
 | 
				
			||||||
 | 
				
			|||||||
@ -390,7 +390,7 @@ class FeatureToggleService {
 | 
				
			|||||||
        value: string | number,
 | 
					        value: string | number,
 | 
				
			||||||
        context: IFeatureStrategyContext,
 | 
					        context: IFeatureStrategyContext,
 | 
				
			||||||
        userName: string,
 | 
					        userName: string,
 | 
				
			||||||
    ): Promise<IStrategyConfig> {
 | 
					    ): Promise<Saved<IStrategyConfig>> {
 | 
				
			||||||
        const { projectId, environment, featureName } = context;
 | 
					        const { projectId, environment, featureName } = context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const existingStrategy = await this.featureStrategiesStore.get(id);
 | 
					        const existingStrategy = await this.featureStrategiesStore.get(id);
 | 
				
			||||||
@ -466,7 +466,7 @@ class FeatureToggleService {
 | 
				
			|||||||
        project: string,
 | 
					        project: string,
 | 
				
			||||||
        featureName: string,
 | 
					        featureName: string,
 | 
				
			||||||
        environment: string = DEFAULT_ENV,
 | 
					        environment: string = DEFAULT_ENV,
 | 
				
			||||||
    ): Promise<IStrategyConfig[]> {
 | 
					    ): Promise<Saved<IStrategyConfig>[]> {
 | 
				
			||||||
        const hasEnv = await this.featureEnvironmentStore.featureHasEnvironment(
 | 
					        const hasEnv = await this.featureEnvironmentStore.featureHasEnvironment(
 | 
				
			||||||
            environment,
 | 
					            environment,
 | 
				
			||||||
            featureName,
 | 
					            featureName,
 | 
				
			||||||
@ -701,7 +701,7 @@ class FeatureToggleService {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async getStrategy(strategyId: string): Promise<IStrategyConfig> {
 | 
					    async getStrategy(strategyId: string): Promise<Saved<IStrategyConfig>> {
 | 
				
			||||||
        const strategy = await this.featureStrategiesStore.getStrategyById(
 | 
					        const strategy = await this.featureStrategiesStore.getStrategyById(
 | 
				
			||||||
            strategyId,
 | 
					            strategyId,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -188,7 +188,7 @@ export interface ITag {
 | 
				
			|||||||
    type: string;
 | 
					    type: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IParameterDefinition {
 | 
					export interface IAddonParameterDefinition {
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    displayName: string;
 | 
					    displayName: string;
 | 
				
			||||||
    type: string;
 | 
					    type: string;
 | 
				
			||||||
@ -203,7 +203,7 @@ export interface IAddonDefinition {
 | 
				
			|||||||
    displayName: string;
 | 
					    displayName: string;
 | 
				
			||||||
    documentationUrl: string;
 | 
					    documentationUrl: string;
 | 
				
			||||||
    description: string;
 | 
					    description: string;
 | 
				
			||||||
    parameters?: IParameterDefinition[];
 | 
					    parameters?: IAddonParameterDefinition[];
 | 
				
			||||||
    events?: string[];
 | 
					    events?: string[];
 | 
				
			||||||
    tagTypes?: ITagType[];
 | 
					    tagTypes?: ITagType[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ export interface IStrategy {
 | 
				
			|||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    editable: boolean;
 | 
					    editable: boolean;
 | 
				
			||||||
    description: string;
 | 
					    description: string;
 | 
				
			||||||
    parameters: object;
 | 
					    parameters: object[];
 | 
				
			||||||
    deprecated: boolean;
 | 
					    deprecated: boolean;
 | 
				
			||||||
    displayName: string;
 | 
					    displayName: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,9 +7,9 @@ import {
 | 
				
			|||||||
} from '../../helpers/test-helper';
 | 
					} from '../../helpers/test-helper';
 | 
				
			||||||
import getLogger from '../../../fixtures/no-logger';
 | 
					import getLogger from '../../../fixtures/no-logger';
 | 
				
			||||||
import { DEFAULT_ENV } from '../../../../lib/util/constants';
 | 
					import { DEFAULT_ENV } from '../../../../lib/util/constants';
 | 
				
			||||||
import { StrategySchema } from '../../../../lib/openapi/spec/strategy-schema';
 | 
					 | 
				
			||||||
import { FeatureSchema } from '../../../../lib/openapi/spec/feature-schema';
 | 
					import { FeatureSchema } from '../../../../lib/openapi/spec/feature-schema';
 | 
				
			||||||
import { VariantSchema } from '../../../../lib/openapi/spec/variant-schema';
 | 
					import { VariantSchema } from '../../../../lib/openapi/spec/variant-schema';
 | 
				
			||||||
 | 
					import { FeatureStrategySchema } from '../../../../lib/openapi/spec/feature-strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let app: IUnleashTest;
 | 
					let app: IUnleashTest;
 | 
				
			||||||
let db: ITestDb;
 | 
					let db: ITestDb;
 | 
				
			||||||
@ -26,7 +26,7 @@ beforeAll(async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const createToggle = async (
 | 
					    const createToggle = async (
 | 
				
			||||||
        toggle: Omit<FeatureSchema, 'createdAt'>,
 | 
					        toggle: Omit<FeatureSchema, 'createdAt'>,
 | 
				
			||||||
        strategy: Omit<StrategySchema, 'id'> = defaultStrategy,
 | 
					        strategy: Omit<FeatureStrategySchema, 'id'> = defaultStrategy,
 | 
				
			||||||
        projectId: string = 'default',
 | 
					        projectId: string = 'default',
 | 
				
			||||||
        username: string = 'test',
 | 
					        username: string = 'test',
 | 
				
			||||||
    ) => {
 | 
					    ) => {
 | 
				
			||||||
@ -576,7 +576,7 @@ test('tagging a feature with an already existing tag should be a noop', async ()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
test('can untag feature', async () => {
 | 
					test('can untag feature', async () => {
 | 
				
			||||||
    expect.assertions(1);
 | 
					    expect.assertions(1);
 | 
				
			||||||
    const feature1Name = faker.lorem.slug(3);
 | 
					    const feature1Name = faker.datatype.uuid();
 | 
				
			||||||
    await app.request.post('/api/admin/features').send({
 | 
					    await app.request.post('/api/admin/features').send({
 | 
				
			||||||
        name: feature1Name,
 | 
					        name: feature1Name,
 | 
				
			||||||
        type: 'killswitch',
 | 
					        type: 'killswitch',
 | 
				
			||||||
@ -584,7 +584,7 @@ test('can untag feature', async () => {
 | 
				
			|||||||
        strategies: [{ name: 'default' }],
 | 
					        strategies: [{ name: 'default' }],
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    const tag = {
 | 
					    const tag = {
 | 
				
			||||||
        value: faker.lorem.slug(1),
 | 
					        value: faker.lorem.word(),
 | 
				
			||||||
        type: 'simple',
 | 
					        type: 'simple',
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    await app.request
 | 
					    await app.request
 | 
				
			||||||
@ -607,8 +607,8 @@ test('can untag feature', async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
test('Can get features tagged by tag', async () => {
 | 
					test('Can get features tagged by tag', async () => {
 | 
				
			||||||
    expect.assertions(2);
 | 
					    expect.assertions(2);
 | 
				
			||||||
    const feature1Name = faker.helpers.slugify(faker.lorem.words(3));
 | 
					    const feature1Name = faker.datatype.uuid();
 | 
				
			||||||
    const feature2Name = faker.helpers.slugify(faker.lorem.words(3));
 | 
					    const feature2Name = faker.datatype.uuid();
 | 
				
			||||||
    await app.request.post('/api/admin/features').send({
 | 
					    await app.request.post('/api/admin/features').send({
 | 
				
			||||||
        name: feature1Name,
 | 
					        name: feature1Name,
 | 
				
			||||||
        type: 'killswitch',
 | 
					        type: 'killswitch',
 | 
				
			||||||
@ -637,8 +637,8 @@ test('Can get features tagged by tag', async () => {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
test('Can query for multiple tags using OR', async () => {
 | 
					test('Can query for multiple tags using OR', async () => {
 | 
				
			||||||
    expect.assertions(3);
 | 
					    expect.assertions(3);
 | 
				
			||||||
    const feature1Name = faker.helpers.slugify(faker.lorem.words(3));
 | 
					    const feature1Name = faker.datatype.uuid();
 | 
				
			||||||
    const feature2Name = faker.helpers.slugify(faker.lorem.words(3));
 | 
					    const feature2Name = faker.datatype.uuid();
 | 
				
			||||||
    await app.request.post('/api/admin/features').send({
 | 
					    await app.request.post('/api/admin/features').send({
 | 
				
			||||||
        name: feature1Name,
 | 
					        name: feature1Name,
 | 
				
			||||||
        type: 'killswitch',
 | 
					        type: 'killswitch',
 | 
				
			||||||
@ -678,8 +678,8 @@ test('Can query for multiple tags using OR', async () => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
test('Querying with multiple filters ANDs the filters', async () => {
 | 
					test('Querying with multiple filters ANDs the filters', async () => {
 | 
				
			||||||
    const feature1Name = `test.${faker.helpers.slugify(faker.hacker.phrase())}`;
 | 
					    const feature1Name = `test.${faker.datatype.uuid()}`;
 | 
				
			||||||
    const feature2Name = faker.helpers.slugify(faker.lorem.words());
 | 
					    const feature2Name = faker.datatype.uuid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await app.request.post('/api/admin/features').send({
 | 
					    await app.request.post('/api/admin/features').send({
 | 
				
			||||||
        name: feature1Name,
 | 
					        name: feature1Name,
 | 
				
			||||||
@ -729,7 +729,7 @@ test('Querying with multiple filters ANDs the filters', async () => {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test('Tagging a feature with a tag it already has should return 409', async () => {
 | 
					test('Tagging a feature with a tag it already has should return 409', async () => {
 | 
				
			||||||
    const feature1Name = `test.${faker.helpers.slugify(faker.lorem.words(3))}`;
 | 
					    const feature1Name = `test.${faker.datatype.uuid()}`;
 | 
				
			||||||
    await app.request.post('/api/admin/features').send({
 | 
					    await app.request.post('/api/admin/features').send({
 | 
				
			||||||
        name: feature1Name,
 | 
					        name: feature1Name,
 | 
				
			||||||
        type: 'killswitch',
 | 
					        type: 'killswitch',
 | 
				
			||||||
 | 
				
			|||||||
@ -465,7 +465,7 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "createStrategySchema": Object {
 | 
					      "createFeatureStrategySchema": Object {
 | 
				
			||||||
        "properties": Object {
 | 
					        "properties": Object {
 | 
				
			||||||
          "constraints": Object {
 | 
					          "constraints": Object {
 | 
				
			||||||
            "items": Object {
 | 
					            "items": Object {
 | 
				
			||||||
@ -612,7 +612,50 @@ Object {
 | 
				
			|||||||
          },
 | 
					          },
 | 
				
			||||||
          "strategies": Object {
 | 
					          "strategies": Object {
 | 
				
			||||||
            "items": Object {
 | 
					            "items": Object {
 | 
				
			||||||
              "$ref": "#/components/schemas/featureStrategySchema",
 | 
					              "additionalProperties": false,
 | 
				
			||||||
 | 
					              "properties": Object {
 | 
				
			||||||
 | 
					                "constraints": Object {
 | 
				
			||||||
 | 
					                  "items": Object {
 | 
				
			||||||
 | 
					                    "$ref": "#/components/schemas/constraintSchema",
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  "type": "array",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "createdAt": Object {
 | 
				
			||||||
 | 
					                  "format": "date-time",
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "environment": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "featureName": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "id": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "parameters": Object {
 | 
				
			||||||
 | 
					                  "$ref": "#/components/schemas/parametersSchema",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "projectId": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "sortOrder": Object {
 | 
				
			||||||
 | 
					                  "type": "number",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "strategyName": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "required": Array [
 | 
				
			||||||
 | 
					                "id",
 | 
				
			||||||
 | 
					                "featureName",
 | 
				
			||||||
 | 
					                "projectId",
 | 
				
			||||||
 | 
					                "environment",
 | 
				
			||||||
 | 
					                "strategyName",
 | 
				
			||||||
 | 
					                "constraints",
 | 
				
			||||||
 | 
					                "parameters",
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              "type": "object",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "type": "array",
 | 
					            "type": "array",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@ -668,7 +711,7 @@ Object {
 | 
				
			|||||||
          },
 | 
					          },
 | 
				
			||||||
          "strategies": Object {
 | 
					          "strategies": Object {
 | 
				
			||||||
            "items": Object {
 | 
					            "items": Object {
 | 
				
			||||||
              "$ref": "#/components/schemas/strategySchema",
 | 
					              "$ref": "#/components/schemas/featureStrategySchema",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "type": "array",
 | 
					            "type": "array",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@ -696,17 +739,6 @@ Object {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
            "type": "array",
 | 
					            "type": "array",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "createdAt": Object {
 | 
					 | 
				
			||||||
            "format": "date-time",
 | 
					 | 
				
			||||||
            "nullable": true,
 | 
					 | 
				
			||||||
            "type": "string",
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "environment": Object {
 | 
					 | 
				
			||||||
            "type": "string",
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "featureName": Object {
 | 
					 | 
				
			||||||
            "type": "string",
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "id": Object {
 | 
					          "id": Object {
 | 
				
			||||||
            "type": "string",
 | 
					            "type": "string",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@ -716,23 +748,13 @@ Object {
 | 
				
			|||||||
          "parameters": Object {
 | 
					          "parameters": Object {
 | 
				
			||||||
            "$ref": "#/components/schemas/parametersSchema",
 | 
					            "$ref": "#/components/schemas/parametersSchema",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "projectId": Object {
 | 
					 | 
				
			||||||
            "type": "string",
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "sortOrder": Object {
 | 
					          "sortOrder": Object {
 | 
				
			||||||
            "type": "number",
 | 
					            "type": "number",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "strategyName": Object {
 | 
					 | 
				
			||||||
            "type": "string",
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "required": Array [
 | 
					        "required": Array [
 | 
				
			||||||
 | 
					          "name",
 | 
				
			||||||
          "id",
 | 
					          "id",
 | 
				
			||||||
          "featureName",
 | 
					 | 
				
			||||||
          "strategyName",
 | 
					 | 
				
			||||||
          "constraints",
 | 
					 | 
				
			||||||
          "parameters",
 | 
					 | 
				
			||||||
          "environment",
 | 
					 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -1383,30 +1405,73 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "strategySchema": Object {
 | 
					      "strategiesSchema": Object {
 | 
				
			||||||
        "additionalProperties": false,
 | 
					        "additionalProperties": false,
 | 
				
			||||||
        "properties": Object {
 | 
					        "properties": Object {
 | 
				
			||||||
          "constraints": Object {
 | 
					          "strategies": Object {
 | 
				
			||||||
            "items": Object {
 | 
					            "items": Object {
 | 
				
			||||||
              "$ref": "#/components/schemas/constraintSchema",
 | 
					              "$ref": "#/components/schemas/strategySchema",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "type": "array",
 | 
					            "type": "array",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "id": Object {
 | 
					          "version": Object {
 | 
				
			||||||
 | 
					            "type": "integer",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required": Array [
 | 
				
			||||||
 | 
					          "version",
 | 
				
			||||||
 | 
					          "strategies",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "strategySchema": Object {
 | 
				
			||||||
 | 
					        "additionalProperties": false,
 | 
				
			||||||
 | 
					        "properties": Object {
 | 
				
			||||||
 | 
					          "deprecated": Object {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "description": Object {
 | 
				
			||||||
            "type": "string",
 | 
					            "type": "string",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          "displayName": Object {
 | 
				
			||||||
 | 
					            "nullable": true,
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "editable": Object {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          "name": Object {
 | 
					          "name": Object {
 | 
				
			||||||
            "type": "string",
 | 
					            "type": "string",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "parameters": Object {
 | 
					          "parameters": Object {
 | 
				
			||||||
            "$ref": "#/components/schemas/parametersSchema",
 | 
					            "items": Object {
 | 
				
			||||||
          },
 | 
					              "additionalProperties": false,
 | 
				
			||||||
          "sortOrder": Object {
 | 
					              "properties": Object {
 | 
				
			||||||
            "type": "number",
 | 
					                "description": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "name": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "required": Object {
 | 
				
			||||||
 | 
					                  "type": "boolean",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "type": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "type": "object",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "type": "array",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "required": Array [
 | 
					        "required": Array [
 | 
				
			||||||
          "name",
 | 
					          "name",
 | 
				
			||||||
 | 
					          "displayName",
 | 
				
			||||||
 | 
					          "description",
 | 
				
			||||||
 | 
					          "editable",
 | 
				
			||||||
 | 
					          "deprecated",
 | 
				
			||||||
 | 
					          "parameters",
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@ -1647,8 +1712,7 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "updateStrategySchema": Object {
 | 
					      "updateFeatureStrategySchema": Object {
 | 
				
			||||||
        "additionalProperties": false,
 | 
					 | 
				
			||||||
        "properties": Object {
 | 
					        "properties": Object {
 | 
				
			||||||
          "constraints": Object {
 | 
					          "constraints": Object {
 | 
				
			||||||
            "items": Object {
 | 
					            "items": Object {
 | 
				
			||||||
@ -1656,9 +1720,6 @@ Object {
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
            "type": "array",
 | 
					            "type": "array",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "id": Object {
 | 
					 | 
				
			||||||
            "type": "string",
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          "name": Object {
 | 
					          "name": Object {
 | 
				
			||||||
            "type": "string",
 | 
					            "type": "string",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
@ -1669,7 +1730,6 @@ Object {
 | 
				
			|||||||
            "type": "number",
 | 
					            "type": "number",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "required": Array [],
 | 
					 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "updateTagTypeSchema": Object {
 | 
					      "updateTagTypeSchema": Object {
 | 
				
			||||||
@ -1724,6 +1784,43 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "type": "object",
 | 
					        "type": "object",
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      "upsertStrategySchema": Object {
 | 
				
			||||||
 | 
					        "properties": Object {
 | 
				
			||||||
 | 
					          "description": Object {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "editable": Object {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "name": Object {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "parameters": Object {
 | 
				
			||||||
 | 
					            "items": Object {
 | 
				
			||||||
 | 
					              "properties": Object {
 | 
				
			||||||
 | 
					                "description": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "name": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "required": Object {
 | 
				
			||||||
 | 
					                  "type": "boolean",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "type": Object {
 | 
				
			||||||
 | 
					                  "type": "string",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "type": "object",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "type": "array",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "required": Array [
 | 
				
			||||||
 | 
					          "name",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      "userSchema": Object {
 | 
					      "userSchema": Object {
 | 
				
			||||||
        "additionalProperties": false,
 | 
					        "additionalProperties": false,
 | 
				
			||||||
        "properties": Object {
 | 
					        "properties": Object {
 | 
				
			||||||
@ -3434,7 +3531,7 @@ Object {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "/api/admin/projects/{projectId}/features/{featureName}/environments/{environment}/strategies": Object {
 | 
					    "/api/admin/projects/{projectId}/features/{featureName}/environments/{environment}/strategies": Object {
 | 
				
			||||||
      "get": Object {
 | 
					      "get": Object {
 | 
				
			||||||
        "operationId": "getStrategies",
 | 
					        "operationId": "getFeatureStrategies",
 | 
				
			||||||
        "parameters": Array [
 | 
					        "parameters": Array [
 | 
				
			||||||
          Object {
 | 
					          Object {
 | 
				
			||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
@ -3466,11 +3563,11 @@ Object {
 | 
				
			|||||||
            "content": Object {
 | 
					            "content": Object {
 | 
				
			||||||
              "application/json": Object {
 | 
					              "application/json": Object {
 | 
				
			||||||
                "schema": Object {
 | 
					                "schema": Object {
 | 
				
			||||||
                  "$ref": "#/components/schemas/strategySchema",
 | 
					                  "$ref": "#/components/schemas/featureStrategySchema",
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "description": "strategySchema",
 | 
					            "description": "featureStrategySchema",
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "tags": Array [
 | 
					        "tags": Array [
 | 
				
			||||||
@ -3478,7 +3575,7 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "post": Object {
 | 
					      "post": Object {
 | 
				
			||||||
        "operationId": "addStrategy",
 | 
					        "operationId": "addFeatureStrategy",
 | 
				
			||||||
        "parameters": Array [
 | 
					        "parameters": Array [
 | 
				
			||||||
          Object {
 | 
					          Object {
 | 
				
			||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
@ -3509,11 +3606,11 @@ Object {
 | 
				
			|||||||
          "content": Object {
 | 
					          "content": Object {
 | 
				
			||||||
            "application/json": Object {
 | 
					            "application/json": Object {
 | 
				
			||||||
              "schema": Object {
 | 
					              "schema": Object {
 | 
				
			||||||
                "$ref": "#/components/schemas/createStrategySchema",
 | 
					                "$ref": "#/components/schemas/createFeatureStrategySchema",
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "description": "createStrategySchema",
 | 
					          "description": "createFeatureStrategySchema",
 | 
				
			||||||
          "required": true,
 | 
					          "required": true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "responses": Object {
 | 
					        "responses": Object {
 | 
				
			||||||
@ -3535,7 +3632,7 @@ Object {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "/api/admin/projects/{projectId}/features/{featureName}/environments/{environment}/strategies/{strategyId}": Object {
 | 
					    "/api/admin/projects/{projectId}/features/{featureName}/environments/{environment}/strategies/{strategyId}": Object {
 | 
				
			||||||
      "delete": Object {
 | 
					      "delete": Object {
 | 
				
			||||||
        "operationId": "deleteStrategy",
 | 
					        "operationId": "deleteFeatureStrategy",
 | 
				
			||||||
        "parameters": Array [
 | 
					        "parameters": Array [
 | 
				
			||||||
          Object {
 | 
					          Object {
 | 
				
			||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
@ -3580,7 +3677,7 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "get": Object {
 | 
					      "get": Object {
 | 
				
			||||||
        "operationId": "getStrategy",
 | 
					        "operationId": "getFeatureStrategy",
 | 
				
			||||||
        "parameters": Array [
 | 
					        "parameters": Array [
 | 
				
			||||||
          Object {
 | 
					          Object {
 | 
				
			||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
@ -3632,7 +3729,7 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "patch": Object {
 | 
					      "patch": Object {
 | 
				
			||||||
        "operationId": "patchStrategy",
 | 
					        "operationId": "patchFeatureStrategy",
 | 
				
			||||||
        "parameters": Array [
 | 
					        "parameters": Array [
 | 
				
			||||||
          Object {
 | 
					          Object {
 | 
				
			||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
@ -3695,7 +3792,7 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "put": Object {
 | 
					      "put": Object {
 | 
				
			||||||
        "operationId": "updateStrategy",
 | 
					        "operationId": "updateFeatureStrategy",
 | 
				
			||||||
        "parameters": Array [
 | 
					        "parameters": Array [
 | 
				
			||||||
          Object {
 | 
					          Object {
 | 
				
			||||||
            "in": "path",
 | 
					            "in": "path",
 | 
				
			||||||
@ -3734,11 +3831,11 @@ Object {
 | 
				
			|||||||
          "content": Object {
 | 
					          "content": Object {
 | 
				
			||||||
            "application/json": Object {
 | 
					            "application/json": Object {
 | 
				
			||||||
              "schema": Object {
 | 
					              "schema": Object {
 | 
				
			||||||
                "$ref": "#/components/schemas/updateStrategySchema",
 | 
					                "$ref": "#/components/schemas/updateFeatureStrategySchema",
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "description": "updateStrategySchema",
 | 
					          "description": "updateFeatureStrategySchema",
 | 
				
			||||||
          "required": true,
 | 
					          "required": true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "responses": Object {
 | 
					        "responses": Object {
 | 
				
			||||||
@ -3999,6 +4096,179 @@ Object {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "/api/admin/strategies": Object {
 | 
				
			||||||
 | 
					      "get": Object {
 | 
				
			||||||
 | 
					        "operationId": "getAllStrategies",
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "200": Object {
 | 
				
			||||||
 | 
					            "content": Object {
 | 
				
			||||||
 | 
					              "application/json": Object {
 | 
				
			||||||
 | 
					                "schema": Object {
 | 
				
			||||||
 | 
					                  "$ref": "#/components/schemas/strategiesSchema",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "description": "strategiesSchema",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "post": Object {
 | 
				
			||||||
 | 
					        "operationId": "createStrategy",
 | 
				
			||||||
 | 
					        "requestBody": Object {
 | 
				
			||||||
 | 
					          "content": Object {
 | 
				
			||||||
 | 
					            "application/json": Object {
 | 
				
			||||||
 | 
					              "schema": Object {
 | 
				
			||||||
 | 
					                "$ref": "#/components/schemas/upsertStrategySchema",
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "description": "upsertStrategySchema",
 | 
				
			||||||
 | 
					          "required": true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "201": Object {
 | 
				
			||||||
 | 
					            "description": "emptyResponse",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/api/admin/strategies/{name}": Object {
 | 
				
			||||||
 | 
					      "delete": Object {
 | 
				
			||||||
 | 
					        "operationId": "removeStrategy",
 | 
				
			||||||
 | 
					        "parameters": Array [
 | 
				
			||||||
 | 
					          Object {
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "name": "name",
 | 
				
			||||||
 | 
					            "required": true,
 | 
				
			||||||
 | 
					            "schema": Object {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "200": Object {
 | 
				
			||||||
 | 
					            "description": "emptyResponse",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "get": Object {
 | 
				
			||||||
 | 
					        "operationId": "getStrategy",
 | 
				
			||||||
 | 
					        "parameters": Array [
 | 
				
			||||||
 | 
					          Object {
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "name": "name",
 | 
				
			||||||
 | 
					            "required": true,
 | 
				
			||||||
 | 
					            "schema": Object {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "200": Object {
 | 
				
			||||||
 | 
					            "content": Object {
 | 
				
			||||||
 | 
					              "application/json": Object {
 | 
				
			||||||
 | 
					                "schema": Object {
 | 
				
			||||||
 | 
					                  "$ref": "#/components/schemas/strategySchema",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "description": "strategySchema",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/api/admin/strategies/{strategyName}": Object {
 | 
				
			||||||
 | 
					      "put": Object {
 | 
				
			||||||
 | 
					        "operationId": "updateStrategy",
 | 
				
			||||||
 | 
					        "parameters": Array [
 | 
				
			||||||
 | 
					          Object {
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "name": "strategyName",
 | 
				
			||||||
 | 
					            "required": true,
 | 
				
			||||||
 | 
					            "schema": Object {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "requestBody": Object {
 | 
				
			||||||
 | 
					          "content": Object {
 | 
				
			||||||
 | 
					            "application/json": Object {
 | 
				
			||||||
 | 
					              "schema": Object {
 | 
				
			||||||
 | 
					                "$ref": "#/components/schemas/upsertStrategySchema",
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "description": "upsertStrategySchema",
 | 
				
			||||||
 | 
					          "required": true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "200": Object {
 | 
				
			||||||
 | 
					            "description": "emptyResponse",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/api/admin/strategies/{strategyName}/deprecate": Object {
 | 
				
			||||||
 | 
					      "post": Object {
 | 
				
			||||||
 | 
					        "operationId": "deprecateStrategy",
 | 
				
			||||||
 | 
					        "parameters": Array [
 | 
				
			||||||
 | 
					          Object {
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "name": "strategyName",
 | 
				
			||||||
 | 
					            "required": true,
 | 
				
			||||||
 | 
					            "schema": Object {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "200": Object {
 | 
				
			||||||
 | 
					            "description": "emptyResponse",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "/api/admin/strategies/{strategyName}/reactivate": Object {
 | 
				
			||||||
 | 
					      "post": Object {
 | 
				
			||||||
 | 
					        "operationId": "reactivateStrategy",
 | 
				
			||||||
 | 
					        "parameters": Array [
 | 
				
			||||||
 | 
					          Object {
 | 
				
			||||||
 | 
					            "in": "path",
 | 
				
			||||||
 | 
					            "name": "strategyName",
 | 
				
			||||||
 | 
					            "required": true,
 | 
				
			||||||
 | 
					            "schema": Object {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        "responses": Object {
 | 
				
			||||||
 | 
					          "200": Object {
 | 
				
			||||||
 | 
					            "description": "emptyResponse",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "tags": Array [
 | 
				
			||||||
 | 
					          "admin",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "/api/admin/tag-types": Object {
 | 
					    "/api/admin/tag-types": Object {
 | 
				
			||||||
      "get": Object {
 | 
					      "get": Object {
 | 
				
			||||||
        "operationId": "getTagTypes",
 | 
					        "operationId": "getTagTypes",
 | 
				
			||||||
 | 
				
			|||||||
@ -43,7 +43,7 @@ test('Apps registered should be announced', async () => {
 | 
				
			|||||||
        color: faker.internet.color(),
 | 
					        color: faker.internet.color(),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const differentClient = {
 | 
					    const differentClient = {
 | 
				
			||||||
        appName: faker.lorem.slug(2),
 | 
					        appName: faker.datatype.uuid(),
 | 
				
			||||||
        instanceId: faker.datatype.uuid(),
 | 
					        instanceId: faker.datatype.uuid(),
 | 
				
			||||||
        strategies: ['default'],
 | 
					        strategies: ['default'],
 | 
				
			||||||
        started: Date.now(),
 | 
					        started: Date.now(),
 | 
				
			||||||
 | 
				
			|||||||
@ -2,8 +2,8 @@ import FeatureToggleService from '../../../lib/services/feature-toggle-service';
 | 
				
			|||||||
import { createTestConfig } from '../../config/test-config';
 | 
					import { createTestConfig } from '../../config/test-config';
 | 
				
			||||||
import dbInit from '../helpers/database-init';
 | 
					import dbInit from '../helpers/database-init';
 | 
				
			||||||
import { DEFAULT_ENV } from '../../../lib/util/constants';
 | 
					import { DEFAULT_ENV } from '../../../lib/util/constants';
 | 
				
			||||||
import { StrategySchema } from '../../../lib/openapi/spec/strategy-schema';
 | 
					 | 
				
			||||||
import { SegmentService } from '../../../lib/services/segment-service';
 | 
					import { SegmentService } from '../../../lib/services/segment-service';
 | 
				
			||||||
 | 
					import { FeatureStrategySchema } from '../../../lib/openapi/spec/feature-strategy-schema';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let stores;
 | 
					let stores;
 | 
				
			||||||
let db;
 | 
					let db;
 | 
				
			||||||
@ -30,7 +30,7 @@ afterAll(async () => {
 | 
				
			|||||||
test('Should create feature toggle strategy configuration', async () => {
 | 
					test('Should create feature toggle strategy configuration', async () => {
 | 
				
			||||||
    const projectId = 'default';
 | 
					    const projectId = 'default';
 | 
				
			||||||
    const username = 'feature-toggle';
 | 
					    const username = 'feature-toggle';
 | 
				
			||||||
    const config: Omit<StrategySchema, 'id'> = {
 | 
					    const config: Omit<FeatureStrategySchema, 'id'> = {
 | 
				
			||||||
        name: 'default',
 | 
					        name: 'default',
 | 
				
			||||||
        constraints: [],
 | 
					        constraints: [],
 | 
				
			||||||
        parameters: {},
 | 
					        parameters: {},
 | 
				
			||||||
@ -58,7 +58,7 @@ test('Should be able to update existing strategy configuration', async () => {
 | 
				
			|||||||
    const projectId = 'default';
 | 
					    const projectId = 'default';
 | 
				
			||||||
    const username = 'existing-strategy';
 | 
					    const username = 'existing-strategy';
 | 
				
			||||||
    const featureName = 'update-existing-strategy';
 | 
					    const featureName = 'update-existing-strategy';
 | 
				
			||||||
    const config: Omit<StrategySchema, 'id'> = {
 | 
					    const config: Omit<FeatureStrategySchema, 'id'> = {
 | 
				
			||||||
        name: 'default',
 | 
					        name: 'default',
 | 
				
			||||||
        constraints: [],
 | 
					        constraints: [],
 | 
				
			||||||
        parameters: {},
 | 
					        parameters: {},
 | 
				
			||||||
@ -93,7 +93,7 @@ test('Should be able to get strategy by id', async () => {
 | 
				
			|||||||
    const projectId = 'default';
 | 
					    const projectId = 'default';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const userName = 'strategy';
 | 
					    const userName = 'strategy';
 | 
				
			||||||
    const config: Omit<StrategySchema, 'id'> = {
 | 
					    const config: Omit<FeatureStrategySchema, 'id'> = {
 | 
				
			||||||
        name: 'default',
 | 
					        name: 'default',
 | 
				
			||||||
        constraints: [],
 | 
					        constraints: [],
 | 
				
			||||||
        parameters: {},
 | 
					        parameters: {},
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								src/test/fixtures/fake-strategies-store.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/test/fixtures/fake-strategies-store.ts
									
									
									
									
										vendored
									
									
								
							@ -12,7 +12,7 @@ export default class FakeStrategiesStore implements IStrategyStore {
 | 
				
			|||||||
        description: 'default strategy',
 | 
					        description: 'default strategy',
 | 
				
			||||||
        displayName: 'Default',
 | 
					        displayName: 'Default',
 | 
				
			||||||
        editable: false,
 | 
					        editable: false,
 | 
				
			||||||
        parameters: {},
 | 
					        parameters: [],
 | 
				
			||||||
        deprecated: false,
 | 
					        deprecated: false,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user