diff --git a/packages/schemas/src/db-entries/custom-types.ts b/packages/schemas/src/db-entries/custom-types.ts index ceedccc35..6cba93da5 100644 --- a/packages/schemas/src/db-entries/custom-types.ts +++ b/packages/schemas/src/db-entries/custom-types.ts @@ -5,6 +5,14 @@ export enum ApplicationType { SPA = 'SPA', Traditional = 'Traditional', } +export enum UserLogType { + SignInUsernameAndPassword = 'SignInUsernameAndPassword', + ExchangeAccessToken = 'ExchangeAccessToken', +} +export enum UserLogResult { + Success = 'Success', + Failed = 'Failed', +} export enum PasswordEncryptionMethod { SaltAndPepper = 'SaltAndPepper', } diff --git a/packages/schemas/src/db-entries/index.ts b/packages/schemas/src/db-entries/index.ts index 497cf7050..d8cc7a1db 100644 --- a/packages/schemas/src/db-entries/index.ts +++ b/packages/schemas/src/db-entries/index.ts @@ -3,4 +3,5 @@ export * from './custom-types'; export * from './application'; export * from './oidc-model-instance'; +export * from './user-log'; export * from './user'; diff --git a/packages/schemas/src/db-entries/user-log.ts b/packages/schemas/src/db-entries/user-log.ts new file mode 100644 index 000000000..51f1fa5ff --- /dev/null +++ b/packages/schemas/src/db-entries/user-log.ts @@ -0,0 +1,39 @@ +// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +import { z } from 'zod'; + +import { UserLogPayload, userLogPayloadGuard, GeneratedSchema, Guard } from '../foundations'; +import { UserLogType, UserLogResult } from './custom-types'; + +export type UserLogDBEntry = { + id: string; + userId: string; + type: UserLogType; + result: UserLogResult; + payload: UserLogPayload; + createdAt: number; +}; + +const guard: Guard = z.object({ + id: z.string(), + userId: z.string(), + type: z.nativeEnum(UserLogType), + result: z.nativeEnum(UserLogResult), + payload: userLogPayloadGuard, + createdAt: z.number(), +}); + +export const UserLogs: GeneratedSchema = Object.freeze({ + table: 'user_logs', + tableSingular: 'user_log', + fields: { + id: 'id', + userId: 'user_id', + type: 'type', + result: 'result', + payload: 'payload', + createdAt: 'created_at', + }, + fieldKeys: ['id', 'userId', 'type', 'result', 'payload', 'createdAt'], + guard, +}); diff --git a/packages/schemas/src/foundations/jsonb-types.ts b/packages/schemas/src/foundations/jsonb-types.ts index 8a618d57a..beab5c7e3 100644 --- a/packages/schemas/src/foundations/jsonb-types.ts +++ b/packages/schemas/src/foundations/jsonb-types.ts @@ -21,3 +21,13 @@ export const oidcClientMetadataGuard = z.object({ }); export type OidcClientMetadata = z.infer; + +export const userLogPayloadGuard = z.object({ + ip: z.string().optional(), + userAgent: z.string().optional(), + applicationId: z.string().optional(), + applicationName: z.string().optional(), + details: z.object({}).optional(), // NOT intend to be parsed +}); + +export type UserLogPayload = z.infer; diff --git a/packages/schemas/src/gen/index.ts b/packages/schemas/src/gen/index.ts index 837362c15..d0c8cd6a6 100644 --- a/packages/schemas/src/gen/index.ts +++ b/packages/schemas/src/gen/index.ts @@ -11,7 +11,13 @@ import pluralize from 'pluralize'; import { generateSchema } from './schema'; import { FileData, Table, Field, Type, GeneratedType, TableWithType } from './types'; -import { findFirstParentheses, getType, normalizeWhitespaces, removeParentheses } from './utils'; +import { + findFirstParentheses, + getType, + normalizeWhitespaces, + removeParentheses, + removeUnrecognizedComments, +} from './utils'; const directory = 'tables'; @@ -25,7 +31,8 @@ const generate = async () => { .map>(async (file) => { const statements = (await fs.readFile(path.join(directory, file), { encoding: 'utf-8' })) .split(';') - .map((value) => normalizeWhitespaces(value)); + .map((value) => normalizeWhitespaces(value)) + .map((value) => removeUnrecognizedComments(value)); const tables = statements .filter((value) => value.toLowerCase().startsWith('create table')) .map((value) => findFirstParentheses(value)) @@ -55,7 +62,6 @@ const generate = async () => { const required = restLowercased.includes('not null'); const primitiveType = getType(type); const tsType = /\/\* @use (.*) \*\//.exec(restJoined)?.[1]; - assert( !(!primitiveType && tsType), `TS type can only be applied on primitive types, found ${ diff --git a/packages/schemas/src/gen/utils.ts b/packages/schemas/src/gen/utils.ts index bd5d6f0b5..98ac90b83 100644 --- a/packages/schemas/src/gen/utils.ts +++ b/packages/schemas/src/gen/utils.ts @@ -2,6 +2,10 @@ import { Optional } from '@silverhand/essentials'; export const normalizeWhitespaces = (string: string): string => string.replace(/\s+/g, ' ').trim(); +// Remove all comments not start with @ +export const removeUnrecognizedComments = (string: string): string => + string.replace(/\/\*(?!\s@)[^*]+\*\//g, ''); + const getCountDelta = (value: string): number => { if (value === '(') { return 1; diff --git a/packages/schemas/tables/user_logs.sql b/packages/schemas/tables/user_logs.sql new file mode 100644 index 000000000..8708e1ade --- /dev/null +++ b/packages/schemas/tables/user_logs.sql @@ -0,0 +1,13 @@ +create type user_log_type as enum ('SignInUsernameAndPassword', 'ExchangeAccessToken'); + +create type user_log_result as enum ('Success', 'Failed'); + +create table user_logs ( + id varchar(24) not null, + user_id varchar(24) not null, + type user_log_type not null, + result user_log_result not null, /* not using boolean, may have more result types in the future */ + payload jsonb /* @use UserLogPayload */ not null, + created_at timestamptz not null default(now()), + primary key (id) +);