diff --git a/src/lib/proxy/client-feature-toggle-read-model-type.ts b/src/lib/features/frontend-api/client-feature-toggle-read-model-type.ts similarity index 71% rename from src/lib/proxy/client-feature-toggle-read-model-type.ts rename to src/lib/features/frontend-api/client-feature-toggle-read-model-type.ts index 63a1e8e25a..93067d2480 100644 --- a/src/lib/proxy/client-feature-toggle-read-model-type.ts +++ b/src/lib/features/frontend-api/client-feature-toggle-read-model-type.ts @@ -1,4 +1,4 @@ -import { IFeatureToggleClient } from '../types'; +import { IFeatureToggleClient } from '../../types'; export interface IClientFeatureToggleReadModel { getAll(): Promise>>; diff --git a/src/lib/proxy/client-feature-toggle-read-model.ts b/src/lib/features/frontend-api/client-feature-toggle-read-model.ts similarity index 94% rename from src/lib/proxy/client-feature-toggle-read-model.ts rename to src/lib/features/frontend-api/client-feature-toggle-read-model.ts index ee91b1b9e4..fada749285 100644 --- a/src/lib/proxy/client-feature-toggle-read-model.ts +++ b/src/lib/features/frontend-api/client-feature-toggle-read-model.ts @@ -1,11 +1,15 @@ import { Knex } from 'knex'; -import { IFeatureToggleClient, IStrategyConfig, PartialDeep } from '../types'; -import { ensureStringValue, mapValues } from '../util'; -import { Db } from '../db/db'; -import FeatureToggleStore from '../features/feature-toggle/feature-toggle-store'; +import { + IFeatureToggleClient, + IStrategyConfig, + PartialDeep, +} from '../../types'; +import { ensureStringValue, mapValues } from '../../util'; +import { Db } from '../../db/db'; +import FeatureToggleStore from '../feature-toggle/feature-toggle-store'; import Raw = Knex.Raw; -import metricsHelper from '../util/metrics-helper'; -import { DB_TIME } from '../metric-events'; +import metricsHelper from '../../util/metrics-helper'; +import { DB_TIME } from '../../metric-events'; import EventEmitter from 'events'; import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type'; diff --git a/src/lib/proxy/create-context.test.ts b/src/lib/features/frontend-api/create-context.test.ts similarity index 100% rename from src/lib/proxy/create-context.test.ts rename to src/lib/features/frontend-api/create-context.test.ts diff --git a/src/lib/proxy/create-context.ts b/src/lib/features/frontend-api/create-context.ts similarity index 100% rename from src/lib/proxy/create-context.ts rename to src/lib/features/frontend-api/create-context.ts diff --git a/src/lib/proxy/createProxyService.ts b/src/lib/features/frontend-api/createFrontendApiService.ts similarity index 75% rename from src/lib/proxy/createProxyService.ts rename to src/lib/features/frontend-api/createFrontendApiService.ts index cea79f73a2..4af589a651 100644 --- a/src/lib/proxy/createProxyService.ts +++ b/src/lib/features/frontend-api/createFrontendApiService.ts @@ -1,30 +1,30 @@ -import { ProxyService } from './proxy-service'; -import { SegmentReadModel } from '../features/segment/segment-read-model'; -import ClientMetricsServiceV2 from '../features/metrics/client-metrics/metrics-service-v2'; -import SettingService from '../services/setting-service'; -import SettingStore from '../db/setting-store'; +import { FrontendApiService } from './frontend-api-service'; +import { SegmentReadModel } from '../segment/segment-read-model'; +import ClientMetricsServiceV2 from '../metrics/client-metrics/metrics-service-v2'; +import SettingService from '../../services/setting-service'; +import SettingStore from '../../db/setting-store'; import { createEventsService, createFakeEventsService, createFakeFeatureToggleService, createFeatureToggleService, -} from '../features'; -import ConfigurationRevisionService from '../features/feature-toggle/configuration-revision-service'; +} from '../index'; +import ConfigurationRevisionService from '../feature-toggle/configuration-revision-service'; import { GlobalFrontendApiCache } from './global-frontend-api-cache'; import ClientFeatureToggleReadModel from './client-feature-toggle-read-model'; -import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model'; -import FakeSettingStore from '../../test/fixtures/fake-setting-store'; +import { FakeSegmentReadModel } from '../segment/fake-segment-read-model'; +import FakeSettingStore from '../../../test/fixtures/fake-setting-store'; import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model'; -import { IUnleashConfig } from '../types'; -import { Db } from '../db/db'; +import { IUnleashConfig } from '../../types'; +import { Db } from '../../db/db'; -export const createProxyService = ( +export const createFrontendApiService = ( db: Db, config: IUnleashConfig, // client metrics service needs to be shared because it uses in-memory cache clientMetricsServiceV2: ClientMetricsServiceV2, configurationRevisionService: ConfigurationRevisionService, -): ProxyService => { +): FrontendApiService => { const segmentReadModel = new SegmentReadModel(db); const settingStore = new SettingStore(db, config.getLogger); const eventService = createEventsService(db, config); @@ -45,7 +45,7 @@ export const createProxyService = ( clientFeatureToggleReadModel, configurationRevisionService, ); - return new ProxyService( + return new FrontendApiService( config, { segmentReadModel }, { @@ -58,11 +58,11 @@ export const createProxyService = ( ); }; -export const createFakeProxyService = ( +export const createFakeFrontendApiService = ( config: IUnleashConfig, clientMetricsServiceV2: ClientMetricsServiceV2, configurationRevisionService: ConfigurationRevisionService, -): ProxyService => { +): FrontendApiService => { const segmentReadModel = new FakeSegmentReadModel(); const settingStore = new FakeSettingStore(); const eventService = createFakeEventsService(config); @@ -80,7 +80,7 @@ export const createFakeProxyService = ( clientFeatureToggleReadModel, configurationRevisionService, ); - return new ProxyService( + return new FrontendApiService( config, { segmentReadModel }, { diff --git a/src/lib/proxy/fake-client-feature-toggle-read-model.ts b/src/lib/features/frontend-api/fake-client-feature-toggle-read-model.ts similarity index 91% rename from src/lib/proxy/fake-client-feature-toggle-read-model.ts rename to src/lib/features/frontend-api/fake-client-feature-toggle-read-model.ts index 58337c9e88..889046d162 100644 --- a/src/lib/proxy/fake-client-feature-toggle-read-model.ts +++ b/src/lib/features/frontend-api/fake-client-feature-toggle-read-model.ts @@ -1,4 +1,4 @@ -import { IFeatureToggleClient } from '../types'; +import { IFeatureToggleClient } from '../../types'; import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type'; export default class FakeClientFeatureToggleReadModel diff --git a/src/lib/proxy/proxy-controller.ts b/src/lib/features/frontend-api/frontend-api-controller.ts similarity index 86% rename from src/lib/proxy/proxy-controller.ts rename to src/lib/features/frontend-api/frontend-api-controller.ts index 4f26fc9feb..86d8b834e8 100644 --- a/src/lib/proxy/proxy-controller.ts +++ b/src/lib/features/frontend-api/frontend-api-controller.ts @@ -1,8 +1,8 @@ import { Request, Response } from 'express'; -import Controller from '../routes/controller'; -import { IUnleashConfig, IUnleashServices, NONE } from '../types'; -import { Logger } from '../logger'; -import { IApiUser } from '../types/api-user'; +import Controller from '../../routes/controller'; +import { IUnleashConfig, IUnleashServices, NONE } from '../../types'; +import { Logger } from '../../logger'; +import { IApiUser } from '../../types/api-user'; import { ClientMetricsSchema, createRequestSchema, @@ -13,12 +13,12 @@ import { ProxyFeatureSchema, proxyFeaturesSchema, ProxyFeaturesSchema, -} from '../openapi'; +} from '../../openapi'; import { Context } from 'unleash-client'; import { enrichContextWithIp } from './index'; -import { corsOriginMiddleware } from '../middleware'; -import NotImplementedError from '../error/not-implemented-error'; -import NotFoundError from '../error/notfound-error'; +import { corsOriginMiddleware } from '../../middleware'; +import NotImplementedError from '../../error/not-implemented-error'; +import NotFoundError from '../../error/notfound-error'; import rateLimit from 'express-rate-limit'; import { minutesToMilliseconds } from 'date-fns'; import isEqual from 'lodash.isequal'; @@ -34,7 +34,7 @@ interface ApiUserRequest< type Services = Pick< IUnleashServices, - 'settingService' | 'proxyService' | 'openApiService' + 'settingService' | 'frontendApiService' | 'openApiService' >; export default class FrontendAPIController extends Controller { @@ -44,7 +44,7 @@ export default class FrontendAPIController extends Controller { constructor(config: IUnleashConfig, services: Services) { super(config); - this.logger = config.getLogger('proxy-api/index.ts'); + this.logger = config.getLogger('frontend-api-controller.ts'); this.services = services; // Support CORS requests for the frontend endpoints. @@ -54,7 +54,7 @@ export default class FrontendAPIController extends Controller { this.route({ method: 'get', path: '', - handler: this.getProxyFeatures, + handler: this.getFrontendApiFeatures, permission: NONE, middleware: [ this.services.openApiService.validPath({ @@ -89,7 +89,7 @@ export default class FrontendAPIController extends Controller { this.route({ method: 'post', path: '/client/metrics', - handler: this.registerProxyMetrics, + handler: this.registerFrontendApiMetrics, permission: NONE, middleware: [ this.services.openApiService.validPath({ @@ -117,7 +117,7 @@ export default class FrontendAPIController extends Controller { this.route({ method: 'post', path: '/client/register', - handler: this.registerProxyClient, + handler: this.registerFrontendApiClient, permission: NONE, middleware: [ this.services.openApiService.validPath({ @@ -168,7 +168,7 @@ export default class FrontendAPIController extends Controller { res.status(error.statusCode).json(error); } - private async getProxyFeatures( + private async getFrontendApiFeatures( req: ApiUserRequest, res: Response, ) { @@ -179,11 +179,11 @@ export default class FrontendAPIController extends Controller { let newToggles: ProxyFeatureSchema[] = []; if (this.config.flagResolver.isEnabled('globalFrontendApiCache')) { [toggles, newToggles] = await Promise.all([ - this.services.proxyService.getProxyFeatures( + this.services.frontendApiService.getFrontendApiFeatures( req.user, FrontendAPIController.createContext(req), ), - this.services.proxyService.getNewProxyFeatures( + this.services.frontendApiService.getNewFrontendApiFeatures( req.user, FrontendAPIController.createContext(req), ), @@ -199,10 +199,11 @@ export default class FrontendAPIController extends Controller { ); } } else { - toggles = await this.services.proxyService.getProxyFeatures( - req.user, - FrontendAPIController.createContext(req), - ); + toggles = + await this.services.frontendApiService.getFrontendApiFeatures( + req.user, + FrontendAPIController.createContext(req), + ); } const returnedToggles = this.config.flagResolver.isEnabled( @@ -221,7 +222,7 @@ export default class FrontendAPIController extends Controller { ); } - private async registerProxyMetrics( + private async registerFrontendApiMetrics( req: ApiUserRequest, res: Response, ) { @@ -234,7 +235,7 @@ export default class FrontendAPIController extends Controller { return; } - await this.services.proxyService.registerProxyMetrics( + await this.services.frontendApiService.registerFrontendApiMetrics( req.user, req.body, req.ip, @@ -242,7 +243,7 @@ export default class FrontendAPIController extends Controller { res.sendStatus(200); } - private async registerProxyClient( + private async registerFrontendApiClient( req: ApiUserRequest, res: Response, ) { diff --git a/src/lib/proxy/frontend-api-repository.ts b/src/lib/features/frontend-api/frontend-api-repository.ts similarity index 93% rename from src/lib/proxy/frontend-api-repository.ts rename to src/lib/features/frontend-api/frontend-api-repository.ts index 41591bd313..50606a9e3f 100644 --- a/src/lib/proxy/frontend-api-repository.ts +++ b/src/lib/features/frontend-api/frontend-api-repository.ts @@ -5,10 +5,10 @@ import { EnhancedFeatureInterface, FeatureInterface, } from 'unleash-client/lib/feature'; -import { IApiUser } from '../types/api-user'; -import { IUnleashConfig } from '../types'; +import { IApiUser } from '../../types/api-user'; +import { IUnleashConfig } from '../../types'; import { UnleashEvents } from 'unleash-client'; -import { Logger } from '../logger'; +import { Logger } from '../../logger'; import { GlobalFrontendApiCache } from './global-frontend-api-cache'; type Config = Pick; diff --git a/src/lib/proxy/proxy-service.ts b/src/lib/features/frontend-api/frontend-api-service.ts similarity index 75% rename from src/lib/proxy/proxy-service.ts rename to src/lib/features/frontend-api/frontend-api-service.ts index 7cfe814c62..ac43d09057 100644 --- a/src/lib/proxy/proxy-service.ts +++ b/src/lib/features/frontend-api/frontend-api-service.ts @@ -1,25 +1,24 @@ -import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../types'; -import { Logger } from '../logger'; -import { ClientMetricsSchema, ProxyFeatureSchema } from '../openapi'; -import ApiUser, { IApiUser } from '../types/api-user'; +import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../../types'; +import { Logger } from '../../logger'; +import { ClientMetricsSchema, ProxyFeatureSchema } from '../../openapi'; +import ApiUser, { IApiUser } from '../../types/api-user'; import { Context, InMemStorageProvider, Unleash, UnleashEvents, } from 'unleash-client'; -import { ApiTokenType } from '../types/models/api-token'; +import { ApiTokenType } from '../../types/models/api-token'; import { FrontendSettings, frontendSettingsKey, -} from '../types/settings/frontend-settings'; -import { validateOrigins } from '../util'; -import { BadDataError, InvalidTokenError } from '../error'; -import { PROXY_REPOSITORY_CREATED } from '../metric-events'; -import { ProxyRepository } from './index'; +} from '../../types/settings/frontend-settings'; +import { validateOrigins } from '../../util'; +import { BadDataError, InvalidTokenError } from '../../error'; +import { PROXY_REPOSITORY_CREATED } from '../../metric-events'; import { FrontendApiRepository } from './frontend-api-repository'; import { GlobalFrontendApiCache } from './global-frontend-api-cache'; -import isEqual from 'lodash.isequal'; +import { ProxyRepository } from './proxy-repository'; export type Config = Pick< IUnleashConfig, @@ -36,7 +35,7 @@ export type Services = Pick< | 'configurationRevisionService' >; -export class ProxyService { +export class FrontendApiService { private readonly config: Config; private readonly logger: Logger; @@ -50,7 +49,7 @@ export class ProxyService { /** * This is intentionally a Promise because we want to be able to await * until the client (which might be being created by a different request) is ready - * Check this test that fails if we don't use a Promise: src/test/e2e/api/proxy/proxy.concurrency.e2e.test.ts + * Check this test that fails if we don't use a Promise: frontend-api.concurrency.e2e.test.ts */ private readonly clients: Map> = new Map(); @@ -66,17 +65,17 @@ export class ProxyService { globalFrontendApiCache: GlobalFrontendApiCache, ) { this.config = config; - this.logger = config.getLogger('services/proxy-service.ts'); + this.logger = config.getLogger('services/frontend-api-service.ts'); this.stores = stores; this.services = services; this.globalFrontendApiCache = globalFrontendApiCache; } - async getProxyFeatures( + async getFrontendApiFeatures( token: IApiUser, context: Context, ): Promise { - const client = await this.clientForProxyToken(token); + const client = await this.clientForFrontendApiToken(token); const definitions = client.getFeatureToggleDefinitions() || []; const sessionId = context.sessionId || String(Math.random()); @@ -98,30 +97,11 @@ export class ProxyService { })); } - async compareToggleDefinitions(token: IApiUser) { - const oldClient = await this.clientForProxyToken(token); - const oldDefinitions = oldClient.getFeatureToggleDefinitions() || []; - - const newClient = await this.newClientForProxyToken(token); - const newDefinitions = newClient.getFeatureToggleDefinitions() || []; - - if ( - !isEqual( - oldDefinitions.sort((a, b) => a.name.localeCompare(b.name)), - newDefinitions.sort((a, b) => a.name.localeCompare(b.name)), - ) - ) { - this.logger.warn( - `old features definitions and new features definitions are different. Old definitions count ${oldDefinitions.length}, new count ${newDefinitions.length}`, - ); - } - } - - async getNewProxyFeatures( + async getNewFrontendApiFeatures( token: IApiUser, context: Context, ): Promise { - const client = await this.newClientForProxyToken(token); + const client = await this.newClientForFrontendApiToken(token); const definitions = client.getFeatureToggleDefinitions() || []; const sessionId = context.sessionId || String(Math.random()); @@ -144,12 +124,12 @@ export class ProxyService { })); } - async registerProxyMetrics( + async registerFrontendApiMetrics( token: IApiUser, metrics: ClientMetricsSchema, ip: string, ): Promise { - ProxyService.assertExpectedTokenType(token); + FrontendApiService.assertExpectedTokenType(token); const environment = this.services.clientMetricsServiceV2.resolveMetricsEnvironment( @@ -166,12 +146,12 @@ export class ProxyService { ); } - private async clientForProxyToken(token: IApiUser): Promise { - ProxyService.assertExpectedTokenType(token); + private async clientForFrontendApiToken(token: IApiUser): Promise { + FrontendApiService.assertExpectedTokenType(token); let client = this.clients.get(token.secret); if (!client) { - client = this.createClientForProxyToken(token); + client = this.createClientForFrontendApiToken(token); this.clients.set(token.secret, client); this.config.eventBus.emit(PROXY_REPOSITORY_CREATED); } @@ -179,12 +159,14 @@ export class ProxyService { return client; } - private async newClientForProxyToken(token: IApiUser): Promise { - ProxyService.assertExpectedTokenType(token); + private async newClientForFrontendApiToken( + token: IApiUser, + ): Promise { + FrontendApiService.assertExpectedTokenType(token); let newClient = this.newClients.get(token.secret); if (!newClient) { - newClient = this.createNewClientForProxyToken(token); + newClient = this.createNewClientForFrontendApiToken(token); this.newClients.set(token.secret, newClient); // TODO: do we need this twice? // this.config.eventBus.emit(PROXY_REPOSITORY_CREATED); @@ -193,7 +175,9 @@ export class ProxyService { return newClient; } - private async createClientForProxyToken(token: IApiUser): Promise { + private async createClientForFrontendApiToken( + token: IApiUser, + ): Promise { const repository = new ProxyRepository( this.config, this.stores, @@ -219,7 +203,7 @@ export class ProxyService { return client; } - private async createNewClientForProxyToken( + private async createNewClientForFrontendApiToken( token: IApiUser, ): Promise { const repository = new FrontendApiRepository( @@ -228,7 +212,7 @@ export class ProxyService { token, ); const client = new Unleash({ - appName: 'proxy', + appName: 'frontend-api', url: 'unused', storageProvider: new InMemStorageProvider(), disableMetrics: true, @@ -246,7 +230,7 @@ export class ProxyService { return client; } - async deleteClientForProxyToken(secret: string): Promise { + async deleteClientForFrontendApiToken(secret: string): Promise { const clientPromise = this.clients.get(secret); if (clientPromise) { const client = await clientPromise; diff --git a/src/test/e2e/api/proxy/proxy.concurrency.e2e.test.ts b/src/lib/features/frontend-api/frontend-api.concurrency.e2e.test.ts similarity index 80% rename from src/test/e2e/api/proxy/proxy.concurrency.e2e.test.ts rename to src/lib/features/frontend-api/frontend-api.concurrency.e2e.test.ts index 68c0dc214f..f053f6ce36 100644 --- a/src/test/e2e/api/proxy/proxy.concurrency.e2e.test.ts +++ b/src/lib/features/frontend-api/frontend-api.concurrency.e2e.test.ts @@ -1,8 +1,11 @@ -import { IUnleashTest, setupAppWithAuth } from '../../helpers/test-helper'; -import dbInit, { ITestDb } from '../../helpers/database-init'; -import getLogger from '../../../fixtures/no-logger'; -import { randomId } from '../../../../lib/util'; -import { ApiTokenType } from '../../../../lib/types/models/api-token'; +import { + IUnleashTest, + setupAppWithAuth, +} from '../../../test/e2e/helpers/test-helper'; +import dbInit, { ITestDb } from '../../../test/e2e/helpers/database-init'; +import getLogger from '../../../test/fixtures/no-logger'; +import { randomId } from '../../util'; +import { ApiTokenType } from '../../types/models/api-token'; let app: IUnleashTest; let db: ITestDb; @@ -25,7 +28,7 @@ beforeAll(async () => { }); afterEach(() => { - app.services.proxyService.stopAll(); + app.services.frontendApiService.stopAll(); jest.clearAllMocks(); }); diff --git a/src/test/e2e/api/proxy/proxy.e2e.test.ts b/src/lib/features/frontend-api/frontend-api.e2e.test.ts similarity index 98% rename from src/test/e2e/api/proxy/proxy.e2e.test.ts rename to src/lib/features/frontend-api/frontend-api.e2e.test.ts index 9af9f759a6..7696b3fb2b 100644 --- a/src/test/e2e/api/proxy/proxy.e2e.test.ts +++ b/src/lib/features/frontend-api/frontend-api.e2e.test.ts @@ -1,21 +1,24 @@ -import { IUnleashTest, setupAppWithAuth } from '../../helpers/test-helper'; -import dbInit, { ITestDb } from '../../helpers/database-init'; -import getLogger from '../../../fixtures/no-logger'; -import { randomId } from '../../../../lib/util'; +import { + IUnleashTest, + setupAppWithAuth, +} from '../../../test/e2e/helpers/test-helper'; +import dbInit, { ITestDb } from '../../../test/e2e/helpers/database-init'; +import getLogger from '../../../test/fixtures/no-logger'; +import { randomId } from '../../util'; import { ApiTokenType, IApiToken, IApiTokenCreate, -} from '../../../../lib/types/models/api-token'; +} from '../../types/models/api-token'; import { startOfHour } from 'date-fns'; import { FEATURE_UPDATED, IConstraint, IStrategyConfig, SYSTEM_USER, -} from '../../../../lib/types'; -import { ProxyRepository } from '../../../../lib/proxy'; -import { Logger } from '../../../../lib/logger'; +} from '../../types'; +import { ProxyRepository } from './index'; +import { Logger } from '../../logger'; let app: IUnleashTest; let db: ITestDb; @@ -32,7 +35,7 @@ beforeAll(async () => { }); afterEach(() => { - app.services.proxyService.stopAll(); + app.services.frontendApiService.stopAll(); jest.clearAllMocks(); }); diff --git a/src/lib/proxy/global-frontend-api-cache.test.ts b/src/lib/features/frontend-api/global-frontend-api-cache.test.ts similarity index 95% rename from src/lib/proxy/global-frontend-api-cache.test.ts rename to src/lib/features/frontend-api/global-frontend-api-cache.test.ts index 3b662d9d6e..d1b9476179 100644 --- a/src/lib/proxy/global-frontend-api-cache.test.ts +++ b/src/lib/features/frontend-api/global-frontend-api-cache.test.ts @@ -2,8 +2,8 @@ import { GlobalFrontendApiCache, GlobalFrontendApiCacheState, } from './global-frontend-api-cache'; -import noLogger from '../../test/fixtures/no-logger'; -import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model'; +import noLogger from '../../../test/fixtures/no-logger'; +import { FakeSegmentReadModel } from '../segment/fake-segment-read-model'; import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model'; import EventEmitter from 'events'; import { @@ -11,8 +11,8 @@ import { IFeatureToggleClient, IFlagResolver, ISegment, -} from '../types'; -import { UPDATE_REVISION } from '../features/feature-toggle/configuration-revision-service'; +} from '../../types'; +import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service'; const state = async ( cache: GlobalFrontendApiCache, diff --git a/src/lib/proxy/global-frontend-api-cache.ts b/src/lib/features/frontend-api/global-frontend-api-cache.ts similarity index 94% rename from src/lib/proxy/global-frontend-api-cache.ts rename to src/lib/features/frontend-api/global-frontend-api-cache.ts index 3a3e937cf6..6551edc107 100644 --- a/src/lib/proxy/global-frontend-api-cache.ts +++ b/src/lib/features/frontend-api/global-frontend-api-cache.ts @@ -1,19 +1,19 @@ import EventEmitter from 'events'; import { Segment } from 'unleash-client/lib/strategy/strategy'; import { FeatureInterface } from 'unleash-client/lib/feature'; -import { IApiUser } from '../types/api-user'; +import { IApiUser } from '../../types/api-user'; import { IFeatureToggleClient, ISegmentReadModel, IUnleashConfig, -} from '../types'; +} from '../../types'; import { mapFeatureForClient, mapSegmentsForClient, -} from '../features/playground/offline-unleash-client'; -import { ALL_ENVS } from '../util/constants'; -import { Logger } from '../logger'; -import { UPDATE_REVISION } from '../features/feature-toggle/configuration-revision-service'; +} from '../playground/offline-unleash-client'; +import { ALL_ENVS } from '../../util/constants'; +import { Logger } from '../../logger'; +import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service'; import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type'; type Config = Pick; diff --git a/src/lib/proxy/index.ts b/src/lib/features/frontend-api/index.ts similarity index 100% rename from src/lib/proxy/index.ts rename to src/lib/features/frontend-api/index.ts diff --git a/src/lib/proxy/proxy-repository.ts b/src/lib/features/frontend-api/proxy-repository.ts similarity index 92% rename from src/lib/proxy/proxy-repository.ts rename to src/lib/features/frontend-api/proxy-repository.ts index c025b75a4c..69e0bda123 100644 --- a/src/lib/proxy/proxy-repository.ts +++ b/src/lib/features/frontend-api/proxy-repository.ts @@ -5,19 +5,19 @@ import { EnhancedFeatureInterface, FeatureInterface, } from 'unleash-client/lib/feature'; -import { IApiUser } from '../types/api-user'; -import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../types'; +import { IApiUser } from '../../types/api-user'; +import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../../types'; import { mapFeaturesForClient, mapSegmentsForClient, -} from '../features/playground/offline-unleash-client'; -import { ALL_ENVS } from '../util/constants'; +} from '../playground/offline-unleash-client'; +import { ALL_ENVS } from '../../util/constants'; import { UnleashEvents } from 'unleash-client'; -import { Logger } from '../logger'; +import { Logger } from '../../logger'; import ConfigurationRevisionService, { UPDATE_REVISION, -} from '../features/feature-toggle/configuration-revision-service'; -import { PROXY_FEATURES_FOR_TOKEN_TIME } from '../metric-events'; +} from '../feature-toggle/configuration-revision-service'; +import { PROXY_FEATURES_FOR_TOKEN_TIME } from '../../metric-events'; type Config = Pick; @@ -28,6 +28,7 @@ type Services = Pick< 'featureToggleServiceV2' | 'configurationRevisionService' >; +// TODO: remove after finished migration to global frontend api cache export class ProxyRepository extends EventEmitter implements RepositoryInterface diff --git a/src/lib/proxy/proxy-service.test.ts b/src/lib/features/frontend-api/proxy-service.test.ts similarity index 79% rename from src/lib/proxy/proxy-service.test.ts rename to src/lib/features/frontend-api/proxy-service.test.ts index adde792851..fd068ecc6e 100644 --- a/src/lib/proxy/proxy-service.test.ts +++ b/src/lib/features/frontend-api/proxy-service.test.ts @@ -1,11 +1,11 @@ -import { ProxyService, Config } from './proxy-service'; +import { FrontendApiService, Config } from './frontend-api-service'; import { GlobalFrontendApiCache } from './global-frontend-api-cache'; -import { IApiUser } from '../types'; +import { IApiUser } from '../../types'; import { FeatureInterface } from 'unleash-client/lib/feature'; -import noLogger from '../../test/fixtures/no-logger'; -import { ApiTokenType } from '../types/models/api-token'; +import noLogger from '../../../test/fixtures/no-logger'; +import { ApiTokenType } from '../../types/models/api-token'; -test('proxy service fetching features from global cache', async () => { +test('frontend api service fetching features from global cache', async () => { const irrelevant = {} as any; const globalFrontendApiCache = { getToggles(_: IApiUser): FeatureInterface[] { @@ -38,14 +38,14 @@ test('proxy service fetching features from global cache', async () => { ) as FeatureInterface; }, } as GlobalFrontendApiCache; - const proxyService = new ProxyService( + const frontendApiService = new FrontendApiService( { getLogger: noLogger } as unknown as Config, irrelevant, irrelevant, globalFrontendApiCache, ); - const features = await proxyService.getNewProxyFeatures( + const features = await frontendApiService.getNewFrontendApiFeatures( { projects: ['irrelevant'], environment: 'irrelevant', diff --git a/src/lib/features/scheduler/schedule-services.ts b/src/lib/features/scheduler/schedule-services.ts index 9d163ab135..8c337cb09f 100644 --- a/src/lib/features/scheduler/schedule-services.ts +++ b/src/lib/features/scheduler/schedule-services.ts @@ -28,7 +28,7 @@ export const scheduleServices = async ( eventService, versionService, lastSeenService, - proxyService, + frontendApiService, clientMetricsServiceV2, } = services; @@ -126,7 +126,7 @@ export const scheduleServices = async ( ); schedulerService.schedule( - proxyService.fetchFrontendSettings.bind(proxyService), + frontendApiService.fetchFrontendSettings.bind(frontendApiService), minutesToMilliseconds(2), 'fetchFrontendSettings', 0, diff --git a/src/lib/internals.ts b/src/lib/internals.ts index 369c8529f6..f56ffc548b 100644 --- a/src/lib/internals.ts +++ b/src/lib/internals.ts @@ -6,7 +6,7 @@ export * from './addons'; export * from './db'; export * from './middleware'; export * from './openapi'; -export * from './proxy'; +export * from './features/frontend-api'; export * from './routes'; export * from './services'; export * from './types'; diff --git a/src/lib/middleware/cors-origin-middleware.test.ts b/src/lib/middleware/cors-origin-middleware.test.ts index f5c6c73532..28d4dcf829 100644 --- a/src/lib/middleware/cors-origin-middleware.test.ts +++ b/src/lib/middleware/cors-origin-middleware.test.ts @@ -4,7 +4,11 @@ import { createTestConfig } from '../../test/config/test-config'; import FakeEventStore from '../../test/fixtures/fake-event-store'; import { randomId } from '../util/random-id'; import FakeProjectStore from '../../test/fixtures/fake-project-store'; -import { EventService, ProxyService, SettingService } from '../../lib/services'; +import { + EventService, + FrontendApiService, + SettingService, +} from '../../lib/services'; import { ISettingStore } from '../../lib/types'; import { frontendSettingsKey } from '../../lib/types/settings/frontend-settings'; import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store'; @@ -12,7 +16,7 @@ import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store'; const TEST_USER_ID = -9999; const createSettingService = ( frontendApiOrigins: string[], -): { proxyService: ProxyService; settingStore: ISettingStore } => { +): { frontendApiService: FrontendApiService; settingStore: ISettingStore } => { const config = createTestConfig({ frontendApiOrigins }); const stores = { @@ -30,7 +34,7 @@ const createSettingService = ( return { //@ts-ignore - proxyService: new ProxyService(config, stores, services), + frontendApiService: new FrontendApiService(config, stores, services), settingStore: stores.settingStore, }; }; @@ -47,10 +51,10 @@ test('resolveOrigin', () => { }); test('corsOriginMiddleware origin validation', async () => { - const { proxyService } = createSettingService([]); + const { frontendApiService } = createSettingService([]); const userName = randomId(); await expect(() => - proxyService.setFrontendSettings( + frontendApiService.setFrontendSettings( { frontendApiOrigins: ['a'] }, userName, TEST_USER_ID, @@ -59,84 +63,84 @@ test('corsOriginMiddleware origin validation', async () => { }); test('corsOriginMiddleware without config', async () => { - const { proxyService, settingStore } = createSettingService([]); + const { frontendApiService, settingStore } = createSettingService([]); const userName = randomId(); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: [], }); - await proxyService.setFrontendSettings( + await frontendApiService.setFrontendSettings( { frontendApiOrigins: [] }, userName, TEST_USER_ID, ); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: [], }); - await proxyService.setFrontendSettings( + await frontendApiService.setFrontendSettings( { frontendApiOrigins: ['*'] }, userName, TEST_USER_ID, ); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: ['*'], }); await settingStore.delete(frontendSettingsKey); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: [], }); }); test('corsOriginMiddleware with config', async () => { - const { proxyService, settingStore } = createSettingService(['*']); + const { frontendApiService, settingStore } = createSettingService(['*']); const userName = randomId(); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: ['*'], }); - await proxyService.setFrontendSettings( + await frontendApiService.setFrontendSettings( { frontendApiOrigins: [] }, userName, TEST_USER_ID, ); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: [], }); - await proxyService.setFrontendSettings( + await frontendApiService.setFrontendSettings( { frontendApiOrigins: ['https://example.com', 'https://example.org'] }, userName, TEST_USER_ID, ); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: ['https://example.com', 'https://example.org'], }); await settingStore.delete(frontendSettingsKey); - expect(await proxyService.getFrontendSettings(false)).toEqual({ + expect(await frontendApiService.getFrontendSettings(false)).toEqual({ frontendApiOrigins: ['*'], }); }); test('corsOriginMiddleware with caching enabled', async () => { - const { proxyService } = createSettingService([]); + const { frontendApiService } = createSettingService([]); const userName = randomId(); - expect(await proxyService.getFrontendSettings()).toEqual({ + expect(await frontendApiService.getFrontendSettings()).toEqual({ frontendApiOrigins: [], }); //setting - await proxyService.setFrontendSettings( + await frontendApiService.setFrontendSettings( { frontendApiOrigins: ['*'] }, userName, TEST_USER_ID, ); //still get cached value - expect(await proxyService.getFrontendSettings()).toEqual({ + expect(await frontendApiService.getFrontendSettings()).toEqual({ frontendApiOrigins: [], }); - await proxyService.fetchFrontendSettings(); // called by the scheduler service + await frontendApiService.fetchFrontendSettings(); // called by the scheduler service - const settings = await proxyService.getFrontendSettings(); + const settings = await frontendApiService.getFrontendSettings(); expect(settings).toEqual({ frontendApiOrigins: ['*'], diff --git a/src/lib/middleware/cors-origin-middleware.ts b/src/lib/middleware/cors-origin-middleware.ts index 4804b00e5e..0ff3f0acad 100644 --- a/src/lib/middleware/cors-origin-middleware.ts +++ b/src/lib/middleware/cors-origin-middleware.ts @@ -16,13 +16,13 @@ export const resolveOrigin = (allowedOrigins: string[]): string | string[] => { // Check the request's Origin header against a list of allowed origins. // The list may include '*', which `cors` does not support natively. export const corsOriginMiddleware = ( - { proxyService }: Pick, + { frontendApiService }: Pick, config: IUnleashConfig, ): RequestHandler => { const corsFunc = cors(async (req, callback) => { try { const { frontendApiOrigins = [] } = - await proxyService.getFrontendSettings(); + await frontendApiService.getFrontendSettings(); callback(null, { origin: resolveOrigin(frontendApiOrigins), maxAge: config.accessControlMaxAge, diff --git a/src/lib/routes/admin-api/api-token.ts b/src/lib/routes/admin-api/api-token.ts index cdf213cabe..2033e6f13b 100644 --- a/src/lib/routes/admin-api/api-token.ts +++ b/src/lib/routes/admin-api/api-token.ts @@ -41,7 +41,7 @@ import { emptyResponse, getStandardResponses, } from '../../openapi/util/standard-responses'; -import { ProxyService } from '../../proxy/proxy-service'; +import { FrontendApiService } from '../../features/frontend-api/frontend-api-service'; import { extractUserId, extractUsername } from '../../util'; import { OperationDeniedError } from '../../error'; @@ -121,7 +121,7 @@ export class ApiTokenController extends Controller { private accessService: AccessService; - private proxyService: ProxyService; + private frontendApiService: FrontendApiService; private openApiService: OpenApiService; @@ -134,20 +134,20 @@ export class ApiTokenController extends Controller { { apiTokenService, accessService, - proxyService, + frontendApiService, openApiService, }: Pick< IUnleashServices, | 'apiTokenService' | 'accessService' - | 'proxyService' + | 'frontendApiService' | 'openApiService' >, ) { super(config); this.apiTokenService = apiTokenService; this.accessService = accessService; - this.proxyService = proxyService; + this.frontendApiService = frontendApiService; this.openApiService = openApiService; this.flagResolver = config.flagResolver; this.logger = config.getLogger('api-token-controller.js'); @@ -411,7 +411,7 @@ export class ApiTokenController extends Controller { extractUsername(req), req.user.id, ); - await this.proxyService.deleteClientForProxyToken(token); + await this.frontendApiService.deleteClientForFrontendApiToken(token); res.status(200).end(); } diff --git a/src/lib/routes/admin-api/config.ts b/src/lib/routes/admin-api/config.ts index eda23d6204..61a2d4f8e7 100644 --- a/src/lib/routes/admin-api/config.ts +++ b/src/lib/routes/admin-api/config.ts @@ -24,7 +24,7 @@ import { extractUsername } from '../../util/extract-user'; import NotFoundError from '../../error/notfound-error'; import { SetUiConfigSchema } from '../../openapi/spec/set-ui-config-schema'; import { createRequestSchema } from '../../openapi/util/create-request-schema'; -import { ProxyService } from '../../services'; +import { FrontendApiService } from '../../services'; import MaintenanceService from '../../features/maintenance/maintenance-service'; import memoizee from 'memoizee'; import { minutesToMilliseconds } from 'date-fns'; @@ -35,7 +35,7 @@ class ConfigController extends Controller { private settingService: SettingService; - private proxyService: ProxyService; + private frontendApiService: FrontendApiService; private emailService: EmailService; @@ -54,7 +54,7 @@ class ConfigController extends Controller { settingService, emailService, openApiService, - proxyService, + frontendApiService, maintenanceService, clientInstanceService, }: Pick< @@ -63,7 +63,7 @@ class ConfigController extends Controller { | 'settingService' | 'emailService' | 'openApiService' - | 'proxyService' + | 'frontendApiService' | 'maintenanceService' | 'clientInstanceService' >, @@ -73,7 +73,7 @@ class ConfigController extends Controller { this.settingService = settingService; this.emailService = emailService; this.openApiService = openApiService; - this.proxyService = proxyService; + this.frontendApiService = frontendApiService; this.maintenanceService = maintenanceService; this.clientInstanceService = clientInstanceService; this.usesOldEdgeFunction = memoizee( @@ -136,7 +136,7 @@ class ConfigController extends Controller { maintenanceMode, usesOldEdge, ] = await Promise.all([ - this.proxyService.getFrontendSettings(false), + this.frontendApiService.getFrontendSettings(false), this.settingService.get(simpleAuthSettingsKey), this.maintenanceService.isMaintenanceMode(), this.usesOldEdgeFunction(), @@ -190,7 +190,7 @@ class ConfigController extends Controller { res: Response, ): Promise { if (req.body.frontendSettings) { - await this.proxyService.setFrontendSettings( + await this.frontendApiService.setFrontendSettings( req.body.frontendSettings, extractUsername(req), req.user.id, diff --git a/src/lib/routes/admin-api/project/api-token.ts b/src/lib/routes/admin-api/project/api-token.ts index 2eb4b23d4e..1497cebbdc 100644 --- a/src/lib/routes/admin-api/project/api-token.ts +++ b/src/lib/routes/admin-api/project/api-token.ts @@ -25,7 +25,7 @@ import { ApiTokenService, OpenApiService, ProjectService, - ProxyService, + FrontendApiService, } from '../../../services'; import { extractUserId, extractUsername } from '../../../util'; import { IAuthRequest } from '../../unleash-types'; @@ -48,7 +48,7 @@ export class ProjectApiTokenController extends Controller { private accessService: AccessService; - private proxyService: ProxyService; + private frontendApiService: FrontendApiService; private openApiService: OpenApiService; @@ -61,14 +61,14 @@ export class ProjectApiTokenController extends Controller { { apiTokenService, accessService, - proxyService, + frontendApiService, openApiService, projectService, }: Pick< IUnleashServices, | 'apiTokenService' | 'accessService' - | 'proxyService' + | 'frontendApiService' | 'openApiService' | 'projectService' >, @@ -76,7 +76,7 @@ export class ProjectApiTokenController extends Controller { super(config); this.apiTokenService = apiTokenService; this.accessService = accessService; - this.proxyService = proxyService; + this.frontendApiService = frontendApiService; this.openApiService = openApiService; this.projectService = projectService; this.logger = config.getLogger('project-api-token-controller.js'); @@ -226,7 +226,9 @@ export class ProjectApiTokenController extends Controller { extractUsername(req), user.id, ); - await this.proxyService.deleteClientForProxyToken(token); + await this.frontendApiService.deleteClientForFrontendApiToken( + token, + ); res.status(200).end(); } else if (!storedToken) { res.status(404).end(); diff --git a/src/lib/routes/index.ts b/src/lib/routes/index.ts index 2a52bb0f8f..886d71ba09 100644 --- a/src/lib/routes/index.ts +++ b/src/lib/routes/index.ts @@ -9,7 +9,7 @@ import { AdminApi } from './admin-api'; import ClientApi from './client-api'; import { HealthCheckController } from './health-check'; -import FrontendAPIController from '../proxy/proxy-controller'; +import FrontendAPIController from '../features/frontend-api/frontend-api-controller'; import EdgeController from './edge-api'; import { PublicInviteController } from './public-invite'; import { Db } from '../db/db'; diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index 2d840fde5c..72169d8bc9 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -31,7 +31,7 @@ import { OpenApiService } from './openapi-service'; import { ClientSpecService } from './client-spec-service'; import { PlaygroundService } from '../features/playground/playground-service'; import { GroupService } from './group-service'; -import { ProxyService } from '../proxy/proxy-service'; +import { FrontendApiService } from '../features/frontend-api/frontend-api-service'; import EdgeService from './edge-service'; import PatService from './pat-service'; import { PublicSignupTokenService } from './public-signup-token-service'; @@ -112,9 +112,9 @@ import { InactiveUsersService } from '../users/inactive/inactive-users-service'; import { SegmentReadModel } from '../features/segment/segment-read-model'; import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model'; import { - createFakeProxyService, - createProxyService, -} from '../proxy/createProxyService'; + createFakeFrontendApiService, + createFrontendApiService, +} from '../features/frontend-api/createFrontendApiService'; export const createServices = ( stores: IUnleashStores, @@ -295,14 +295,14 @@ export const createServices = ( ? createClientFeatureToggleService(db, config) : createFakeClientFeatureToggleService(config); - const proxyService = db - ? createProxyService( + const frontendApiService = db + ? createFrontendApiService( db, config, clientMetricsServiceV2, configurationRevisionService, ) - : createFakeProxyService( + : createFakeFrontendApiService( config, clientMetricsServiceV2, configurationRevisionService, @@ -373,7 +373,7 @@ export const createServices = ( clientSpecService, playgroundService, groupService, - proxyService, + frontendApiService, edgeService, patService, publicSignupTokenService, @@ -428,7 +428,7 @@ export { ClientSpecService, PlaygroundService, GroupService, - ProxyService, + FrontendApiService, EdgeService, PatService, PublicSignupTokenService, diff --git a/src/lib/types/services.ts b/src/lib/types/services.ts index d514969f63..b7a7756759 100644 --- a/src/lib/types/services.ts +++ b/src/lib/types/services.ts @@ -28,7 +28,7 @@ import { OpenApiService } from '../services/openapi-service'; import { ClientSpecService } from '../services/client-spec-service'; import { PlaygroundService } from '../features/playground/playground-service'; import { GroupService } from '../services/group-service'; -import { ProxyService } from '../proxy/proxy-service'; +import { FrontendApiService } from '../features/frontend-api/frontend-api-service'; import EdgeService from '../services/edge-service'; import PatService from '../services/pat-service'; import { PublicSignupTokenService } from '../services/public-signup-token-service'; @@ -76,7 +76,7 @@ export interface IUnleashServices { projectHealthService: ProjectHealthService; projectService: ProjectService; playgroundService: PlaygroundService; - proxyService: ProxyService; + frontendApiService: FrontendApiService; publicSignupTokenService: PublicSignupTokenService; resetTokenService: ResetTokenService; sessionService: SessionService; diff --git a/src/test/e2e/api/admin/config.e2e.test.ts b/src/test/e2e/api/admin/config.e2e.test.ts index 2170d02372..fc9b3c53bc 100644 --- a/src/test/e2e/api/admin/config.e2e.test.ts +++ b/src/test/e2e/api/admin/config.e2e.test.ts @@ -57,7 +57,7 @@ test('gets ui config with disablePasswordAuth', async () => { test('gets ui config with frontendSettings', async () => { const frontendApiOrigins = ['https://example.net']; - await app.services.proxyService.setFrontendSettings( + await app.services.frontendApiService.setFrontendSettings( { frontendApiOrigins }, randomId(), -9999,