From b04545c25f38f62caf521c965ab25e430fff64ea Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Thu, 6 Jul 2023 10:57:09 +0200 Subject: [PATCH] docs: Events tag (#4152) ### What This PR adds documentation for our endpoints that are covered by our "Events" tag. It also adds a type for all valid events, and then uses this as valid values for type argument. --- src/lib/db/event-store.ts | 9 +- src/lib/openapi/meta-schema-rules.test.ts | 7 - src/lib/openapi/spec/event-schema.ts | 105 +++++- src/lib/openapi/spec/events-schema.ts | 8 + src/lib/openapi/spec/feature-events-schema.ts | 15 +- src/lib/openapi/spec/search-events-schema.ts | 11 + src/lib/routes/admin-api/event.ts | 5 +- src/lib/types/events.ts | 309 ++++++++++++------ src/test/e2e/api/openapi/openapi.e2e.test.ts | 2 - .../e2e/services/user-service.e2e.test.ts | 5 +- src/test/e2e/stores/event-store.e2e.test.ts | 2 +- 11 files changed, 360 insertions(+), 118 deletions(-) diff --git a/src/lib/db/event-store.ts b/src/lib/db/event-store.ts index 7af1977027..26511fd99d 100644 --- a/src/lib/db/event-store.ts +++ b/src/lib/db/event-store.ts @@ -1,4 +1,9 @@ -import { IEvent, IBaseEvent, SEGMENT_UPDATED } from '../types/events'; +import { + IEvent, + IBaseEvent, + SEGMENT_UPDATED, + IEventType, +} from '../types/events'; import { LogProvider, Logger } from '../logger'; import { IEventStore } from '../types/stores/event-store'; import { ITag } from '../types/model'; @@ -359,7 +364,7 @@ class EventStore implements IEventStore { rowToEvent(row: IEventTable): IEvent { return { id: row.id, - type: row.type, + type: row.type as IEventType, createdBy: row.created_by, createdAt: row.created_at, data: row.data, diff --git a/src/lib/openapi/meta-schema-rules.test.ts b/src/lib/openapi/meta-schema-rules.test.ts index a198fb8c79..1a83e28130 100644 --- a/src/lib/openapi/meta-schema-rules.test.ts +++ b/src/lib/openapi/meta-schema-rules.test.ts @@ -97,10 +97,7 @@ const metaRules: Rule[] = [ 'createInvitedUserSchema', 'environmentsSchema', 'environmentsProjectSchema', - 'eventSchema', - 'eventsSchema', 'featureEnvironmentSchema', - 'featureEventsSchema', 'featureSchema', 'featuresSchema', 'featureStrategySegmentSchema', @@ -126,7 +123,6 @@ const metaRules: Rule[] = [ 'resetPasswordSchema', 'requestsPerSecondSchema', 'sdkContextSchema', - 'searchEventsSchema', 'setUiConfigSchema', 'splashSchema', 'stateSchema', @@ -169,9 +165,6 @@ const metaRules: Rule[] = [ 'createInvitedUserSchema', 'dateSchema', 'environmentsSchema', - 'eventSchema', - 'eventsSchema', - 'featureEventsSchema', 'featureSchema', 'featuresSchema', 'featureStrategySegmentSchema', diff --git a/src/lib/openapi/spec/event-schema.ts b/src/lib/openapi/spec/event-schema.ts index 28c74b2df4..9dd6cac18e 100644 --- a/src/lib/openapi/spec/event-schema.ts +++ b/src/lib/openapi/spec/event-schema.ts @@ -1,51 +1,152 @@ import { FromSchema } from 'json-schema-to-ts'; import { tagSchema } from './tag-schema'; +import { IEventTypes } from '../../types'; +import { variantSchema } from './variant-schema'; +const eventDataSchema = { + type: 'object', + additionalProperties: true, + properties: { + name: { + type: 'string', + description: + 'Name of the feature toggle/strategy/environment that this event relates to', + example: 'my.first.toggle', + }, + description: { + type: 'string', + description: 'The description of the object this event relates to', + example: 'Toggle description', + }, + type: { + type: 'string', + description: + 'If this event relates to a feature toggle, the type of feature toggle.', + example: 'release', + }, + project: { + type: 'string', + description: 'The project this event relates to', + example: 'default', + }, + stale: { + description: 'Is the feature toggle this event relates to stale', + type: 'boolean', + example: true, + }, + variants: { + description: 'Variants configured for this toggle', + type: 'array', + items: { + $ref: '#/components/schemas/variantSchema', + }, + }, + createdAt: { + type: 'string', + format: 'date-time', + description: + 'The time the event happened as a RFC 3339-conformant timestamp.', + example: '2023-07-05T12:56:00.000Z', + }, + lastSeenAt: { + type: 'string', + format: 'date-time', + description: 'The time the feature was last seen', + example: '2023-07-05T12:56:00.000Z', + nullable: true, + }, + impressionData: { + description: + 'Should [impression events](https://docs.getunleash.io/reference/impression-data) activate for this feature toggle', + type: 'boolean', + example: false, + }, + }, + description: + 'Extra associated data related to the event, such as feature toggle state, segment configuration, etc., if applicable.', + example: { + name: 'new-feature', + description: 'Toggle description', + type: 'release', + project: 'my-project', + stale: false, + variants: [], + createdAt: '2022-05-31T13:32:20.547Z', + lastSeenAt: null, + impressionData: true, + }, +} as const; export const eventSchema = { $id: '#/components/schemas/eventSchema', type: 'object', additionalProperties: false, required: ['id', 'createdAt', 'type', 'createdBy'], + description: 'An event describing something happening in the system', properties: { id: { type: 'integer', minimum: 1, + description: 'The ID of the event. An increasing natural number.', }, createdAt: { type: 'string', format: 'date-time', + description: + 'The time the event happened as a RFC 3339-conformant timestamp.', + example: '2023-07-05T12:56:00.000Z', }, type: { type: 'string', + description: + 'What [type](https://docs.getunleash.io/reference/api/legacy/unleash/admin/events#event-type-description) of event this is', + enum: IEventTypes, + example: 'feature-created', }, createdBy: { type: 'string', + description: 'Which user created this event', + example: 'johndoe', }, environment: { type: 'string', + description: + 'The feature toggle environment the event relates to, if applicable.', nullable: true, + example: 'development', }, project: { type: 'string', nullable: true, + description: 'The project the event relates to, if applicable.', + example: 'default', }, featureName: { type: 'string', nullable: true, + description: + 'The name of the feature toggle the event relates to, if applicable.', + example: 'my.first.feature', + }, + data: eventDataSchema, + preData: { + ...eventDataSchema, + description: + "Data relating to the previous state of the event's subject.", + nullable: true, }, - data: { type: 'object', nullable: true }, - preData: { type: 'object', nullable: true }, tags: { type: 'array', items: { $ref: tagSchema.$id, }, nullable: true, + description: 'Any tags related to the event, if applicable.', }, }, components: { schemas: { tagSchema, + variantSchema, }, }, } as const; diff --git a/src/lib/openapi/spec/events-schema.ts b/src/lib/openapi/spec/events-schema.ts index 912d8981e5..000557f103 100644 --- a/src/lib/openapi/spec/events-schema.ts +++ b/src/lib/openapi/spec/events-schema.ts @@ -7,18 +7,26 @@ export const eventsSchema = { type: 'object', additionalProperties: false, required: ['version', 'events'], + description: 'A list of events that has happened in the system', properties: { version: { type: 'integer', minimum: 1, + enum: [1], + description: + 'The api version of this response. A natural increasing number. Only increases if format changes', + example: 1, }, events: { + description: 'The list of events', type: 'array', items: { $ref: eventSchema.$id }, }, totalEvents: { type: 'integer', + description: 'The total count of events', minimum: 0, + example: 842, }, }, components: { diff --git a/src/lib/openapi/spec/feature-events-schema.ts b/src/lib/openapi/spec/feature-events-schema.ts index 1c412184f6..e1b98bf073 100644 --- a/src/lib/openapi/spec/feature-events-schema.ts +++ b/src/lib/openapi/spec/feature-events-schema.ts @@ -7,18 +7,31 @@ export const featureEventsSchema = { type: 'object', additionalProperties: false, required: ['events'], + description: 'One or more events happening to a specific feature toggle', properties: { - version: { type: 'number' }, + version: { + type: 'integer', + description: 'An API versioning number', + minimum: 1, + enum: [1], + example: 1, + }, toggleName: { + description: + 'The name of the feature toggle these events relate to', type: 'string', + example: 'my.first.feature.toggle', }, events: { + description: 'The list of events', type: 'array', items: { $ref: eventSchema.$id }, }, totalEvents: { + description: 'How many events are there for this feature toggle', type: 'integer', minimum: 0, + example: 13, }, }, components: { diff --git a/src/lib/openapi/spec/search-events-schema.ts b/src/lib/openapi/spec/search-events-schema.ts index f1d187a343..5567278300 100644 --- a/src/lib/openapi/spec/search-events-schema.ts +++ b/src/lib/openapi/spec/search-events-schema.ts @@ -1,4 +1,5 @@ import { FromSchema } from 'json-schema-to-ts'; +import { IEventTypes } from '../../types'; export const searchEventsSchema = { $id: '#/components/schemas/searchEventsSchema', @@ -11,14 +12,18 @@ export const searchEventsSchema = { type: { type: 'string', description: 'Find events by event type (case-sensitive).', + enum: IEventTypes, + example: 'feature-created', }, project: { type: 'string', description: 'Find events by project ID (case-sensitive).', + example: 'default', }, feature: { type: 'string', description: 'Find events by feature toggle name (case-sensitive).', + example: 'my.first.toggle', }, query: { type: 'string', @@ -28,17 +33,23 @@ export const searchEventsSchema = { the username or email that created the event (if any), and the event data payload (if any). `, + example: 'admin@example.com', }, limit: { type: 'integer', + description: + 'The maximum amount of events to return in the search result', minimum: 1, maximum: 100, default: 100, + example: 50, }, offset: { + description: 'Which event id to start listing from', type: 'integer', minimum: 0, default: 0, + example: 100, }, }, components: {}, diff --git a/src/lib/routes/admin-api/event.ts b/src/lib/routes/admin-api/event.ts index dd54bbaa06..107f54def6 100644 --- a/src/lib/routes/admin-api/event.ts +++ b/src/lib/routes/admin-api/event.ts @@ -23,7 +23,7 @@ import { SearchEventsSchema } from '../../openapi/spec/search-events-schema'; import { IFlagResolver } from '../../types/experimental'; const ANON_KEYS = ['email', 'username', 'createdBy']; -const version = 1; +const version = 1 as const; export default class EventController extends Controller { private eventService: EventService; @@ -104,6 +104,9 @@ export default class EventController extends Controller { openApiService.validPath({ operationId: 'searchEvents', tags: ['Events'], + summary: 'Search for events', + description: + 'Allows searching for events matching the search criteria in the request body', requestBody: createRequestSchema('searchEventsSchema'), responses: { 200: createResponseSchema('eventsSchema') }, }), diff --git a/src/lib/types/events.ts b/src/lib/types/events.ts index c5a973da0c..40b4a20938 100644 --- a/src/lib/types/events.ts +++ b/src/lib/types/events.ts @@ -3,115 +3,222 @@ import { FeatureToggle, IStrategyConfig, ITag, IVariant } from './model'; import { IApiToken } from './models/api-token'; import { IUser } from './user'; -export const APPLICATION_CREATED = 'application-created'; +export const APPLICATION_CREATED = 'application-created' as const; // feature event types -export const FEATURE_CREATED = 'feature-created'; -export const FEATURE_DELETED = 'feature-deleted'; -export const FEATURE_UPDATED = 'feature-updated'; -export const FEATURE_METADATA_UPDATED = 'feature-metadata-updated'; -export const FEATURE_VARIANTS_UPDATED = 'feature-variants-updated'; +export const FEATURE_CREATED = 'feature-created' as const; +export const FEATURE_DELETED = 'feature-deleted' as const; +export const FEATURE_UPDATED = 'feature-updated' as const; +export const FEATURE_METADATA_UPDATED = 'feature-metadata-updated' as const; +export const FEATURE_VARIANTS_UPDATED = 'feature-variants-updated' as const; export const FEATURE_ENVIRONMENT_VARIANTS_UPDATED = - 'feature-environment-variants-updated'; -export const FEATURE_PROJECT_CHANGE = 'feature-project-change'; -export const FEATURE_ARCHIVED = 'feature-archived'; -export const FEATURE_REVIVED = 'feature-revived'; -export const FEATURE_IMPORT = 'feature-import'; -export const FEATURE_TAGGED = 'feature-tagged'; -export const FEATURE_TAG_IMPORT = 'feature-tag-import'; -export const FEATURE_STRATEGY_UPDATE = 'feature-strategy-update'; -export const FEATURE_STRATEGY_ADD = 'feature-strategy-add'; -export const FEATURE_STRATEGY_REMOVE = 'feature-strategy-remove'; -export const DROP_FEATURE_TAGS = 'drop-feature-tags'; -export const FEATURE_UNTAGGED = 'feature-untagged'; -export const FEATURE_STALE_ON = 'feature-stale-on'; -export const FEATURE_STALE_OFF = 'feature-stale-off'; -export const DROP_FEATURES = 'drop-features'; -export const FEATURE_ENVIRONMENT_ENABLED = 'feature-environment-enabled'; -export const FEATURE_ENVIRONMENT_DISABLED = 'feature-environment-disabled'; + 'feature-environment-variants-updated' as const; +export const FEATURE_PROJECT_CHANGE = 'feature-project-change' as const; +export const FEATURE_ARCHIVED = 'feature-archived' as const; +export const FEATURE_REVIVED = 'feature-revived' as const; +export const FEATURE_IMPORT = 'feature-import' as const; +export const FEATURE_TAGGED = 'feature-tagged' as const; +export const FEATURE_TAG_IMPORT = 'feature-tag-import' as const; +export const FEATURE_STRATEGY_UPDATE = 'feature-strategy-update' as const; +export const FEATURE_STRATEGY_ADD = 'feature-strategy-add' as const; +export const FEATURE_STRATEGY_REMOVE = 'feature-strategy-remove' as const; +export const DROP_FEATURE_TAGS = 'drop-feature-tags' as const; +export const FEATURE_UNTAGGED = 'feature-untagged' as const; +export const FEATURE_STALE_ON = 'feature-stale-on' as const; +export const FEATURE_STALE_OFF = 'feature-stale-off' as const; +export const DROP_FEATURES = 'drop-features' as const; +export const FEATURE_ENVIRONMENT_ENABLED = + 'feature-environment-enabled' as const; +export const FEATURE_ENVIRONMENT_DISABLED = + 'feature-environment-disabled' as const; -export const STRATEGY_CREATED = 'strategy-created'; -export const STRATEGY_DELETED = 'strategy-deleted'; -export const STRATEGY_DEPRECATED = 'strategy-deprecated'; -export const STRATEGY_REACTIVATED = 'strategy-reactivated'; -export const STRATEGY_UPDATED = 'strategy-updated'; -export const STRATEGY_IMPORT = 'strategy-import'; -export const DROP_STRATEGIES = 'drop-strategies'; -export const CONTEXT_FIELD_CREATED = 'context-field-created'; -export const CONTEXT_FIELD_UPDATED = 'context-field-updated'; -export const CONTEXT_FIELD_DELETED = 'context-field-deleted'; -export const PROJECT_ACCESS_ADDED = 'project-access-added'; -export const PROJECT_CREATED = 'project-created'; -export const PROJECT_UPDATED = 'project-updated'; -export const PROJECT_DELETED = 'project-deleted'; -export const PROJECT_IMPORT = 'project-import'; -export const PROJECT_USER_ADDED = 'project-user-added'; -export const PROJECT_USER_REMOVED = 'project-user-removed'; -export const PROJECT_USER_ROLE_CHANGED = 'project-user-role-changed'; -export const PROJECT_GROUP_ADDED = 'project-group-added'; -export const PROJECT_GROUP_REMOVED = 'project-group-removed'; -export const PROJECT_GROUP_ROLE_CHANGED = 'project-group-role-changed'; -export const DROP_PROJECTS = 'drop-projects'; -export const TAG_CREATED = 'tag-created'; -export const TAG_DELETED = 'tag-deleted'; -export const TAG_IMPORT = 'tag-import'; -export const DROP_TAGS = 'drop-tags'; -export const TAG_TYPE_CREATED = 'tag-type-created'; -export const TAG_TYPE_DELETED = 'tag-type-deleted'; -export const TAG_TYPE_UPDATED = 'tag-type-updated'; -export const TAG_TYPE_IMPORT = 'tag-type-import'; -export const DROP_TAG_TYPES = 'drop-tag-types'; -export const ADDON_CONFIG_CREATED = 'addon-config-created'; -export const ADDON_CONFIG_UPDATED = 'addon-config-updated'; -export const ADDON_CONFIG_DELETED = 'addon-config-deleted'; -export const DB_POOL_UPDATE = 'db-pool-update'; -export const USER_CREATED = 'user-created'; -export const USER_UPDATED = 'user-updated'; -export const USER_DELETED = 'user-deleted'; -export const DROP_ENVIRONMENTS = 'drop-environments'; -export const ENVIRONMENT_IMPORT = 'environment-import'; -export const SEGMENT_CREATED = 'segment-created'; -export const SEGMENT_UPDATED = 'segment-updated'; -export const SEGMENT_DELETED = 'segment-deleted'; -export const GROUP_CREATED = 'group-created'; -export const GROUP_UPDATED = 'group-updated'; -export const SETTING_CREATED = 'setting-created'; -export const SETTING_UPDATED = 'setting-updated'; -export const SETTING_DELETED = 'setting-deleted'; +export const STRATEGY_CREATED = 'strategy-created' as const; +export const STRATEGY_DELETED = 'strategy-deleted' as const; +export const STRATEGY_DEPRECATED = 'strategy-deprecated' as const; +export const STRATEGY_REACTIVATED = 'strategy-reactivated' as const; +export const STRATEGY_UPDATED = 'strategy-updated' as const; +export const STRATEGY_IMPORT = 'strategy-import' as const; +export const DROP_STRATEGIES = 'drop-strategies' as const; +export const CONTEXT_FIELD_CREATED = 'context-field-created' as const; +export const CONTEXT_FIELD_UPDATED = 'context-field-updated' as const; +export const CONTEXT_FIELD_DELETED = 'context-field-deleted' as const; +export const PROJECT_ACCESS_ADDED = 'project-access-added' as const; +export const PROJECT_CREATED = 'project-created' as const; +export const PROJECT_UPDATED = 'project-updated' as const; +export const PROJECT_DELETED = 'project-deleted' as const; +export const PROJECT_IMPORT = 'project-import' as const; +export const PROJECT_USER_ADDED = 'project-user-added' as const; +export const PROJECT_USER_REMOVED = 'project-user-removed' as const; +export const PROJECT_USER_ROLE_CHANGED = 'project-user-role-changed' as const; +export const PROJECT_GROUP_ADDED = 'project-group-added' as const; +export const PROJECT_GROUP_REMOVED = 'project-group-removed' as const; +export const PROJECT_GROUP_ROLE_CHANGED = 'project-group-role-changed' as const; +export const DROP_PROJECTS = 'drop-projects' as const; +export const TAG_CREATED = 'tag-created' as const; +export const TAG_DELETED = 'tag-deleted' as const; +export const TAG_IMPORT = 'tag-import' as const; +export const DROP_TAGS = 'drop-tags' as const; +export const TAG_TYPE_CREATED = 'tag-type-created' as const; +export const TAG_TYPE_DELETED = 'tag-type-deleted' as const; +export const TAG_TYPE_UPDATED = 'tag-type-updated' as const; +export const TAG_TYPE_IMPORT = 'tag-type-import' as const; +export const DROP_TAG_TYPES = 'drop-tag-types' as const; +export const ADDON_CONFIG_CREATED = 'addon-config-created' as const; +export const ADDON_CONFIG_UPDATED = 'addon-config-updated' as const; +export const ADDON_CONFIG_DELETED = 'addon-config-deleted' as const; +export const DB_POOL_UPDATE = 'db-pool-update' as const; +export const USER_CREATED = 'user-created' as const; +export const USER_UPDATED = 'user-updated' as const; +export const USER_DELETED = 'user-deleted' as const; +export const DROP_ENVIRONMENTS = 'drop-environments' as const; +export const ENVIRONMENT_IMPORT = 'environment-import' as const; +export const SEGMENT_CREATED = 'segment-created' as const; +export const SEGMENT_UPDATED = 'segment-updated' as const; +export const SEGMENT_DELETED = 'segment-deleted' as const; +export const GROUP_CREATED = 'group-created' as const; +export const GROUP_UPDATED = 'group-updated' as const; +export const SETTING_CREATED = 'setting-created' as const; +export const SETTING_UPDATED = 'setting-updated' as const; +export const SETTING_DELETED = 'setting-deleted' as const; -export const CLIENT_METRICS = 'client-metrics'; -export const CLIENT_REGISTER = 'client-register'; +export const CLIENT_METRICS = 'client-metrics' as const; +export const CLIENT_REGISTER = 'client-register' as const; -export const PAT_CREATED = 'pat-created'; -export const PAT_DELETED = 'pat-deleted'; +export const PAT_CREATED = 'pat-created' as const; +export const PAT_DELETED = 'pat-deleted' as const; -export const PUBLIC_SIGNUP_TOKEN_CREATED = 'public-signup-token-created'; -export const PUBLIC_SIGNUP_TOKEN_USER_ADDED = 'public-signup-token-user-added'; -export const PUBLIC_SIGNUP_TOKEN_TOKEN_UPDATED = 'public-signup-token-updated'; +export const PUBLIC_SIGNUP_TOKEN_CREATED = + 'public-signup-token-created' as const; +export const PUBLIC_SIGNUP_TOKEN_USER_ADDED = + 'public-signup-token-user-added' as const; +export const PUBLIC_SIGNUP_TOKEN_TOKEN_UPDATED = + 'public-signup-token-updated' as const; -export const CHANGE_REQUEST_CREATED = 'change-request-created'; -export const CHANGE_REQUEST_DISCARDED = 'change-request-discarded'; -export const CHANGE_ADDED = 'change-added'; -export const CHANGE_DISCARDED = 'change-discarded'; -export const CHANGE_REQUEST_APPROVED = 'change-request-approved'; -export const CHANGE_REQUEST_APPROVAL_ADDED = 'change-request-approval-added'; -export const CHANGE_REQUEST_CANCELLED = 'change-request-cancelled'; -export const CHANGE_REQUEST_SENT_TO_REVIEW = 'change-request-sent-to-review'; -export const CHANGE_REQUEST_APPLIED = 'change-request-applied'; +export const CHANGE_REQUEST_CREATED = 'change-request-created' as const; +export const CHANGE_REQUEST_DISCARDED = 'change-request-discarded' as const; +export const CHANGE_ADDED = 'change-added' as const; +export const CHANGE_DISCARDED = 'change-discarded' as const; +export const CHANGE_REQUEST_APPROVED = 'change-request-approved' as const; +export const CHANGE_REQUEST_APPROVAL_ADDED = + 'change-request-approval-added' as const; +export const CHANGE_REQUEST_CANCELLED = 'change-request-cancelled' as const; +export const CHANGE_REQUEST_SENT_TO_REVIEW = + 'change-request-sent-to-review' as const; +export const CHANGE_REQUEST_APPLIED = 'change-request-applied' as const; -export const API_TOKEN_CREATED = 'api-token-created'; -export const API_TOKEN_UPDATED = 'api-token-updated'; -export const API_TOKEN_DELETED = 'api-token-deleted'; +export const API_TOKEN_CREATED = 'api-token-created' as const; +export const API_TOKEN_UPDATED = 'api-token-updated' as const; +export const API_TOKEN_DELETED = 'api-token-deleted' as const; -export const FEATURE_FAVORITED = 'feature-favorited'; -export const FEATURE_UNFAVORITED = 'feature-unfavorited'; -export const PROJECT_FAVORITED = 'project-favorited'; -export const PROJECT_UNFAVORITED = 'project-unfavorited'; -export const FEATURES_EXPORTED = 'features-exported'; -export const FEATURES_IMPORTED = 'features-imported'; +export const FEATURE_FAVORITED = 'feature-favorited' as const; +export const FEATURE_UNFAVORITED = 'feature-unfavorited' as const; +export const PROJECT_FAVORITED = 'project-favorited' as const; +export const PROJECT_UNFAVORITED = 'project-unfavorited' as const; +export const FEATURES_EXPORTED = 'features-exported' as const; +export const FEATURES_IMPORTED = 'features-imported' as const; + +export const IEventTypes = [ + APPLICATION_CREATED, + FEATURE_CREATED, + FEATURE_DELETED, + FEATURE_UPDATED, + FEATURE_METADATA_UPDATED, + FEATURE_VARIANTS_UPDATED, + FEATURE_ENVIRONMENT_VARIANTS_UPDATED, + FEATURE_PROJECT_CHANGE, + FEATURE_ARCHIVED, + FEATURE_REVIVED, + FEATURE_IMPORT, + FEATURE_TAGGED, + FEATURE_TAG_IMPORT, + FEATURE_STRATEGY_UPDATE, + FEATURE_STRATEGY_ADD, + FEATURE_STRATEGY_REMOVE, + DROP_FEATURE_TAGS, + FEATURE_UNTAGGED, + FEATURE_STALE_ON, + FEATURE_STALE_OFF, + DROP_FEATURES, + FEATURE_ENVIRONMENT_ENABLED, + FEATURE_ENVIRONMENT_DISABLED, + STRATEGY_CREATED, + STRATEGY_DELETED, + STRATEGY_DEPRECATED, + STRATEGY_REACTIVATED, + STRATEGY_UPDATED, + STRATEGY_IMPORT, + DROP_STRATEGIES, + CONTEXT_FIELD_CREATED, + CONTEXT_FIELD_UPDATED, + CONTEXT_FIELD_DELETED, + PROJECT_ACCESS_ADDED, + PROJECT_CREATED, + PROJECT_UPDATED, + PROJECT_DELETED, + PROJECT_IMPORT, + PROJECT_USER_ADDED, + PROJECT_USER_REMOVED, + PROJECT_USER_ROLE_CHANGED, + PROJECT_GROUP_ROLE_CHANGED, + PROJECT_GROUP_ADDED, + PROJECT_GROUP_REMOVED, + DROP_PROJECTS, + TAG_CREATED, + TAG_DELETED, + TAG_IMPORT, + DROP_TAGS, + TAG_TYPE_CREATED, + TAG_TYPE_DELETED, + TAG_TYPE_UPDATED, + TAG_TYPE_IMPORT, + DROP_TAG_TYPES, + ADDON_CONFIG_CREATED, + ADDON_CONFIG_UPDATED, + ADDON_CONFIG_DELETED, + DB_POOL_UPDATE, + USER_CREATED, + USER_UPDATED, + USER_DELETED, + DROP_ENVIRONMENTS, + ENVIRONMENT_IMPORT, + SEGMENT_CREATED, + SEGMENT_UPDATED, + SEGMENT_DELETED, + GROUP_CREATED, + GROUP_UPDATED, + SETTING_CREATED, + SETTING_UPDATED, + SETTING_DELETED, + CLIENT_METRICS, + CLIENT_REGISTER, + PAT_CREATED, + PAT_DELETED, + PUBLIC_SIGNUP_TOKEN_CREATED, + PUBLIC_SIGNUP_TOKEN_USER_ADDED, + PUBLIC_SIGNUP_TOKEN_TOKEN_UPDATED, + CHANGE_REQUEST_CREATED, + CHANGE_REQUEST_DISCARDED, + CHANGE_ADDED, + CHANGE_DISCARDED, + CHANGE_REQUEST_APPROVED, + CHANGE_REQUEST_APPROVAL_ADDED, + CHANGE_REQUEST_CANCELLED, + CHANGE_REQUEST_SENT_TO_REVIEW, + CHANGE_REQUEST_APPLIED, + API_TOKEN_CREATED, + API_TOKEN_UPDATED, + API_TOKEN_DELETED, + FEATURE_FAVORITED, + FEATURE_UNFAVORITED, + PROJECT_FAVORITED, + PROJECT_UNFAVORITED, + FEATURES_EXPORTED, + FEATURES_IMPORTED, +] as const; +export type IEventType = typeof IEventTypes[number]; export interface IBaseEvent { - type: string; + type: IEventType; createdBy: string; project?: string; environment?: string; @@ -132,7 +239,7 @@ export interface IEventList { } class BaseEvent implements IBaseEvent { - readonly type: string; + readonly type: IEventType; readonly createdBy: string; @@ -141,7 +248,11 @@ class BaseEvent implements IBaseEvent { /** * @param createdBy accepts a string for backward compatibility. Prefer using IUser for standardization */ - constructor(type: string, createdBy: string | IUser, tags: ITag[] = []) { + constructor( + type: IEventType, + createdBy: string | IUser, + tags: ITag[] = [], + ) { this.type = type; this.createdBy = typeof createdBy === 'string' diff --git a/src/test/e2e/api/openapi/openapi.e2e.test.ts b/src/test/e2e/api/openapi/openapi.e2e.test.ts index 035dd30a70..a54a196f19 100644 --- a/src/test/e2e/api/openapi/openapi.e2e.test.ts +++ b/src/test/e2e/api/openapi/openapi.e2e.test.ts @@ -59,7 +59,6 @@ test('the generated OpenAPI spec is valid', async () => { .get('/docs/openapi.json') .expect('Content-Type', /json/) .expect(200); - // this throws if the swagger parser can't parse it correctly // also parses examples, but _does_ do some string coercion in examples try { @@ -86,7 +85,6 @@ test('the generated OpenAPI spec is valid', async () => { ], }, }); - if (enforcerWarning !== undefined) { console.warn(enforcerWarning); } diff --git a/src/test/e2e/services/user-service.e2e.test.ts b/src/test/e2e/services/user-service.e2e.test.ts index bf0d8775d4..361c5a044e 100644 --- a/src/test/e2e/services/user-service.e2e.test.ts +++ b/src/test/e2e/services/user-service.e2e.test.ts @@ -47,8 +47,8 @@ beforeAll(async () => { }); userStore = stores.userStore; const rootRoles = await accessService.getRootRoles(); - adminRole = rootRoles.find((r) => r.name === RoleName.ADMIN); - viewerRole = rootRoles.find((r) => r.name === RoleName.VIEWER); + adminRole = rootRoles.find((r) => r.name === RoleName.ADMIN)!; + viewerRole = rootRoles.find((r) => r.name === RoleName.VIEWER)!; }); afterAll(async () => { @@ -218,7 +218,6 @@ test('updating a user without an email should not strip the email', async () => await userService.updateUser({ id: user.id, - email: null, name: 'some', }); diff --git a/src/test/e2e/stores/event-store.e2e.test.ts b/src/test/e2e/stores/event-store.e2e.test.ts index db6c4d7fbe..72e14dce41 100644 --- a/src/test/e2e/stores/event-store.e2e.test.ts +++ b/src/test/e2e/stores/event-store.e2e.test.ts @@ -40,7 +40,7 @@ test('Should include id and createdAt when saving', async () => { appName: 'test1', }, }; - const seen = []; + const seen: Array = []; eventStore.on(APPLICATION_CREATED, (e) => seen.push(e)); await eventStore.store(event1); jest.advanceTimersByTime(100);