From a3267dec679d6a76735443ee9332860a0a69196a Mon Sep 17 00:00:00 2001 From: Muntasir Mallik <73852736+muntaxir4@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:42:34 +0530 Subject: [PATCH] feat(schema, api-client): Migrate event schemas and types to @keyshade/schema (#546) --- packages/api-client/src/controllers/event.ts | 5 +- .../api-client/src/types/event.types.d.ts | 82 ---------- packages/schema/package.json | 2 +- packages/schema/src/enums.ts | 14 ++ packages/schema/src/event/index.ts | 40 +++++ packages/schema/src/event/index.types.ts | 6 + packages/schema/src/index.ts | 1 + packages/schema/src/index.types.ts | 1 + packages/schema/src/project/index.ts | 2 +- packages/schema/tests/enums.test.ts | 149 ++++++++++++++++++ packages/schema/tests/event.spec.ts | 128 +++++++++++++++ packages/schema/tests/project.spec.ts | 16 +- 12 files changed, 350 insertions(+), 96 deletions(-) delete mode 100644 packages/api-client/src/types/event.types.d.ts create mode 100644 packages/schema/src/event/index.ts create mode 100644 packages/schema/src/event/index.types.ts create mode 100644 packages/schema/tests/enums.test.ts create mode 100644 packages/schema/tests/event.spec.ts diff --git a/packages/api-client/src/controllers/event.ts b/packages/api-client/src/controllers/event.ts index 77450752..6a36b14c 100644 --- a/packages/api-client/src/controllers/event.ts +++ b/packages/api-client/src/controllers/event.ts @@ -1,7 +1,4 @@ -import { - GetEventsRequest, - GetEventsResponse -} from '@api-client/types/event.types' +import { GetEventsRequest, GetEventsResponse } from '@keyshade/schema' import { APIClient } from '../core/client' import { ClientResponse } from '@keyshade/schema' import { parseResponse } from '@api-client/core/response-parser' diff --git a/packages/api-client/src/types/event.types.d.ts b/packages/api-client/src/types/event.types.d.ts deleted file mode 100644 index b267592e..00000000 --- a/packages/api-client/src/types/event.types.d.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { PageResponse } from '@keyshade/schema' - -export enum EventSource { - SECRET, - VARIABLE, - ENVIRONMENT, - PROJECT, - WORKSPACE, - WORKSPACE_ROLE, - INTEGRATION -} - -export enum EventTriggerer { - USER, - SYSTEM -} - -export enum EventSeverity { - INFO, - WARN, - ERROR -} - -export enum EventType { - INVITED_TO_WORKSPACE, - REMOVED_FROM_WORKSPACE, - ACCEPTED_INVITATION, - DECLINED_INVITATION, - CANCELLED_INVITATION, - LEFT_WORKSPACE, - WORKSPACE_MEMBERSHIP_UPDATED, - WORKSPACE_UPDATED, - WORKSPACE_CREATED, - WORKSPACE_ROLE_CREATED, - WORKSPACE_ROLE_UPDATED, - WORKSPACE_ROLE_DELETED, - PROJECT_CREATED, - PROJECT_UPDATED, - PROJECT_DELETED, - SECRET_UPDATED, - SECRET_DELETED, - SECRET_ADDED, - VARIABLE_UPDATED, - VARIABLE_DELETED, - VARIABLE_ADDED, - ENVIRONMENT_UPDATED, - ENVIRONMENT_DELETED, - ENVIRONMENT_ADDED, - INTEGRATION_ADDED, - INTEGRATION_UPDATED, - INTEGRATION_DELETED -} - -export interface GetEventsRequest { - workspaceSlug: string - source: string -} - -export interface GetEventsResponse - extends PageResponse<{ - id: string - source: EventSource - triggerer: EventTriggerer - severity: EventSeverity - type: EventType - timestamp: string - metadata: { - name: string - projectName: string - projectId?: string - variableId?: string - environmentId?: string - secretId?: string - workspaceId?: string - workspaceName?: string - } - title: string - description: string - itemId: string - userId: string - workspaceId: string - }> {} diff --git a/packages/schema/package.json b/packages/schema/package.json index 45b1f14a..80233e5e 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,7 +1,7 @@ { "name": "@keyshade/schema", "version": "1.0.0", - "main": "dist/src/index.js", + "main": "dist/src/index.types.js", "description": "This package holds the schemas that other applications can use to validate the input data.", "private": true, "exports": { diff --git a/packages/schema/src/enums.ts b/packages/schema/src/enums.ts index 1d01129b..24280633 100644 --- a/packages/schema/src/enums.ts +++ b/packages/schema/src/enums.ts @@ -11,6 +11,20 @@ export const expiresAfterEnum = z.enum(['never', '24', '168', '720', '8760']) export const rotateAfterEnum = z.enum(['never', '24', '168', '720', '8760']) +export const eventSourceEnum = z.enum([ + 'SECRET', + 'VARIABLE', + 'ENVIRONMENT', + 'PROJECT', + 'WORKSPACE', + 'WORKSPACE_ROLE', + 'INTEGRATION' +]) + +export const eventTriggererEnum = z.enum(['USER', 'SYSTEM']) + +export const eventSeverityEnum = z.enum(['INFO', 'WARN', 'ERROR']) + export const eventTypeEnum = z.enum([ 'INVITED_TO_WORKSPACE', 'REMOVED_FROM_WORKSPACE', diff --git a/packages/schema/src/event/index.ts b/packages/schema/src/event/index.ts new file mode 100644 index 00000000..c0ebdd0c --- /dev/null +++ b/packages/schema/src/event/index.ts @@ -0,0 +1,40 @@ +import { + eventSourceEnum, + eventSeverityEnum, + eventTriggererEnum, + eventTypeEnum +} from '@/enums' +import { PageRequestSchema, PageResponseSchema } from '@/pagination' +import { z } from 'zod' + +export const GetEventsRequestSchema = PageRequestSchema.extend({ + workspaceSlug: z.string(), + source: eventSourceEnum.optional(), + severity: eventSeverityEnum.optional() +}) + +export const GetEventsResponseSchema = PageResponseSchema( + z.object({ + id: z.string(), + source: eventSourceEnum, + triggerer: eventTriggererEnum, + severity: eventSeverityEnum, + type: eventTypeEnum, + timestamp: z.string(), + metadata: z.object({ + name: z.string(), + projectName: z.string(), + projectId: z.string().optional(), + variableId: z.string().optional(), + environmentId: z.string().optional(), + secretId: z.string().optional(), + workspaceId: z.string().optional(), + workspaceName: z.string().optional() + }), + title: z.string(), + description: z.string(), + itemId: z.string(), + userId: z.string(), + workspaceId: z.string() + }) +) diff --git a/packages/schema/src/event/index.types.ts b/packages/schema/src/event/index.types.ts new file mode 100644 index 00000000..e33043c1 --- /dev/null +++ b/packages/schema/src/event/index.types.ts @@ -0,0 +1,6 @@ +import { z } from 'zod' +import { GetEventsRequestSchema, GetEventsResponseSchema } from '.' + +export type GetEventsRequest = z.infer + +export type GetEventsResponse = z.infer diff --git a/packages/schema/src/index.ts b/packages/schema/src/index.ts index 4fc9dd17..d78c0d66 100644 --- a/packages/schema/src/index.ts +++ b/packages/schema/src/index.ts @@ -12,3 +12,4 @@ export * from './user' export * from './variable' export * from './workspace' export * from './workspace-role' +export * from './event' diff --git a/packages/schema/src/index.types.ts b/packages/schema/src/index.types.ts index 01c96b50..73ffeeae 100644 --- a/packages/schema/src/index.types.ts +++ b/packages/schema/src/index.types.ts @@ -14,6 +14,7 @@ export * from './secret/index.types' export * from './user/index.types' export * from './workspace/index.types' export * from './variable/index.types' +export * from './event/index.types' export type TCreateApiKey = z.infer export type TUpdateApiKey = z.infer diff --git a/packages/schema/src/project/index.ts b/packages/schema/src/project/index.ts index 708b7196..89969da0 100644 --- a/packages/schema/src/project/index.ts +++ b/packages/schema/src/project/index.ts @@ -15,7 +15,7 @@ export const ProjectSchema = z privateKey: z.string(), storePrivateKey: z.boolean(), isDisabled: z.boolean(), - accessLevel: z.string(), + accessLevel: projectAccessLevelEnum, pendingCreation: z.boolean(), isForked: z.boolean(), lastUpdatedById: z.string(), diff --git a/packages/schema/tests/enums.test.ts b/packages/schema/tests/enums.test.ts new file mode 100644 index 00000000..12c2e6e7 --- /dev/null +++ b/packages/schema/tests/enums.test.ts @@ -0,0 +1,149 @@ +import { z } from 'zod' +import { + integrationTypeEnum, + expiresAfterEnum, + rotateAfterEnum, + eventSourceEnum, + eventTriggererEnum, + eventSeverityEnum, + eventTypeEnum, + authorityEnum, + projectAccessLevelEnum +} from '@//enums' + +describe('Enums Tests', () => { + it('integrationTypeEnum should have correct values', () => { + expect(integrationTypeEnum.options).toEqual([ + 'DISCORD', + 'SLACK', + 'GITHUB', + 'GITLAB' + ]) + }) + + it('expiresAfterEnum should have correct values', () => { + expect(expiresAfterEnum.options).toEqual([ + 'never', + '24', + '168', + '720', + '8760' + ]) + }) + + it('rotateAfterEnum should have correct values', () => { + expect(rotateAfterEnum.options).toEqual([ + 'never', + '24', + '168', + '720', + '8760' + ]) + }) + + it('eventSourceEnum should have correct values', () => { + expect(eventSourceEnum.options).toEqual([ + 'SECRET', + 'VARIABLE', + 'ENVIRONMENT', + 'PROJECT', + 'WORKSPACE', + 'WORKSPACE_ROLE', + 'INTEGRATION' + ]) + }) + + it('eventTriggererEnum should have correct values', () => { + expect(eventTriggererEnum.options).toEqual(['USER', 'SYSTEM']) + }) + + it('eventSeverityEnum should have correct values', () => { + expect(eventSeverityEnum.options).toEqual(['INFO', 'WARN', 'ERROR']) + }) + + it('eventTypeEnum should have correct values', () => { + expect(eventTypeEnum.options).toEqual([ + 'INVITED_TO_WORKSPACE', + 'REMOVED_FROM_WORKSPACE', + 'ACCEPTED_INVITATION', + 'DECLINED_INVITATION', + 'CANCELLED_INVITATION', + 'LEFT_WORKSPACE', + 'WORKSPACE_MEMBERSHIP_UPDATED', + 'WORKSPACE_UPDATED', + 'WORKSPACE_CREATED', + 'WORKSPACE_ROLE_CREATED', + 'WORKSPACE_ROLE_UPDATED', + 'WORKSPACE_ROLE_DELETED', + 'PROJECT_CREATED', + 'PROJECT_UPDATED', + 'PROJECT_DELETED', + 'SECRET_UPDATED', + 'SECRET_DELETED', + 'SECRET_ADDED', + 'VARIABLE_UPDATED', + 'VARIABLE_DELETED', + 'VARIABLE_ADDED', + 'ENVIRONMENT_UPDATED', + 'ENVIRONMENT_DELETED', + 'ENVIRONMENT_ADDED', + 'INTEGRATION_ADDED', + 'INTEGRATION_UPDATED', + 'INTEGRATION_DELETED' + ]) + }) + + it('authorityEnum should have correct values', () => { + expect(authorityEnum.options).toEqual([ + 'CREATE_PROJECT', + 'READ_USERS', + 'ADD_USER', + 'REMOVE_USER', + 'UPDATE_USER_ROLE', + 'READ_WORKSPACE', + 'UPDATE_WORKSPACE', + 'DELETE_WORKSPACE', + 'CREATE_WORKSPACE_ROLE', + 'READ_WORKSPACE_ROLE', + 'UPDATE_WORKSPACE_ROLE', + 'DELETE_WORKSPACE_ROLE', + 'WORKSPACE_ADMIN', + 'READ_PROJECT', + 'UPDATE_PROJECT', + 'DELETE_PROJECT', + 'CREATE_SECRET', + 'READ_SECRET', + 'UPDATE_SECRET', + 'DELETE_SECRET', + 'CREATE_ENVIRONMENT', + 'READ_ENVIRONMENT', + 'UPDATE_ENVIRONMENT', + 'DELETE_ENVIRONMENT', + 'CREATE_VARIABLE', + 'READ_VARIABLE', + 'UPDATE_VARIABLE', + 'DELETE_VARIABLE', + 'CREATE_INTEGRATION', + 'READ_INTEGRATION', + 'UPDATE_INTEGRATION', + 'DELETE_INTEGRATION', + 'CREATE_WORKSPACE', + 'CREATE_API_KEY', + 'READ_API_KEY', + 'UPDATE_API_KEY', + 'DELETE_API_KEY', + 'UPDATE_PROFILE', + 'READ_SELF', + 'UPDATE_SELF', + 'READ_EVENT' + ]) + }) + + it('projectAccessLevelEnum should have correct values', () => { + expect(projectAccessLevelEnum.options).toEqual([ + 'GLOBAL', + 'INTERNAL', + 'PRIVATE' + ]) + }) +}) diff --git a/packages/schema/tests/event.spec.ts b/packages/schema/tests/event.spec.ts new file mode 100644 index 00000000..64eb1142 --- /dev/null +++ b/packages/schema/tests/event.spec.ts @@ -0,0 +1,128 @@ +// event.spec.ts +import { GetEventsRequestSchema, GetEventsResponseSchema } from '@/event' + +describe('Event Schema Tests', () => { + // Tests for GetEventsRequestSchema + it('should validate a valid GetEventsRequestSchema', () => { + const result = GetEventsRequestSchema.safeParse({ + workspaceSlug: 'workspace-slug', + source: 'WORKSPACE' + }) + expect(result.success).toBe(true) + }) + + it('should validate GetEventsRequestSchema when only workspaceSlug is provided', () => { + const result = GetEventsRequestSchema.safeParse({ + workspaceSlug: 'workspace-slug' + }) + expect(result.success).toBe(true) + }) + + it('should validate GetEventsRequestSchema when severity is also provided', () => { + const result = GetEventsRequestSchema.safeParse({ + workspaceSlug: 'workspace-slug', + source: 'INTEGRATION', + severity: 'WARN' + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid GetEventsRequestSchema', () => { + const result = GetEventsRequestSchema.safeParse({ + workspaceSlug: 123, // Should be a string + source: 'PROJECT_CREATED' // Invalid source + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(2) + }) + + // Tests for GetEventsResponseSchema + it('should validate a valid GetEventsResponseSchema', () => { + const result = GetEventsResponseSchema.safeParse({ + items: [ + { + id: 'event123', + source: 'SECRET', + triggerer: 'USER', + severity: 'INFO', + type: 'SECRET_UPDATED', + timestamp: '2024-10-01T00:00:00Z', + metadata: { + name: 'Event Name', + projectName: 'Project Name', + projectId: 'project123', + variableId: 'variable123', + environmentId: 'env123', + secretId: 'secret123', + workspaceId: 'workspace123', + workspaceName: 'Workspace Name' + }, + title: 'Event Title', + description: 'Event Description', + itemId: 'item123', + userId: 'user123', + workspaceId: 'workspace123' + } + ], + metadata: { + page: 1, + perPage: 10, + pageCount: 1, + totalCount: 1, + links: { + self: 'http://example.com/page/1', + first: 'http://example.com/page/1', + previous: null, + next: null, + last: 'http://example.com/page/1' + } + } + }) + expect(result.success).toBe(true) + }) + + it('should not validate an invalid GetEventsResponseSchema', () => { + const result = GetEventsResponseSchema.safeParse({ + items: [ + { + id: 'event123', + source: 'PROJECT_CREATED', + triggerer: 'user123', + severity: 'high', + type: 'update', + timestamp: '2024-10-01T00:00:00Z', + metadata: { + name: 'Event Name', + projectName: 'Project Name', + projectId: 'project123', + variableId: 'variable123', + environmentId: 'env123', + secretId: 'secret123', + workspaceId: 'workspace123', + workspaceName: 'Workspace Name' + }, + title: 'Event Title', + description: 'Event Description', + itemId: 'item123', + userId: 123, // Should be a string + workspaceId: 'workspace123' + } + ], + metadata: { + page: 1, + perPage: 10, + pageCount: 1, + totalCount: 1, + links: { + self: 'http://example.com/page/1', + first: 'http://example.com/page/1', + previous: null, + next: null, + last: 'http://example.com/page/1' + } + } + }) + expect(result.success).toBe(false) + expect(result.error?.issues).toHaveLength(5) + }) +}) diff --git a/packages/schema/tests/project.spec.ts b/packages/schema/tests/project.spec.ts index 54d766d8..a4e0aafe 100644 --- a/packages/schema/tests/project.spec.ts +++ b/packages/schema/tests/project.spec.ts @@ -35,7 +35,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'INTERNAL', pendingCreation: false, isForked: false, lastUpdatedById: 'user123', @@ -69,7 +69,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'GLOBAL', pendingCreation: false, isForked: true, lastUpdatedById: 'user123', @@ -127,7 +127,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'PRIVATE', pendingCreation: false, isForked: false, lastUpdatedById: 'user123', @@ -190,7 +190,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'PRIVATE', pendingCreation: false, isForked: false, lastUpdatedById: 'user123', @@ -276,7 +276,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'PRIVATE', pendingCreation: false, isForked: false, lastUpdatedById: 'user123', @@ -342,7 +342,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'PRIVATE', pendingCreation: false, isForked: false, lastUpdatedById: 'user123', @@ -471,7 +471,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'PRIVATE', pendingCreation: false, isForked: false, lastUpdatedById: 'user123', @@ -555,7 +555,7 @@ describe('Project Schema Tests', () => { privateKey: 'private-key', storePrivateKey: true, isDisabled: false, - accessLevel: 'admin', + accessLevel: 'PRIVATE', pendingCreation: false, isForked: false, lastUpdatedById: 'user123',