mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-27 01:19:00 +02:00
refactor: rename proxy to frontend api (#6502)
This commit is contained in:
parent
b4454053e8
commit
1f374ea20e
@ -1,4 +1,4 @@
|
|||||||
import { IFeatureToggleClient } from '../types';
|
import { IFeatureToggleClient } from '../../types';
|
||||||
|
|
||||||
export interface IClientFeatureToggleReadModel {
|
export interface IClientFeatureToggleReadModel {
|
||||||
getAll(): Promise<Record<string, Record<string, IFeatureToggleClient>>>;
|
getAll(): Promise<Record<string, Record<string, IFeatureToggleClient>>>;
|
@ -1,11 +1,15 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { IFeatureToggleClient, IStrategyConfig, PartialDeep } from '../types';
|
import {
|
||||||
import { ensureStringValue, mapValues } from '../util';
|
IFeatureToggleClient,
|
||||||
import { Db } from '../db/db';
|
IStrategyConfig,
|
||||||
import FeatureToggleStore from '../features/feature-toggle/feature-toggle-store';
|
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 Raw = Knex.Raw;
|
||||||
import metricsHelper from '../util/metrics-helper';
|
import metricsHelper from '../../util/metrics-helper';
|
||||||
import { DB_TIME } from '../metric-events';
|
import { DB_TIME } from '../../metric-events';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
||||||
|
|
@ -1,30 +1,30 @@
|
|||||||
import { ProxyService } from './proxy-service';
|
import { FrontendApiService } from './frontend-api-service';
|
||||||
import { SegmentReadModel } from '../features/segment/segment-read-model';
|
import { SegmentReadModel } from '../segment/segment-read-model';
|
||||||
import ClientMetricsServiceV2 from '../features/metrics/client-metrics/metrics-service-v2';
|
import ClientMetricsServiceV2 from '../metrics/client-metrics/metrics-service-v2';
|
||||||
import SettingService from '../services/setting-service';
|
import SettingService from '../../services/setting-service';
|
||||||
import SettingStore from '../db/setting-store';
|
import SettingStore from '../../db/setting-store';
|
||||||
import {
|
import {
|
||||||
createEventsService,
|
createEventsService,
|
||||||
createFakeEventsService,
|
createFakeEventsService,
|
||||||
createFakeFeatureToggleService,
|
createFakeFeatureToggleService,
|
||||||
createFeatureToggleService,
|
createFeatureToggleService,
|
||||||
} from '../features';
|
} from '../index';
|
||||||
import ConfigurationRevisionService from '../features/feature-toggle/configuration-revision-service';
|
import ConfigurationRevisionService from '../feature-toggle/configuration-revision-service';
|
||||||
import { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
import { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
||||||
import ClientFeatureToggleReadModel from './client-feature-toggle-read-model';
|
import ClientFeatureToggleReadModel from './client-feature-toggle-read-model';
|
||||||
import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model';
|
import { FakeSegmentReadModel } from '../segment/fake-segment-read-model';
|
||||||
import FakeSettingStore from '../../test/fixtures/fake-setting-store';
|
import FakeSettingStore from '../../../test/fixtures/fake-setting-store';
|
||||||
import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model';
|
import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model';
|
||||||
import { IUnleashConfig } from '../types';
|
import { IUnleashConfig } from '../../types';
|
||||||
import { Db } from '../db/db';
|
import { Db } from '../../db/db';
|
||||||
|
|
||||||
export const createProxyService = (
|
export const createFrontendApiService = (
|
||||||
db: Db,
|
db: Db,
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
// client metrics service needs to be shared because it uses in-memory cache
|
// client metrics service needs to be shared because it uses in-memory cache
|
||||||
clientMetricsServiceV2: ClientMetricsServiceV2,
|
clientMetricsServiceV2: ClientMetricsServiceV2,
|
||||||
configurationRevisionService: ConfigurationRevisionService,
|
configurationRevisionService: ConfigurationRevisionService,
|
||||||
): ProxyService => {
|
): FrontendApiService => {
|
||||||
const segmentReadModel = new SegmentReadModel(db);
|
const segmentReadModel = new SegmentReadModel(db);
|
||||||
const settingStore = new SettingStore(db, config.getLogger);
|
const settingStore = new SettingStore(db, config.getLogger);
|
||||||
const eventService = createEventsService(db, config);
|
const eventService = createEventsService(db, config);
|
||||||
@ -45,7 +45,7 @@ export const createProxyService = (
|
|||||||
clientFeatureToggleReadModel,
|
clientFeatureToggleReadModel,
|
||||||
configurationRevisionService,
|
configurationRevisionService,
|
||||||
);
|
);
|
||||||
return new ProxyService(
|
return new FrontendApiService(
|
||||||
config,
|
config,
|
||||||
{ segmentReadModel },
|
{ segmentReadModel },
|
||||||
{
|
{
|
||||||
@ -58,11 +58,11 @@ export const createProxyService = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createFakeProxyService = (
|
export const createFakeFrontendApiService = (
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
clientMetricsServiceV2: ClientMetricsServiceV2,
|
clientMetricsServiceV2: ClientMetricsServiceV2,
|
||||||
configurationRevisionService: ConfigurationRevisionService,
|
configurationRevisionService: ConfigurationRevisionService,
|
||||||
): ProxyService => {
|
): FrontendApiService => {
|
||||||
const segmentReadModel = new FakeSegmentReadModel();
|
const segmentReadModel = new FakeSegmentReadModel();
|
||||||
const settingStore = new FakeSettingStore();
|
const settingStore = new FakeSettingStore();
|
||||||
const eventService = createFakeEventsService(config);
|
const eventService = createFakeEventsService(config);
|
||||||
@ -80,7 +80,7 @@ export const createFakeProxyService = (
|
|||||||
clientFeatureToggleReadModel,
|
clientFeatureToggleReadModel,
|
||||||
configurationRevisionService,
|
configurationRevisionService,
|
||||||
);
|
);
|
||||||
return new ProxyService(
|
return new FrontendApiService(
|
||||||
config,
|
config,
|
||||||
{ segmentReadModel },
|
{ segmentReadModel },
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
import { IFeatureToggleClient } from '../types';
|
import { IFeatureToggleClient } from '../../types';
|
||||||
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
||||||
|
|
||||||
export default class FakeClientFeatureToggleReadModel
|
export default class FakeClientFeatureToggleReadModel
|
@ -1,8 +1,8 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import Controller from '../routes/controller';
|
import Controller from '../../routes/controller';
|
||||||
import { IUnleashConfig, IUnleashServices, NONE } from '../types';
|
import { IUnleashConfig, IUnleashServices, NONE } from '../../types';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../../logger';
|
||||||
import { IApiUser } from '../types/api-user';
|
import { IApiUser } from '../../types/api-user';
|
||||||
import {
|
import {
|
||||||
ClientMetricsSchema,
|
ClientMetricsSchema,
|
||||||
createRequestSchema,
|
createRequestSchema,
|
||||||
@ -13,12 +13,12 @@ import {
|
|||||||
ProxyFeatureSchema,
|
ProxyFeatureSchema,
|
||||||
proxyFeaturesSchema,
|
proxyFeaturesSchema,
|
||||||
ProxyFeaturesSchema,
|
ProxyFeaturesSchema,
|
||||||
} from '../openapi';
|
} from '../../openapi';
|
||||||
import { Context } from 'unleash-client';
|
import { Context } from 'unleash-client';
|
||||||
import { enrichContextWithIp } from './index';
|
import { enrichContextWithIp } from './index';
|
||||||
import { corsOriginMiddleware } from '../middleware';
|
import { corsOriginMiddleware } from '../../middleware';
|
||||||
import NotImplementedError from '../error/not-implemented-error';
|
import NotImplementedError from '../../error/not-implemented-error';
|
||||||
import NotFoundError from '../error/notfound-error';
|
import NotFoundError from '../../error/notfound-error';
|
||||||
import rateLimit from 'express-rate-limit';
|
import rateLimit from 'express-rate-limit';
|
||||||
import { minutesToMilliseconds } from 'date-fns';
|
import { minutesToMilliseconds } from 'date-fns';
|
||||||
import isEqual from 'lodash.isequal';
|
import isEqual from 'lodash.isequal';
|
||||||
@ -34,7 +34,7 @@ interface ApiUserRequest<
|
|||||||
|
|
||||||
type Services = Pick<
|
type Services = Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
'settingService' | 'proxyService' | 'openApiService'
|
'settingService' | 'frontendApiService' | 'openApiService'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export default class FrontendAPIController extends Controller {
|
export default class FrontendAPIController extends Controller {
|
||||||
@ -44,7 +44,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
|
|
||||||
constructor(config: IUnleashConfig, services: Services) {
|
constructor(config: IUnleashConfig, services: Services) {
|
||||||
super(config);
|
super(config);
|
||||||
this.logger = config.getLogger('proxy-api/index.ts');
|
this.logger = config.getLogger('frontend-api-controller.ts');
|
||||||
this.services = services;
|
this.services = services;
|
||||||
|
|
||||||
// Support CORS requests for the frontend endpoints.
|
// Support CORS requests for the frontend endpoints.
|
||||||
@ -54,7 +54,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
this.route({
|
this.route({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
path: '',
|
path: '',
|
||||||
handler: this.getProxyFeatures,
|
handler: this.getFrontendApiFeatures,
|
||||||
permission: NONE,
|
permission: NONE,
|
||||||
middleware: [
|
middleware: [
|
||||||
this.services.openApiService.validPath({
|
this.services.openApiService.validPath({
|
||||||
@ -89,7 +89,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
this.route({
|
this.route({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
path: '/client/metrics',
|
path: '/client/metrics',
|
||||||
handler: this.registerProxyMetrics,
|
handler: this.registerFrontendApiMetrics,
|
||||||
permission: NONE,
|
permission: NONE,
|
||||||
middleware: [
|
middleware: [
|
||||||
this.services.openApiService.validPath({
|
this.services.openApiService.validPath({
|
||||||
@ -117,7 +117,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
this.route({
|
this.route({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
path: '/client/register',
|
path: '/client/register',
|
||||||
handler: this.registerProxyClient,
|
handler: this.registerFrontendApiClient,
|
||||||
permission: NONE,
|
permission: NONE,
|
||||||
middleware: [
|
middleware: [
|
||||||
this.services.openApiService.validPath({
|
this.services.openApiService.validPath({
|
||||||
@ -168,7 +168,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
res.status(error.statusCode).json(error);
|
res.status(error.statusCode).json(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getProxyFeatures(
|
private async getFrontendApiFeatures(
|
||||||
req: ApiUserRequest,
|
req: ApiUserRequest,
|
||||||
res: Response<ProxyFeaturesSchema>,
|
res: Response<ProxyFeaturesSchema>,
|
||||||
) {
|
) {
|
||||||
@ -179,11 +179,11 @@ export default class FrontendAPIController extends Controller {
|
|||||||
let newToggles: ProxyFeatureSchema[] = [];
|
let newToggles: ProxyFeatureSchema[] = [];
|
||||||
if (this.config.flagResolver.isEnabled('globalFrontendApiCache')) {
|
if (this.config.flagResolver.isEnabled('globalFrontendApiCache')) {
|
||||||
[toggles, newToggles] = await Promise.all([
|
[toggles, newToggles] = await Promise.all([
|
||||||
this.services.proxyService.getProxyFeatures(
|
this.services.frontendApiService.getFrontendApiFeatures(
|
||||||
req.user,
|
req.user,
|
||||||
FrontendAPIController.createContext(req),
|
FrontendAPIController.createContext(req),
|
||||||
),
|
),
|
||||||
this.services.proxyService.getNewProxyFeatures(
|
this.services.frontendApiService.getNewFrontendApiFeatures(
|
||||||
req.user,
|
req.user,
|
||||||
FrontendAPIController.createContext(req),
|
FrontendAPIController.createContext(req),
|
||||||
),
|
),
|
||||||
@ -199,10 +199,11 @@ export default class FrontendAPIController extends Controller {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
toggles = await this.services.proxyService.getProxyFeatures(
|
toggles =
|
||||||
req.user,
|
await this.services.frontendApiService.getFrontendApiFeatures(
|
||||||
FrontendAPIController.createContext(req),
|
req.user,
|
||||||
);
|
FrontendAPIController.createContext(req),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnedToggles = this.config.flagResolver.isEnabled(
|
const returnedToggles = this.config.flagResolver.isEnabled(
|
||||||
@ -221,7 +222,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async registerProxyMetrics(
|
private async registerFrontendApiMetrics(
|
||||||
req: ApiUserRequest<unknown, unknown, ClientMetricsSchema>,
|
req: ApiUserRequest<unknown, unknown, ClientMetricsSchema>,
|
||||||
res: Response,
|
res: Response,
|
||||||
) {
|
) {
|
||||||
@ -234,7 +235,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.services.proxyService.registerProxyMetrics(
|
await this.services.frontendApiService.registerFrontendApiMetrics(
|
||||||
req.user,
|
req.user,
|
||||||
req.body,
|
req.body,
|
||||||
req.ip,
|
req.ip,
|
||||||
@ -242,7 +243,7 @@ export default class FrontendAPIController extends Controller {
|
|||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async registerProxyClient(
|
private async registerFrontendApiClient(
|
||||||
req: ApiUserRequest<unknown, unknown, ProxyClientSchema>,
|
req: ApiUserRequest<unknown, unknown, ProxyClientSchema>,
|
||||||
res: Response<string>,
|
res: Response<string>,
|
||||||
) {
|
) {
|
@ -5,10 +5,10 @@ import {
|
|||||||
EnhancedFeatureInterface,
|
EnhancedFeatureInterface,
|
||||||
FeatureInterface,
|
FeatureInterface,
|
||||||
} from 'unleash-client/lib/feature';
|
} from 'unleash-client/lib/feature';
|
||||||
import { IApiUser } from '../types/api-user';
|
import { IApiUser } from '../../types/api-user';
|
||||||
import { IUnleashConfig } from '../types';
|
import { IUnleashConfig } from '../../types';
|
||||||
import { UnleashEvents } from 'unleash-client';
|
import { UnleashEvents } from 'unleash-client';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../../logger';
|
||||||
import { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
import { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
||||||
|
|
||||||
type Config = Pick<IUnleashConfig, 'getLogger'>;
|
type Config = Pick<IUnleashConfig, 'getLogger'>;
|
@ -1,25 +1,24 @@
|
|||||||
import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../types';
|
import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../../types';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../../logger';
|
||||||
import { ClientMetricsSchema, ProxyFeatureSchema } from '../openapi';
|
import { ClientMetricsSchema, ProxyFeatureSchema } from '../../openapi';
|
||||||
import ApiUser, { IApiUser } from '../types/api-user';
|
import ApiUser, { IApiUser } from '../../types/api-user';
|
||||||
import {
|
import {
|
||||||
Context,
|
Context,
|
||||||
InMemStorageProvider,
|
InMemStorageProvider,
|
||||||
Unleash,
|
Unleash,
|
||||||
UnleashEvents,
|
UnleashEvents,
|
||||||
} from 'unleash-client';
|
} from 'unleash-client';
|
||||||
import { ApiTokenType } from '../types/models/api-token';
|
import { ApiTokenType } from '../../types/models/api-token';
|
||||||
import {
|
import {
|
||||||
FrontendSettings,
|
FrontendSettings,
|
||||||
frontendSettingsKey,
|
frontendSettingsKey,
|
||||||
} from '../types/settings/frontend-settings';
|
} from '../../types/settings/frontend-settings';
|
||||||
import { validateOrigins } from '../util';
|
import { validateOrigins } from '../../util';
|
||||||
import { BadDataError, InvalidTokenError } from '../error';
|
import { BadDataError, InvalidTokenError } from '../../error';
|
||||||
import { PROXY_REPOSITORY_CREATED } from '../metric-events';
|
import { PROXY_REPOSITORY_CREATED } from '../../metric-events';
|
||||||
import { ProxyRepository } from './index';
|
|
||||||
import { FrontendApiRepository } from './frontend-api-repository';
|
import { FrontendApiRepository } from './frontend-api-repository';
|
||||||
import { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
import { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
||||||
import isEqual from 'lodash.isequal';
|
import { ProxyRepository } from './proxy-repository';
|
||||||
|
|
||||||
export type Config = Pick<
|
export type Config = Pick<
|
||||||
IUnleashConfig,
|
IUnleashConfig,
|
||||||
@ -36,7 +35,7 @@ export type Services = Pick<
|
|||||||
| 'configurationRevisionService'
|
| 'configurationRevisionService'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export class ProxyService {
|
export class FrontendApiService {
|
||||||
private readonly config: Config;
|
private readonly config: Config;
|
||||||
|
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
@ -50,7 +49,7 @@ export class ProxyService {
|
|||||||
/**
|
/**
|
||||||
* This is intentionally a Promise because we want to be able to await
|
* 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
|
* 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<ApiUser['secret'], Promise<Unleash>> =
|
private readonly clients: Map<ApiUser['secret'], Promise<Unleash>> =
|
||||||
new Map();
|
new Map();
|
||||||
@ -66,17 +65,17 @@ export class ProxyService {
|
|||||||
globalFrontendApiCache: GlobalFrontendApiCache,
|
globalFrontendApiCache: GlobalFrontendApiCache,
|
||||||
) {
|
) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.logger = config.getLogger('services/proxy-service.ts');
|
this.logger = config.getLogger('services/frontend-api-service.ts');
|
||||||
this.stores = stores;
|
this.stores = stores;
|
||||||
this.services = services;
|
this.services = services;
|
||||||
this.globalFrontendApiCache = globalFrontendApiCache;
|
this.globalFrontendApiCache = globalFrontendApiCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProxyFeatures(
|
async getFrontendApiFeatures(
|
||||||
token: IApiUser,
|
token: IApiUser,
|
||||||
context: Context,
|
context: Context,
|
||||||
): Promise<ProxyFeatureSchema[]> {
|
): Promise<ProxyFeatureSchema[]> {
|
||||||
const client = await this.clientForProxyToken(token);
|
const client = await this.clientForFrontendApiToken(token);
|
||||||
const definitions = client.getFeatureToggleDefinitions() || [];
|
const definitions = client.getFeatureToggleDefinitions() || [];
|
||||||
const sessionId = context.sessionId || String(Math.random());
|
const sessionId = context.sessionId || String(Math.random());
|
||||||
|
|
||||||
@ -98,30 +97,11 @@ export class ProxyService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async compareToggleDefinitions(token: IApiUser) {
|
async getNewFrontendApiFeatures(
|
||||||
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(
|
|
||||||
token: IApiUser,
|
token: IApiUser,
|
||||||
context: Context,
|
context: Context,
|
||||||
): Promise<ProxyFeatureSchema[]> {
|
): Promise<ProxyFeatureSchema[]> {
|
||||||
const client = await this.newClientForProxyToken(token);
|
const client = await this.newClientForFrontendApiToken(token);
|
||||||
const definitions = client.getFeatureToggleDefinitions() || [];
|
const definitions = client.getFeatureToggleDefinitions() || [];
|
||||||
const sessionId = context.sessionId || String(Math.random());
|
const sessionId = context.sessionId || String(Math.random());
|
||||||
|
|
||||||
@ -144,12 +124,12 @@ export class ProxyService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerProxyMetrics(
|
async registerFrontendApiMetrics(
|
||||||
token: IApiUser,
|
token: IApiUser,
|
||||||
metrics: ClientMetricsSchema,
|
metrics: ClientMetricsSchema,
|
||||||
ip: string,
|
ip: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
ProxyService.assertExpectedTokenType(token);
|
FrontendApiService.assertExpectedTokenType(token);
|
||||||
|
|
||||||
const environment =
|
const environment =
|
||||||
this.services.clientMetricsServiceV2.resolveMetricsEnvironment(
|
this.services.clientMetricsServiceV2.resolveMetricsEnvironment(
|
||||||
@ -166,12 +146,12 @@ export class ProxyService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async clientForProxyToken(token: IApiUser): Promise<Unleash> {
|
private async clientForFrontendApiToken(token: IApiUser): Promise<Unleash> {
|
||||||
ProxyService.assertExpectedTokenType(token);
|
FrontendApiService.assertExpectedTokenType(token);
|
||||||
|
|
||||||
let client = this.clients.get(token.secret);
|
let client = this.clients.get(token.secret);
|
||||||
if (!client) {
|
if (!client) {
|
||||||
client = this.createClientForProxyToken(token);
|
client = this.createClientForFrontendApiToken(token);
|
||||||
this.clients.set(token.secret, client);
|
this.clients.set(token.secret, client);
|
||||||
this.config.eventBus.emit(PROXY_REPOSITORY_CREATED);
|
this.config.eventBus.emit(PROXY_REPOSITORY_CREATED);
|
||||||
}
|
}
|
||||||
@ -179,12 +159,14 @@ export class ProxyService {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async newClientForProxyToken(token: IApiUser): Promise<Unleash> {
|
private async newClientForFrontendApiToken(
|
||||||
ProxyService.assertExpectedTokenType(token);
|
token: IApiUser,
|
||||||
|
): Promise<Unleash> {
|
||||||
|
FrontendApiService.assertExpectedTokenType(token);
|
||||||
|
|
||||||
let newClient = this.newClients.get(token.secret);
|
let newClient = this.newClients.get(token.secret);
|
||||||
if (!newClient) {
|
if (!newClient) {
|
||||||
newClient = this.createNewClientForProxyToken(token);
|
newClient = this.createNewClientForFrontendApiToken(token);
|
||||||
this.newClients.set(token.secret, newClient);
|
this.newClients.set(token.secret, newClient);
|
||||||
// TODO: do we need this twice?
|
// TODO: do we need this twice?
|
||||||
// this.config.eventBus.emit(PROXY_REPOSITORY_CREATED);
|
// this.config.eventBus.emit(PROXY_REPOSITORY_CREATED);
|
||||||
@ -193,7 +175,9 @@ export class ProxyService {
|
|||||||
return newClient;
|
return newClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createClientForProxyToken(token: IApiUser): Promise<Unleash> {
|
private async createClientForFrontendApiToken(
|
||||||
|
token: IApiUser,
|
||||||
|
): Promise<Unleash> {
|
||||||
const repository = new ProxyRepository(
|
const repository = new ProxyRepository(
|
||||||
this.config,
|
this.config,
|
||||||
this.stores,
|
this.stores,
|
||||||
@ -219,7 +203,7 @@ export class ProxyService {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createNewClientForProxyToken(
|
private async createNewClientForFrontendApiToken(
|
||||||
token: IApiUser,
|
token: IApiUser,
|
||||||
): Promise<Unleash> {
|
): Promise<Unleash> {
|
||||||
const repository = new FrontendApiRepository(
|
const repository = new FrontendApiRepository(
|
||||||
@ -228,7 +212,7 @@ export class ProxyService {
|
|||||||
token,
|
token,
|
||||||
);
|
);
|
||||||
const client = new Unleash({
|
const client = new Unleash({
|
||||||
appName: 'proxy',
|
appName: 'frontend-api',
|
||||||
url: 'unused',
|
url: 'unused',
|
||||||
storageProvider: new InMemStorageProvider(),
|
storageProvider: new InMemStorageProvider(),
|
||||||
disableMetrics: true,
|
disableMetrics: true,
|
||||||
@ -246,7 +230,7 @@ export class ProxyService {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteClientForProxyToken(secret: string): Promise<void> {
|
async deleteClientForFrontendApiToken(secret: string): Promise<void> {
|
||||||
const clientPromise = this.clients.get(secret);
|
const clientPromise = this.clients.get(secret);
|
||||||
if (clientPromise) {
|
if (clientPromise) {
|
||||||
const client = await clientPromise;
|
const client = await clientPromise;
|
@ -1,8 +1,11 @@
|
|||||||
import { IUnleashTest, setupAppWithAuth } from '../../helpers/test-helper';
|
import {
|
||||||
import dbInit, { ITestDb } from '../../helpers/database-init';
|
IUnleashTest,
|
||||||
import getLogger from '../../../fixtures/no-logger';
|
setupAppWithAuth,
|
||||||
import { randomId } from '../../../../lib/util';
|
} from '../../../test/e2e/helpers/test-helper';
|
||||||
import { ApiTokenType } from '../../../../lib/types/models/api-token';
|
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 app: IUnleashTest;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -25,7 +28,7 @@ beforeAll(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
app.services.proxyService.stopAll();
|
app.services.frontendApiService.stopAll();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
@ -1,21 +1,24 @@
|
|||||||
import { IUnleashTest, setupAppWithAuth } from '../../helpers/test-helper';
|
import {
|
||||||
import dbInit, { ITestDb } from '../../helpers/database-init';
|
IUnleashTest,
|
||||||
import getLogger from '../../../fixtures/no-logger';
|
setupAppWithAuth,
|
||||||
import { randomId } from '../../../../lib/util';
|
} 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 {
|
import {
|
||||||
ApiTokenType,
|
ApiTokenType,
|
||||||
IApiToken,
|
IApiToken,
|
||||||
IApiTokenCreate,
|
IApiTokenCreate,
|
||||||
} from '../../../../lib/types/models/api-token';
|
} from '../../types/models/api-token';
|
||||||
import { startOfHour } from 'date-fns';
|
import { startOfHour } from 'date-fns';
|
||||||
import {
|
import {
|
||||||
FEATURE_UPDATED,
|
FEATURE_UPDATED,
|
||||||
IConstraint,
|
IConstraint,
|
||||||
IStrategyConfig,
|
IStrategyConfig,
|
||||||
SYSTEM_USER,
|
SYSTEM_USER,
|
||||||
} from '../../../../lib/types';
|
} from '../../types';
|
||||||
import { ProxyRepository } from '../../../../lib/proxy';
|
import { ProxyRepository } from './index';
|
||||||
import { Logger } from '../../../../lib/logger';
|
import { Logger } from '../../logger';
|
||||||
|
|
||||||
let app: IUnleashTest;
|
let app: IUnleashTest;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -32,7 +35,7 @@ beforeAll(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
app.services.proxyService.stopAll();
|
app.services.frontendApiService.stopAll();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
@ -2,8 +2,8 @@ import {
|
|||||||
GlobalFrontendApiCache,
|
GlobalFrontendApiCache,
|
||||||
GlobalFrontendApiCacheState,
|
GlobalFrontendApiCacheState,
|
||||||
} from './global-frontend-api-cache';
|
} from './global-frontend-api-cache';
|
||||||
import noLogger from '../../test/fixtures/no-logger';
|
import noLogger from '../../../test/fixtures/no-logger';
|
||||||
import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model';
|
import { FakeSegmentReadModel } from '../segment/fake-segment-read-model';
|
||||||
import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model';
|
import FakeClientFeatureToggleReadModel from './fake-client-feature-toggle-read-model';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import {
|
import {
|
||||||
@ -11,8 +11,8 @@ import {
|
|||||||
IFeatureToggleClient,
|
IFeatureToggleClient,
|
||||||
IFlagResolver,
|
IFlagResolver,
|
||||||
ISegment,
|
ISegment,
|
||||||
} from '../types';
|
} from '../../types';
|
||||||
import { UPDATE_REVISION } from '../features/feature-toggle/configuration-revision-service';
|
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service';
|
||||||
|
|
||||||
const state = async (
|
const state = async (
|
||||||
cache: GlobalFrontendApiCache,
|
cache: GlobalFrontendApiCache,
|
@ -1,19 +1,19 @@
|
|||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import { Segment } from 'unleash-client/lib/strategy/strategy';
|
import { Segment } from 'unleash-client/lib/strategy/strategy';
|
||||||
import { FeatureInterface } from 'unleash-client/lib/feature';
|
import { FeatureInterface } from 'unleash-client/lib/feature';
|
||||||
import { IApiUser } from '../types/api-user';
|
import { IApiUser } from '../../types/api-user';
|
||||||
import {
|
import {
|
||||||
IFeatureToggleClient,
|
IFeatureToggleClient,
|
||||||
ISegmentReadModel,
|
ISegmentReadModel,
|
||||||
IUnleashConfig,
|
IUnleashConfig,
|
||||||
} from '../types';
|
} from '../../types';
|
||||||
import {
|
import {
|
||||||
mapFeatureForClient,
|
mapFeatureForClient,
|
||||||
mapSegmentsForClient,
|
mapSegmentsForClient,
|
||||||
} from '../features/playground/offline-unleash-client';
|
} from '../playground/offline-unleash-client';
|
||||||
import { ALL_ENVS } from '../util/constants';
|
import { ALL_ENVS } from '../../util/constants';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../../logger';
|
||||||
import { UPDATE_REVISION } from '../features/feature-toggle/configuration-revision-service';
|
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service';
|
||||||
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
import { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type';
|
||||||
|
|
||||||
type Config = Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>;
|
type Config = Pick<IUnleashConfig, 'getLogger' | 'flagResolver'>;
|
@ -5,19 +5,19 @@ import {
|
|||||||
EnhancedFeatureInterface,
|
EnhancedFeatureInterface,
|
||||||
FeatureInterface,
|
FeatureInterface,
|
||||||
} from 'unleash-client/lib/feature';
|
} from 'unleash-client/lib/feature';
|
||||||
import { IApiUser } from '../types/api-user';
|
import { IApiUser } from '../../types/api-user';
|
||||||
import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../types';
|
import { IUnleashConfig, IUnleashServices, IUnleashStores } from '../../types';
|
||||||
import {
|
import {
|
||||||
mapFeaturesForClient,
|
mapFeaturesForClient,
|
||||||
mapSegmentsForClient,
|
mapSegmentsForClient,
|
||||||
} from '../features/playground/offline-unleash-client';
|
} from '../playground/offline-unleash-client';
|
||||||
import { ALL_ENVS } from '../util/constants';
|
import { ALL_ENVS } from '../../util/constants';
|
||||||
import { UnleashEvents } from 'unleash-client';
|
import { UnleashEvents } from 'unleash-client';
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../../logger';
|
||||||
import ConfigurationRevisionService, {
|
import ConfigurationRevisionService, {
|
||||||
UPDATE_REVISION,
|
UPDATE_REVISION,
|
||||||
} from '../features/feature-toggle/configuration-revision-service';
|
} from '../feature-toggle/configuration-revision-service';
|
||||||
import { PROXY_FEATURES_FOR_TOKEN_TIME } from '../metric-events';
|
import { PROXY_FEATURES_FOR_TOKEN_TIME } from '../../metric-events';
|
||||||
|
|
||||||
type Config = Pick<IUnleashConfig, 'getLogger' | 'frontendApi' | 'eventBus'>;
|
type Config = Pick<IUnleashConfig, 'getLogger' | 'frontendApi' | 'eventBus'>;
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ type Services = Pick<
|
|||||||
'featureToggleServiceV2' | 'configurationRevisionService'
|
'featureToggleServiceV2' | 'configurationRevisionService'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
// TODO: remove after finished migration to global frontend api cache
|
||||||
export class ProxyRepository
|
export class ProxyRepository
|
||||||
extends EventEmitter
|
extends EventEmitter
|
||||||
implements RepositoryInterface
|
implements RepositoryInterface
|
@ -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 { GlobalFrontendApiCache } from './global-frontend-api-cache';
|
||||||
import { IApiUser } from '../types';
|
import { IApiUser } from '../../types';
|
||||||
import { FeatureInterface } from 'unleash-client/lib/feature';
|
import { FeatureInterface } from 'unleash-client/lib/feature';
|
||||||
import noLogger from '../../test/fixtures/no-logger';
|
import noLogger from '../../../test/fixtures/no-logger';
|
||||||
import { ApiTokenType } from '../types/models/api-token';
|
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 irrelevant = {} as any;
|
||||||
const globalFrontendApiCache = {
|
const globalFrontendApiCache = {
|
||||||
getToggles(_: IApiUser): FeatureInterface[] {
|
getToggles(_: IApiUser): FeatureInterface[] {
|
||||||
@ -38,14 +38,14 @@ test('proxy service fetching features from global cache', async () => {
|
|||||||
) as FeatureInterface;
|
) as FeatureInterface;
|
||||||
},
|
},
|
||||||
} as GlobalFrontendApiCache;
|
} as GlobalFrontendApiCache;
|
||||||
const proxyService = new ProxyService(
|
const frontendApiService = new FrontendApiService(
|
||||||
{ getLogger: noLogger } as unknown as Config,
|
{ getLogger: noLogger } as unknown as Config,
|
||||||
irrelevant,
|
irrelevant,
|
||||||
irrelevant,
|
irrelevant,
|
||||||
globalFrontendApiCache,
|
globalFrontendApiCache,
|
||||||
);
|
);
|
||||||
|
|
||||||
const features = await proxyService.getNewProxyFeatures(
|
const features = await frontendApiService.getNewFrontendApiFeatures(
|
||||||
{
|
{
|
||||||
projects: ['irrelevant'],
|
projects: ['irrelevant'],
|
||||||
environment: 'irrelevant',
|
environment: 'irrelevant',
|
@ -28,7 +28,7 @@ export const scheduleServices = async (
|
|||||||
eventService,
|
eventService,
|
||||||
versionService,
|
versionService,
|
||||||
lastSeenService,
|
lastSeenService,
|
||||||
proxyService,
|
frontendApiService,
|
||||||
clientMetricsServiceV2,
|
clientMetricsServiceV2,
|
||||||
} = services;
|
} = services;
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ export const scheduleServices = async (
|
|||||||
);
|
);
|
||||||
|
|
||||||
schedulerService.schedule(
|
schedulerService.schedule(
|
||||||
proxyService.fetchFrontendSettings.bind(proxyService),
|
frontendApiService.fetchFrontendSettings.bind(frontendApiService),
|
||||||
minutesToMilliseconds(2),
|
minutesToMilliseconds(2),
|
||||||
'fetchFrontendSettings',
|
'fetchFrontendSettings',
|
||||||
0,
|
0,
|
||||||
|
@ -6,7 +6,7 @@ export * from './addons';
|
|||||||
export * from './db';
|
export * from './db';
|
||||||
export * from './middleware';
|
export * from './middleware';
|
||||||
export * from './openapi';
|
export * from './openapi';
|
||||||
export * from './proxy';
|
export * from './features/frontend-api';
|
||||||
export * from './routes';
|
export * from './routes';
|
||||||
export * from './services';
|
export * from './services';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
@ -4,7 +4,11 @@ import { createTestConfig } from '../../test/config/test-config';
|
|||||||
import FakeEventStore from '../../test/fixtures/fake-event-store';
|
import FakeEventStore from '../../test/fixtures/fake-event-store';
|
||||||
import { randomId } from '../util/random-id';
|
import { randomId } from '../util/random-id';
|
||||||
import FakeProjectStore from '../../test/fixtures/fake-project-store';
|
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 { ISettingStore } from '../../lib/types';
|
||||||
import { frontendSettingsKey } from '../../lib/types/settings/frontend-settings';
|
import { frontendSettingsKey } from '../../lib/types/settings/frontend-settings';
|
||||||
import FakeFeatureTagStore from '../../test/fixtures/fake-feature-tag-store';
|
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 TEST_USER_ID = -9999;
|
||||||
const createSettingService = (
|
const createSettingService = (
|
||||||
frontendApiOrigins: string[],
|
frontendApiOrigins: string[],
|
||||||
): { proxyService: ProxyService; settingStore: ISettingStore } => {
|
): { frontendApiService: FrontendApiService; settingStore: ISettingStore } => {
|
||||||
const config = createTestConfig({ frontendApiOrigins });
|
const config = createTestConfig({ frontendApiOrigins });
|
||||||
|
|
||||||
const stores = {
|
const stores = {
|
||||||
@ -30,7 +34,7 @@ const createSettingService = (
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
proxyService: new ProxyService(config, stores, services),
|
frontendApiService: new FrontendApiService(config, stores, services),
|
||||||
settingStore: stores.settingStore,
|
settingStore: stores.settingStore,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -47,10 +51,10 @@ test('resolveOrigin', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('corsOriginMiddleware origin validation', async () => {
|
test('corsOriginMiddleware origin validation', async () => {
|
||||||
const { proxyService } = createSettingService([]);
|
const { frontendApiService } = createSettingService([]);
|
||||||
const userName = randomId();
|
const userName = randomId();
|
||||||
await expect(() =>
|
await expect(() =>
|
||||||
proxyService.setFrontendSettings(
|
frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins: ['a'] },
|
{ frontendApiOrigins: ['a'] },
|
||||||
userName,
|
userName,
|
||||||
TEST_USER_ID,
|
TEST_USER_ID,
|
||||||
@ -59,84 +63,84 @@ test('corsOriginMiddleware origin validation', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('corsOriginMiddleware without config', async () => {
|
test('corsOriginMiddleware without config', async () => {
|
||||||
const { proxyService, settingStore } = createSettingService([]);
|
const { frontendApiService, settingStore } = createSettingService([]);
|
||||||
const userName = randomId();
|
const userName = randomId();
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: [],
|
frontendApiOrigins: [],
|
||||||
});
|
});
|
||||||
await proxyService.setFrontendSettings(
|
await frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins: [] },
|
{ frontendApiOrigins: [] },
|
||||||
userName,
|
userName,
|
||||||
TEST_USER_ID,
|
TEST_USER_ID,
|
||||||
);
|
);
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: [],
|
frontendApiOrigins: [],
|
||||||
});
|
});
|
||||||
await proxyService.setFrontendSettings(
|
await frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins: ['*'] },
|
{ frontendApiOrigins: ['*'] },
|
||||||
userName,
|
userName,
|
||||||
TEST_USER_ID,
|
TEST_USER_ID,
|
||||||
);
|
);
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: ['*'],
|
frontendApiOrigins: ['*'],
|
||||||
});
|
});
|
||||||
await settingStore.delete(frontendSettingsKey);
|
await settingStore.delete(frontendSettingsKey);
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: [],
|
frontendApiOrigins: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('corsOriginMiddleware with config', async () => {
|
test('corsOriginMiddleware with config', async () => {
|
||||||
const { proxyService, settingStore } = createSettingService(['*']);
|
const { frontendApiService, settingStore } = createSettingService(['*']);
|
||||||
const userName = randomId();
|
const userName = randomId();
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: ['*'],
|
frontendApiOrigins: ['*'],
|
||||||
});
|
});
|
||||||
await proxyService.setFrontendSettings(
|
await frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins: [] },
|
{ frontendApiOrigins: [] },
|
||||||
userName,
|
userName,
|
||||||
TEST_USER_ID,
|
TEST_USER_ID,
|
||||||
);
|
);
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: [],
|
frontendApiOrigins: [],
|
||||||
});
|
});
|
||||||
await proxyService.setFrontendSettings(
|
await frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins: ['https://example.com', 'https://example.org'] },
|
{ frontendApiOrigins: ['https://example.com', 'https://example.org'] },
|
||||||
userName,
|
userName,
|
||||||
TEST_USER_ID,
|
TEST_USER_ID,
|
||||||
);
|
);
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: ['https://example.com', 'https://example.org'],
|
frontendApiOrigins: ['https://example.com', 'https://example.org'],
|
||||||
});
|
});
|
||||||
await settingStore.delete(frontendSettingsKey);
|
await settingStore.delete(frontendSettingsKey);
|
||||||
expect(await proxyService.getFrontendSettings(false)).toEqual({
|
expect(await frontendApiService.getFrontendSettings(false)).toEqual({
|
||||||
frontendApiOrigins: ['*'],
|
frontendApiOrigins: ['*'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('corsOriginMiddleware with caching enabled', async () => {
|
test('corsOriginMiddleware with caching enabled', async () => {
|
||||||
const { proxyService } = createSettingService([]);
|
const { frontendApiService } = createSettingService([]);
|
||||||
|
|
||||||
const userName = randomId();
|
const userName = randomId();
|
||||||
expect(await proxyService.getFrontendSettings()).toEqual({
|
expect(await frontendApiService.getFrontendSettings()).toEqual({
|
||||||
frontendApiOrigins: [],
|
frontendApiOrigins: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
//setting
|
//setting
|
||||||
await proxyService.setFrontendSettings(
|
await frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins: ['*'] },
|
{ frontendApiOrigins: ['*'] },
|
||||||
userName,
|
userName,
|
||||||
TEST_USER_ID,
|
TEST_USER_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
//still get cached value
|
//still get cached value
|
||||||
expect(await proxyService.getFrontendSettings()).toEqual({
|
expect(await frontendApiService.getFrontendSettings()).toEqual({
|
||||||
frontendApiOrigins: [],
|
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({
|
expect(settings).toEqual({
|
||||||
frontendApiOrigins: ['*'],
|
frontendApiOrigins: ['*'],
|
||||||
|
@ -16,13 +16,13 @@ export const resolveOrigin = (allowedOrigins: string[]): string | string[] => {
|
|||||||
// Check the request's Origin header against a list of allowed origins.
|
// Check the request's Origin header against a list of allowed origins.
|
||||||
// The list may include '*', which `cors` does not support natively.
|
// The list may include '*', which `cors` does not support natively.
|
||||||
export const corsOriginMiddleware = (
|
export const corsOriginMiddleware = (
|
||||||
{ proxyService }: Pick<IUnleashServices, 'proxyService'>,
|
{ frontendApiService }: Pick<IUnleashServices, 'frontendApiService'>,
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
): RequestHandler => {
|
): RequestHandler => {
|
||||||
const corsFunc = cors(async (req, callback) => {
|
const corsFunc = cors(async (req, callback) => {
|
||||||
try {
|
try {
|
||||||
const { frontendApiOrigins = [] } =
|
const { frontendApiOrigins = [] } =
|
||||||
await proxyService.getFrontendSettings();
|
await frontendApiService.getFrontendSettings();
|
||||||
callback(null, {
|
callback(null, {
|
||||||
origin: resolveOrigin(frontendApiOrigins),
|
origin: resolveOrigin(frontendApiOrigins),
|
||||||
maxAge: config.accessControlMaxAge,
|
maxAge: config.accessControlMaxAge,
|
||||||
|
@ -41,7 +41,7 @@ import {
|
|||||||
emptyResponse,
|
emptyResponse,
|
||||||
getStandardResponses,
|
getStandardResponses,
|
||||||
} from '../../openapi/util/standard-responses';
|
} 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 { extractUserId, extractUsername } from '../../util';
|
||||||
import { OperationDeniedError } from '../../error';
|
import { OperationDeniedError } from '../../error';
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ export class ApiTokenController extends Controller {
|
|||||||
|
|
||||||
private accessService: AccessService;
|
private accessService: AccessService;
|
||||||
|
|
||||||
private proxyService: ProxyService;
|
private frontendApiService: FrontendApiService;
|
||||||
|
|
||||||
private openApiService: OpenApiService;
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
@ -134,20 +134,20 @@ export class ApiTokenController extends Controller {
|
|||||||
{
|
{
|
||||||
apiTokenService,
|
apiTokenService,
|
||||||
accessService,
|
accessService,
|
||||||
proxyService,
|
frontendApiService,
|
||||||
openApiService,
|
openApiService,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
| 'apiTokenService'
|
| 'apiTokenService'
|
||||||
| 'accessService'
|
| 'accessService'
|
||||||
| 'proxyService'
|
| 'frontendApiService'
|
||||||
| 'openApiService'
|
| 'openApiService'
|
||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.apiTokenService = apiTokenService;
|
this.apiTokenService = apiTokenService;
|
||||||
this.accessService = accessService;
|
this.accessService = accessService;
|
||||||
this.proxyService = proxyService;
|
this.frontendApiService = frontendApiService;
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
this.flagResolver = config.flagResolver;
|
this.flagResolver = config.flagResolver;
|
||||||
this.logger = config.getLogger('api-token-controller.js');
|
this.logger = config.getLogger('api-token-controller.js');
|
||||||
@ -411,7 +411,7 @@ export class ApiTokenController extends Controller {
|
|||||||
extractUsername(req),
|
extractUsername(req),
|
||||||
req.user.id,
|
req.user.id,
|
||||||
);
|
);
|
||||||
await this.proxyService.deleteClientForProxyToken(token);
|
await this.frontendApiService.deleteClientForFrontendApiToken(token);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import { extractUsername } from '../../util/extract-user';
|
|||||||
import NotFoundError from '../../error/notfound-error';
|
import NotFoundError from '../../error/notfound-error';
|
||||||
import { SetUiConfigSchema } from '../../openapi/spec/set-ui-config-schema';
|
import { SetUiConfigSchema } from '../../openapi/spec/set-ui-config-schema';
|
||||||
import { createRequestSchema } from '../../openapi/util/create-request-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 MaintenanceService from '../../features/maintenance/maintenance-service';
|
||||||
import memoizee from 'memoizee';
|
import memoizee from 'memoizee';
|
||||||
import { minutesToMilliseconds } from 'date-fns';
|
import { minutesToMilliseconds } from 'date-fns';
|
||||||
@ -35,7 +35,7 @@ class ConfigController extends Controller {
|
|||||||
|
|
||||||
private settingService: SettingService;
|
private settingService: SettingService;
|
||||||
|
|
||||||
private proxyService: ProxyService;
|
private frontendApiService: FrontendApiService;
|
||||||
|
|
||||||
private emailService: EmailService;
|
private emailService: EmailService;
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class ConfigController extends Controller {
|
|||||||
settingService,
|
settingService,
|
||||||
emailService,
|
emailService,
|
||||||
openApiService,
|
openApiService,
|
||||||
proxyService,
|
frontendApiService,
|
||||||
maintenanceService,
|
maintenanceService,
|
||||||
clientInstanceService,
|
clientInstanceService,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
@ -63,7 +63,7 @@ class ConfigController extends Controller {
|
|||||||
| 'settingService'
|
| 'settingService'
|
||||||
| 'emailService'
|
| 'emailService'
|
||||||
| 'openApiService'
|
| 'openApiService'
|
||||||
| 'proxyService'
|
| 'frontendApiService'
|
||||||
| 'maintenanceService'
|
| 'maintenanceService'
|
||||||
| 'clientInstanceService'
|
| 'clientInstanceService'
|
||||||
>,
|
>,
|
||||||
@ -73,7 +73,7 @@ class ConfigController extends Controller {
|
|||||||
this.settingService = settingService;
|
this.settingService = settingService;
|
||||||
this.emailService = emailService;
|
this.emailService = emailService;
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
this.proxyService = proxyService;
|
this.frontendApiService = frontendApiService;
|
||||||
this.maintenanceService = maintenanceService;
|
this.maintenanceService = maintenanceService;
|
||||||
this.clientInstanceService = clientInstanceService;
|
this.clientInstanceService = clientInstanceService;
|
||||||
this.usesOldEdgeFunction = memoizee(
|
this.usesOldEdgeFunction = memoizee(
|
||||||
@ -136,7 +136,7 @@ class ConfigController extends Controller {
|
|||||||
maintenanceMode,
|
maintenanceMode,
|
||||||
usesOldEdge,
|
usesOldEdge,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
this.proxyService.getFrontendSettings(false),
|
this.frontendApiService.getFrontendSettings(false),
|
||||||
this.settingService.get<SimpleAuthSettings>(simpleAuthSettingsKey),
|
this.settingService.get<SimpleAuthSettings>(simpleAuthSettingsKey),
|
||||||
this.maintenanceService.isMaintenanceMode(),
|
this.maintenanceService.isMaintenanceMode(),
|
||||||
this.usesOldEdgeFunction(),
|
this.usesOldEdgeFunction(),
|
||||||
@ -190,7 +190,7 @@ class ConfigController extends Controller {
|
|||||||
res: Response<string>,
|
res: Response<string>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (req.body.frontendSettings) {
|
if (req.body.frontendSettings) {
|
||||||
await this.proxyService.setFrontendSettings(
|
await this.frontendApiService.setFrontendSettings(
|
||||||
req.body.frontendSettings,
|
req.body.frontendSettings,
|
||||||
extractUsername(req),
|
extractUsername(req),
|
||||||
req.user.id,
|
req.user.id,
|
||||||
|
@ -25,7 +25,7 @@ import {
|
|||||||
ApiTokenService,
|
ApiTokenService,
|
||||||
OpenApiService,
|
OpenApiService,
|
||||||
ProjectService,
|
ProjectService,
|
||||||
ProxyService,
|
FrontendApiService,
|
||||||
} from '../../../services';
|
} from '../../../services';
|
||||||
import { extractUserId, extractUsername } from '../../../util';
|
import { extractUserId, extractUsername } from '../../../util';
|
||||||
import { IAuthRequest } from '../../unleash-types';
|
import { IAuthRequest } from '../../unleash-types';
|
||||||
@ -48,7 +48,7 @@ export class ProjectApiTokenController extends Controller {
|
|||||||
|
|
||||||
private accessService: AccessService;
|
private accessService: AccessService;
|
||||||
|
|
||||||
private proxyService: ProxyService;
|
private frontendApiService: FrontendApiService;
|
||||||
|
|
||||||
private openApiService: OpenApiService;
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
@ -61,14 +61,14 @@ export class ProjectApiTokenController extends Controller {
|
|||||||
{
|
{
|
||||||
apiTokenService,
|
apiTokenService,
|
||||||
accessService,
|
accessService,
|
||||||
proxyService,
|
frontendApiService,
|
||||||
openApiService,
|
openApiService,
|
||||||
projectService,
|
projectService,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
| 'apiTokenService'
|
| 'apiTokenService'
|
||||||
| 'accessService'
|
| 'accessService'
|
||||||
| 'proxyService'
|
| 'frontendApiService'
|
||||||
| 'openApiService'
|
| 'openApiService'
|
||||||
| 'projectService'
|
| 'projectService'
|
||||||
>,
|
>,
|
||||||
@ -76,7 +76,7 @@ export class ProjectApiTokenController extends Controller {
|
|||||||
super(config);
|
super(config);
|
||||||
this.apiTokenService = apiTokenService;
|
this.apiTokenService = apiTokenService;
|
||||||
this.accessService = accessService;
|
this.accessService = accessService;
|
||||||
this.proxyService = proxyService;
|
this.frontendApiService = frontendApiService;
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
this.projectService = projectService;
|
this.projectService = projectService;
|
||||||
this.logger = config.getLogger('project-api-token-controller.js');
|
this.logger = config.getLogger('project-api-token-controller.js');
|
||||||
@ -226,7 +226,9 @@ export class ProjectApiTokenController extends Controller {
|
|||||||
extractUsername(req),
|
extractUsername(req),
|
||||||
user.id,
|
user.id,
|
||||||
);
|
);
|
||||||
await this.proxyService.deleteClientForProxyToken(token);
|
await this.frontendApiService.deleteClientForFrontendApiToken(
|
||||||
|
token,
|
||||||
|
);
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
} else if (!storedToken) {
|
} else if (!storedToken) {
|
||||||
res.status(404).end();
|
res.status(404).end();
|
||||||
|
@ -9,7 +9,7 @@ import { AdminApi } from './admin-api';
|
|||||||
import ClientApi from './client-api';
|
import ClientApi from './client-api';
|
||||||
|
|
||||||
import { HealthCheckController } from './health-check';
|
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 EdgeController from './edge-api';
|
||||||
import { PublicInviteController } from './public-invite';
|
import { PublicInviteController } from './public-invite';
|
||||||
import { Db } from '../db/db';
|
import { Db } from '../db/db';
|
||||||
|
@ -31,7 +31,7 @@ import { OpenApiService } from './openapi-service';
|
|||||||
import { ClientSpecService } from './client-spec-service';
|
import { ClientSpecService } from './client-spec-service';
|
||||||
import { PlaygroundService } from '../features/playground/playground-service';
|
import { PlaygroundService } from '../features/playground/playground-service';
|
||||||
import { GroupService } from './group-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 EdgeService from './edge-service';
|
||||||
import PatService from './pat-service';
|
import PatService from './pat-service';
|
||||||
import { PublicSignupTokenService } from './public-signup-token-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 { SegmentReadModel } from '../features/segment/segment-read-model';
|
||||||
import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model';
|
import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model';
|
||||||
import {
|
import {
|
||||||
createFakeProxyService,
|
createFakeFrontendApiService,
|
||||||
createProxyService,
|
createFrontendApiService,
|
||||||
} from '../proxy/createProxyService';
|
} from '../features/frontend-api/createFrontendApiService';
|
||||||
|
|
||||||
export const createServices = (
|
export const createServices = (
|
||||||
stores: IUnleashStores,
|
stores: IUnleashStores,
|
||||||
@ -295,14 +295,14 @@ export const createServices = (
|
|||||||
? createClientFeatureToggleService(db, config)
|
? createClientFeatureToggleService(db, config)
|
||||||
: createFakeClientFeatureToggleService(config);
|
: createFakeClientFeatureToggleService(config);
|
||||||
|
|
||||||
const proxyService = db
|
const frontendApiService = db
|
||||||
? createProxyService(
|
? createFrontendApiService(
|
||||||
db,
|
db,
|
||||||
config,
|
config,
|
||||||
clientMetricsServiceV2,
|
clientMetricsServiceV2,
|
||||||
configurationRevisionService,
|
configurationRevisionService,
|
||||||
)
|
)
|
||||||
: createFakeProxyService(
|
: createFakeFrontendApiService(
|
||||||
config,
|
config,
|
||||||
clientMetricsServiceV2,
|
clientMetricsServiceV2,
|
||||||
configurationRevisionService,
|
configurationRevisionService,
|
||||||
@ -373,7 +373,7 @@ export const createServices = (
|
|||||||
clientSpecService,
|
clientSpecService,
|
||||||
playgroundService,
|
playgroundService,
|
||||||
groupService,
|
groupService,
|
||||||
proxyService,
|
frontendApiService,
|
||||||
edgeService,
|
edgeService,
|
||||||
patService,
|
patService,
|
||||||
publicSignupTokenService,
|
publicSignupTokenService,
|
||||||
@ -428,7 +428,7 @@ export {
|
|||||||
ClientSpecService,
|
ClientSpecService,
|
||||||
PlaygroundService,
|
PlaygroundService,
|
||||||
GroupService,
|
GroupService,
|
||||||
ProxyService,
|
FrontendApiService,
|
||||||
EdgeService,
|
EdgeService,
|
||||||
PatService,
|
PatService,
|
||||||
PublicSignupTokenService,
|
PublicSignupTokenService,
|
||||||
|
@ -28,7 +28,7 @@ import { OpenApiService } from '../services/openapi-service';
|
|||||||
import { ClientSpecService } from '../services/client-spec-service';
|
import { ClientSpecService } from '../services/client-spec-service';
|
||||||
import { PlaygroundService } from '../features/playground/playground-service';
|
import { PlaygroundService } from '../features/playground/playground-service';
|
||||||
import { GroupService } from '../services/group-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 EdgeService from '../services/edge-service';
|
||||||
import PatService from '../services/pat-service';
|
import PatService from '../services/pat-service';
|
||||||
import { PublicSignupTokenService } from '../services/public-signup-token-service';
|
import { PublicSignupTokenService } from '../services/public-signup-token-service';
|
||||||
@ -76,7 +76,7 @@ export interface IUnleashServices {
|
|||||||
projectHealthService: ProjectHealthService;
|
projectHealthService: ProjectHealthService;
|
||||||
projectService: ProjectService;
|
projectService: ProjectService;
|
||||||
playgroundService: PlaygroundService;
|
playgroundService: PlaygroundService;
|
||||||
proxyService: ProxyService;
|
frontendApiService: FrontendApiService;
|
||||||
publicSignupTokenService: PublicSignupTokenService;
|
publicSignupTokenService: PublicSignupTokenService;
|
||||||
resetTokenService: ResetTokenService;
|
resetTokenService: ResetTokenService;
|
||||||
sessionService: SessionService;
|
sessionService: SessionService;
|
||||||
|
@ -57,7 +57,7 @@ test('gets ui config with disablePasswordAuth', async () => {
|
|||||||
|
|
||||||
test('gets ui config with frontendSettings', async () => {
|
test('gets ui config with frontendSettings', async () => {
|
||||||
const frontendApiOrigins = ['https://example.net'];
|
const frontendApiOrigins = ['https://example.net'];
|
||||||
await app.services.proxyService.setFrontendSettings(
|
await app.services.frontendApiService.setFrontendSettings(
|
||||||
{ frontendApiOrigins },
|
{ frontendApiOrigins },
|
||||||
randomId(),
|
randomId(),
|
||||||
-9999,
|
-9999,
|
||||||
|
Loading…
Reference in New Issue
Block a user