mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-02 01:17:58 +02:00
chore: add bulk endpoint for metrics and app registration for edge (#3079)
## About the changes Implementation of bulk metrics and registration endpoint. This will be used by edge nodes to send all collected information. Types around metrics were improved and `IClientApp.bucket` with type `any` is no longer needed --------- Co-authored-by: sighphyre <liquidwicked64@gmail.com>
This commit is contained in:
parent
232ad28661
commit
7a242ecf2a
@ -23,6 +23,7 @@ import { IUnleashStores } from './types/stores';
|
|||||||
import { hoursToMilliseconds, minutesToMilliseconds } from 'date-fns';
|
import { hoursToMilliseconds, minutesToMilliseconds } from 'date-fns';
|
||||||
import Timer = NodeJS.Timer;
|
import Timer = NodeJS.Timer;
|
||||||
import { InstanceStatsService } from './services/instance-stats-service';
|
import { InstanceStatsService } from './services/instance-stats-service';
|
||||||
|
import { ValidatedClientMetrics } from './services/client-metrics/schema';
|
||||||
|
|
||||||
export default class MetricsMonitor {
|
export default class MetricsMonitor {
|
||||||
timer?: Timer;
|
timer?: Timer;
|
||||||
@ -268,16 +269,13 @@ export default class MetricsMonitor {
|
|||||||
featureToggleUpdateTotal.labels(featureName, project, 'n/a').inc();
|
featureToggleUpdateTotal.labels(featureName, project, 'n/a').inc();
|
||||||
});
|
});
|
||||||
|
|
||||||
eventBus.on(CLIENT_METRICS, (m) => {
|
eventBus.on(CLIENT_METRICS, (m: ValidatedClientMetrics) => {
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
for (const entry of Object.entries(m.bucket.toggles)) {
|
for (const entry of Object.entries(m.bucket.toggles)) {
|
||||||
featureToggleUsageTotal
|
featureToggleUsageTotal
|
||||||
.labels(entry[0], 'true', m.appName)
|
.labels(entry[0], 'true', m.appName)
|
||||||
// @ts-expect-error
|
|
||||||
.inc(entry[1].yes);
|
.inc(entry[1].yes);
|
||||||
featureToggleUsageTotal
|
featureToggleUsageTotal
|
||||||
.labels(entry[0], 'false', m.appName)
|
.labels(entry[0], 'false', m.appName)
|
||||||
// @ts-expect-error
|
|
||||||
.inc(entry[1].no);
|
.inc(entry[1].no);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -135,6 +135,8 @@ import { openApiTags } from './util';
|
|||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
import apiVersion from '../util/version';
|
import apiVersion from '../util/version';
|
||||||
import { maintenanceSchema } from './spec/maintenance-schema';
|
import { maintenanceSchema } from './spec/maintenance-schema';
|
||||||
|
import { bulkRegistrationSchema } from './spec/bulk-registration-schema';
|
||||||
|
import { bulkMetricsSchema } from './spec/bulk-metrics-schema';
|
||||||
|
|
||||||
// All schemas in `openapi/spec` should be listed here.
|
// All schemas in `openapi/spec` should be listed here.
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
@ -147,6 +149,8 @@ export const schemas = {
|
|||||||
apiTokensSchema,
|
apiTokensSchema,
|
||||||
applicationSchema,
|
applicationSchema,
|
||||||
applicationsSchema,
|
applicationsSchema,
|
||||||
|
bulkRegistrationSchema,
|
||||||
|
bulkMetricsSchema,
|
||||||
changePasswordSchema,
|
changePasswordSchema,
|
||||||
clientApplicationSchema,
|
clientApplicationSchema,
|
||||||
clientFeatureSchema,
|
clientFeatureSchema,
|
||||||
|
32
src/lib/openapi/spec/bulk-metrics-schema.ts
Normal file
32
src/lib/openapi/spec/bulk-metrics-schema.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
import { bulkRegistrationSchema } from './bulk-registration-schema';
|
||||||
|
import { clientMetricsSchema } from './client-metrics-schema';
|
||||||
|
import { dateSchema } from './date-schema';
|
||||||
|
|
||||||
|
export const bulkMetricsSchema = {
|
||||||
|
$id: '#/components/schemas/bulkMetricsSchema',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
applications: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/bulkRegistrationSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
metrics: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: '#/components/schemas/clientMetricsSchema',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
schemas: {
|
||||||
|
bulkRegistrationSchema,
|
||||||
|
dateSchema,
|
||||||
|
clientMetricsSchema,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BulkMetricsSchema = FromSchema<typeof bulkMetricsSchema>;
|
44
src/lib/openapi/spec/bulk-registration-schema.ts
Normal file
44
src/lib/openapi/spec/bulk-registration-schema.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
export const bulkRegistrationSchema = {
|
||||||
|
$id: '#/components/schemas/bulkRegistrationSchema',
|
||||||
|
type: 'object',
|
||||||
|
required: ['appName', 'instanceId'],
|
||||||
|
properties: {
|
||||||
|
connectVia: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
appName: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
instanceId: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
interval: {
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
started: {
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
strategies: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sdkVersion: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
schemas: {},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type BulkRegistrationSchema = FromSchema<typeof bulkRegistrationSchema>;
|
@ -27,6 +27,21 @@ export const clientMetricsSchema = {
|
|||||||
},
|
},
|
||||||
toggles: {
|
toggles: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
example: {
|
||||||
|
myCoolToggle: {
|
||||||
|
yes: 25,
|
||||||
|
no: 42,
|
||||||
|
variants: {
|
||||||
|
blue: 6,
|
||||||
|
green: 15,
|
||||||
|
red: 46,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
myOtherToggle: {
|
||||||
|
yes: 0,
|
||||||
|
no: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
additionalProperties: {
|
additionalProperties: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -4,14 +4,18 @@ import { IUnleashConfig, IUnleashServices } from '../../types';
|
|||||||
import { Logger } from '../../logger';
|
import { Logger } from '../../logger';
|
||||||
import { NONE } from '../../types/permissions';
|
import { NONE } from '../../types/permissions';
|
||||||
import { createResponseSchema } from '../../openapi/util/create-response-schema';
|
import { createResponseSchema } from '../../openapi/util/create-response-schema';
|
||||||
import { RequestBody } from '../unleash-types';
|
import { IAuthRequest, RequestBody } from '../unleash-types';
|
||||||
import { createRequestSchema } from '../../openapi/util/create-request-schema';
|
import { createRequestSchema } from '../../openapi/util/create-request-schema';
|
||||||
import {
|
import {
|
||||||
validateEdgeTokensSchema,
|
validateEdgeTokensSchema,
|
||||||
ValidateEdgeTokensSchema,
|
ValidateEdgeTokensSchema,
|
||||||
} from '../../openapi/spec/validate-edge-tokens-schema';
|
} from '../../openapi/spec/validate-edge-tokens-schema';
|
||||||
|
import ClientInstanceService from '../../services/client-metrics/instance-service';
|
||||||
import EdgeService from '../../services/edge-service';
|
import EdgeService from '../../services/edge-service';
|
||||||
import { OpenApiService } from '../../services/openapi-service';
|
import { OpenApiService } from '../../services/openapi-service';
|
||||||
|
import { emptyResponse } from '../../openapi/util/standard-responses';
|
||||||
|
import { BulkMetricsSchema } from '../../openapi/spec/bulk-metrics-schema';
|
||||||
|
import ClientMetricsServiceV2 from '../../services/client-metrics/metrics-service-v2';
|
||||||
|
|
||||||
export default class EdgeController extends Controller {
|
export default class EdgeController extends Controller {
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
@ -20,17 +24,31 @@ export default class EdgeController extends Controller {
|
|||||||
|
|
||||||
private openApiService: OpenApiService;
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
|
private metricsV2: ClientMetricsServiceV2;
|
||||||
|
|
||||||
|
private clientInstanceService: ClientInstanceService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
{
|
{
|
||||||
edgeService,
|
edgeService,
|
||||||
openApiService,
|
openApiService,
|
||||||
}: Pick<IUnleashServices, 'edgeService' | 'openApiService'>,
|
clientMetricsServiceV2,
|
||||||
|
clientInstanceService,
|
||||||
|
}: Pick<
|
||||||
|
IUnleashServices,
|
||||||
|
| 'edgeService'
|
||||||
|
| 'openApiService'
|
||||||
|
| 'clientMetricsServiceV2'
|
||||||
|
| 'clientInstanceService'
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.logger = config.getLogger('edge-api/index.ts');
|
this.logger = config.getLogger('edge-api/index.ts');
|
||||||
this.edgeService = edgeService;
|
this.edgeService = edgeService;
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
|
this.metricsV2 = clientMetricsServiceV2;
|
||||||
|
this.clientInstanceService = clientInstanceService;
|
||||||
|
|
||||||
this.route({
|
this.route({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -50,6 +68,23 @@ export default class EdgeController extends Controller {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.route({
|
||||||
|
method: 'post',
|
||||||
|
path: '/metrics',
|
||||||
|
handler: this.bulkMetrics,
|
||||||
|
permission: NONE, // should have a permission but not bound to any environment
|
||||||
|
middleware: [
|
||||||
|
this.openApiService.validPath({
|
||||||
|
tags: ['Edge'],
|
||||||
|
operationId: 'bulkMetrics',
|
||||||
|
requestBody: createRequestSchema('bulkMetricsSchema'),
|
||||||
|
responses: {
|
||||||
|
202: emptyResponse,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getValidTokens(
|
async getValidTokens(
|
||||||
@ -66,4 +101,32 @@ export default class EdgeController extends Controller {
|
|||||||
tokens,
|
tokens,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async bulkMetrics(
|
||||||
|
req: IAuthRequest<void, void, BulkMetricsSchema>,
|
||||||
|
res: Response<void>,
|
||||||
|
): Promise<void> {
|
||||||
|
const { body, ip: clientIp } = req;
|
||||||
|
const { metrics, applications } = body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let promises: Promise<void>[] = [];
|
||||||
|
for (const app of applications) {
|
||||||
|
promises.push(
|
||||||
|
this.clientInstanceService.registerClient(app, clientIp),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (metrics) {
|
||||||
|
for (const metric of metrics) {
|
||||||
|
promises.push(
|
||||||
|
this.metricsV2.registerClientMetrics(metric, clientIp),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
res.status(202).end();
|
||||||
|
} catch (e) {
|
||||||
|
res.status(400).end();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Logger } from '../../logger';
|
import { Logger } from '../../logger';
|
||||||
import { IUnleashConfig } from '../../server-impl';
|
import { IUnleashConfig } from '../../server-impl';
|
||||||
import { IUnleashStores } from '../../types';
|
import { IUnleashStores } from '../../types';
|
||||||
import { IClientApp } from '../../types/model';
|
|
||||||
import { ToggleMetricsSummary } from '../../types/models/metrics';
|
import { ToggleMetricsSummary } from '../../types/models/metrics';
|
||||||
import {
|
import {
|
||||||
IClientMetricsEnv,
|
IClientMetricsEnv,
|
||||||
@ -13,7 +12,6 @@ import {
|
|||||||
hoursToMilliseconds,
|
hoursToMilliseconds,
|
||||||
secondsToMilliseconds,
|
secondsToMilliseconds,
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
import { IFeatureToggleStore } from '../../types/stores/feature-toggle-store';
|
|
||||||
import { CLIENT_METRICS } from '../../types/events';
|
import { CLIENT_METRICS } from '../../types/events';
|
||||||
import ApiUser from '../../types/api-user';
|
import ApiUser from '../../types/api-user';
|
||||||
import { ALL } from '../../types/models/api-token';
|
import { ALL } from '../../types/models/api-token';
|
||||||
@ -21,7 +19,7 @@ import User from '../../types/user';
|
|||||||
import { collapseHourlyMetrics } from '../../util/collapseHourlyMetrics';
|
import { collapseHourlyMetrics } from '../../util/collapseHourlyMetrics';
|
||||||
import { LastSeenService } from './last-seen-service';
|
import { LastSeenService } from './last-seen-service';
|
||||||
import { generateHourBuckets } from '../../util/time-utils';
|
import { generateHourBuckets } from '../../util/time-utils';
|
||||||
import { IFlagResolver } from '../../types/experimental';
|
import { ClientMetricsSchema } from 'lib/openapi';
|
||||||
|
|
||||||
export default class ClientMetricsServiceV2 {
|
export default class ClientMetricsServiceV2 {
|
||||||
private config: IUnleashConfig;
|
private config: IUnleashConfig;
|
||||||
@ -32,28 +30,19 @@ export default class ClientMetricsServiceV2 {
|
|||||||
|
|
||||||
private clientMetricsStoreV2: IClientMetricsStoreV2;
|
private clientMetricsStoreV2: IClientMetricsStoreV2;
|
||||||
|
|
||||||
private featureToggleStore: IFeatureToggleStore;
|
|
||||||
|
|
||||||
private lastSeenService: LastSeenService;
|
private lastSeenService: LastSeenService;
|
||||||
|
|
||||||
private flagResolver: IFlagResolver;
|
|
||||||
|
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{ clientMetricsStoreV2 }: Pick<IUnleashStores, 'clientMetricsStoreV2'>,
|
||||||
featureToggleStore,
|
|
||||||
clientMetricsStoreV2,
|
|
||||||
}: Pick<IUnleashStores, 'featureToggleStore' | 'clientMetricsStoreV2'>,
|
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
lastSeenService: LastSeenService,
|
lastSeenService: LastSeenService,
|
||||||
bulkInterval = secondsToMilliseconds(5),
|
bulkInterval = secondsToMilliseconds(5),
|
||||||
) {
|
) {
|
||||||
this.featureToggleStore = featureToggleStore;
|
|
||||||
this.clientMetricsStoreV2 = clientMetricsStoreV2;
|
this.clientMetricsStoreV2 = clientMetricsStoreV2;
|
||||||
this.lastSeenService = lastSeenService;
|
this.lastSeenService = lastSeenService;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.flagResolver = config.flagResolver;
|
|
||||||
this.logger = config.getLogger(
|
this.logger = config.getLogger(
|
||||||
'/services/client-metrics/client-metrics-service-v2.ts',
|
'/services/client-metrics/client-metrics-service-v2.ts',
|
||||||
);
|
);
|
||||||
@ -72,7 +61,7 @@ export default class ClientMetricsServiceV2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async registerClientMetrics(
|
async registerClientMetrics(
|
||||||
data: IClientApp,
|
data: ClientMetricsSchema,
|
||||||
clientIp: string,
|
clientIp: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const value = await clientMetricsSchema.validateAsync(data);
|
const value = await clientMetricsSchema.validateAsync(data);
|
||||||
@ -100,7 +89,6 @@ export default class ClientMetricsServiceV2 {
|
|||||||
...clientMetrics,
|
...clientMetrics,
|
||||||
]);
|
]);
|
||||||
this.lastSeenService.updateLastSeen(clientMetrics);
|
this.lastSeenService.updateLastSeen(clientMetrics);
|
||||||
|
|
||||||
this.config.eventBus.emit(CLIENT_METRICS, value);
|
this.config.eventBus.emit(CLIENT_METRICS, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +184,10 @@ export default class ClientMetricsServiceV2 {
|
|||||||
return result.sort((a, b) => compareAsc(a.timestamp, b.timestamp));
|
return result.sort((a, b) => compareAsc(a.timestamp, b.timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveMetricsEnvironment(user: User | ApiUser, data: IClientApp): string {
|
resolveMetricsEnvironment(
|
||||||
|
user: User | ApiUser,
|
||||||
|
data: { environment?: string },
|
||||||
|
): string {
|
||||||
if (user instanceof ApiUser) {
|
if (user instanceof ApiUser) {
|
||||||
if (user.environment !== ALL) {
|
if (user.environment !== ALL) {
|
||||||
return user.environment;
|
return user.environment;
|
||||||
|
@ -12,6 +12,17 @@ test('clientRegisterSchema should allow empty ("") instanceId', () => {
|
|||||||
expect(value.instanceId).toBe('default');
|
expect(value.instanceId).toBe('default');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('clientRegisterSchema should allow string dates', () => {
|
||||||
|
const date = new Date();
|
||||||
|
const { value } = clientRegisterSchema.validate({
|
||||||
|
appName: 'test',
|
||||||
|
strategies: ['default'],
|
||||||
|
started: date.toISOString(),
|
||||||
|
interval: 100,
|
||||||
|
});
|
||||||
|
expect(value.started).toStrictEqual(date);
|
||||||
|
});
|
||||||
|
|
||||||
test('clientRegisterSchema should allow undefined instanceId', () => {
|
test('clientRegisterSchema should allow undefined instanceId', () => {
|
||||||
const { value } = clientRegisterSchema.validate({
|
const { value } = clientRegisterSchema.validate({
|
||||||
appName: 'test',
|
appName: 'test',
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import joi from 'joi';
|
import joi from 'joi';
|
||||||
|
import { IMetricsBucket } from 'lib/types';
|
||||||
|
|
||||||
const countSchema = joi
|
const countSchema = joi
|
||||||
.object()
|
.object()
|
||||||
@ -9,8 +10,16 @@ const countSchema = joi
|
|||||||
variants: joi.object().pattern(joi.string(), joi.number().min(0)),
|
variants: joi.object().pattern(joi.string(), joi.number().min(0)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// validated type from client-metrics-schema.ts with default values
|
||||||
|
export type ValidatedClientMetrics = {
|
||||||
|
environment?: string;
|
||||||
|
appName: string;
|
||||||
|
instanceId: string;
|
||||||
|
bucket: IMetricsBucket;
|
||||||
|
};
|
||||||
|
|
||||||
export const clientMetricsSchema = joi
|
export const clientMetricsSchema = joi
|
||||||
.object()
|
.object<ValidatedClientMetrics>()
|
||||||
.options({ stripUnknown: true })
|
.options({ stripUnknown: true })
|
||||||
.keys({
|
.keys({
|
||||||
environment: joi.string().optional(),
|
environment: joi.string().optional(),
|
||||||
|
@ -307,7 +307,6 @@ export interface IClientApp {
|
|||||||
seenToggles?: string[];
|
seenToggles?: string[];
|
||||||
metricsCount?: number;
|
metricsCount?: number;
|
||||||
strategies?: string[] | Record<string, string>[];
|
strategies?: string[] | Record<string, string>[];
|
||||||
bucket?: any;
|
|
||||||
count?: number;
|
count?: number;
|
||||||
started?: string | number | Date;
|
started?: string | number | Date;
|
||||||
interval?: number;
|
interval?: number;
|
||||||
@ -342,7 +341,7 @@ export interface IMetricCounts {
|
|||||||
export interface IMetricsBucket {
|
export interface IMetricsBucket {
|
||||||
start: Date;
|
start: Date;
|
||||||
stop: Date;
|
stop: Date;
|
||||||
toggles: IMetricCounts;
|
toggles: { [key: string]: IMetricCounts };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IImportFile extends ImportCommon {
|
export interface IImportFile extends ImportCommon {
|
||||||
|
@ -328,6 +328,62 @@ exports[`should serve the OpenAPI spec 1`] = `
|
|||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
"bulkMetricsSchema": {
|
||||||
|
"properties": {
|
||||||
|
"applications": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/bulkRegistrationSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/clientMetricsSchema",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
|
"bulkRegistrationSchema": {
|
||||||
|
"properties": {
|
||||||
|
"appName": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"connectVia": {
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"instanceId": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"interval": {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
"sdkVersion": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"started": {
|
||||||
|
"type": "number",
|
||||||
|
},
|
||||||
|
"strategies": {
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"appName",
|
||||||
|
"instanceId",
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
},
|
||||||
"changePasswordSchema": {
|
"changePasswordSchema": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -534,6 +590,21 @@ exports[`should serve the OpenAPI spec 1`] = `
|
|||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
|
"example": {
|
||||||
|
"myCoolToggle": {
|
||||||
|
"no": 42,
|
||||||
|
"variants": {
|
||||||
|
"blue": 6,
|
||||||
|
"green": 15,
|
||||||
|
"red": 46,
|
||||||
|
},
|
||||||
|
"yes": 25,
|
||||||
|
},
|
||||||
|
"myOtherToggle": {
|
||||||
|
"no": 100,
|
||||||
|
"yes": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -8326,6 +8397,30 @@ If the provided project does not exist, the list of events will be empty.",
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"/edge/metrics": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "bulkMetrics",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/bulkMetricsSchema",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"description": "bulkMetricsSchema",
|
||||||
|
"required": true,
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"202": {
|
||||||
|
"description": "This response has no body.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"Edge",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
"/edge/validate": {
|
"/edge/validate": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "getValidTokens",
|
"operationId": "getValidTokens",
|
||||||
|
Loading…
Reference in New Issue
Block a user