diff --git a/packages/console/src/components/AuditLogTable/index.tsx b/packages/console/src/components/AuditLogTable/index.tsx index c848e1c1a..b4b681088 100644 --- a/packages/console/src/components/AuditLogTable/index.tsx +++ b/packages/console/src/components/AuditLogTable/index.tsx @@ -6,7 +6,7 @@ import useSWR from 'swr'; import ApplicationName from '@/components/ApplicationName'; import UserName from '@/components/UserName'; -import { defaultPageSize } from '@/consts'; +import { auditLogEventTitle, defaultPageSize } from '@/consts'; import Table from '@/ds-components/Table'; import type { Column } from '@/ds-components/Table/types'; import type { RequestError } from '@/hooks/use-api'; @@ -21,6 +21,11 @@ import EventName from './components/EventName'; import EventSelector from './components/EventSelector'; import * as styles from './index.module.scss'; +const auditLogEventOptions = Object.entries(auditLogEventTitle).map(([value, title]) => ({ + value, + title: title ?? value, +})); + type Props = { userId?: string; className?: string; @@ -103,6 +108,7 @@ function AuditLogTable({ userId, className }: Props) {
{ updateSearchParameters({ event, page: undefined }); }} diff --git a/packages/console/src/consts/logs.ts b/packages/console/src/consts/logs.ts index d1a5558e0..34f9ee62b 100644 --- a/packages/console/src/consts/logs.ts +++ b/packages/console/src/consts/logs.ts @@ -1,54 +1,64 @@ -import type { LogKey } from '@logto/schemas'; +import type { AuditLogKey, LogKey, WebhookLogKey } from '@logto/schemas'; import { type Optional } from '@silverhand/essentials'; -export const logEventTitle: Record> & Record> = - Object.freeze({ - 'ExchangeTokenBy.AuthorizationCode': 'Exchange token by Code', - 'ExchangeTokenBy.ClientCredentials': 'Exchange token by Client Credentials', - 'ExchangeTokenBy.RefreshToken': 'Exchange token by Refresh Token', - 'ExchangeTokenBy.Unknown': undefined, - 'Interaction.Create': 'Interaction started', - 'Interaction.End': 'Interaction ended', - 'Interaction.ForgotPassword.Identifier.Password.Submit': - 'Submit forgot-password identifier with password', - 'Interaction.ForgotPassword.Identifier.Social.Create': undefined, - 'Interaction.ForgotPassword.Identifier.Social.Submit': undefined, - 'Interaction.ForgotPassword.Identifier.VerificationCode.Create': - 'Create and send forgot-password verification code', - 'Interaction.ForgotPassword.Identifier.VerificationCode.Submit': - 'Submit and verify forgot-password verification code', - 'Interaction.ForgotPassword.Profile.Create': 'Put new forgot-password interaction profile', - 'Interaction.ForgotPassword.Profile.Delete': 'Delete forgot-password interaction profile', - 'Interaction.ForgotPassword.Profile.Update': 'Patch update forgot-password interaction profile', - 'Interaction.ForgotPassword.Submit': 'Submit forgot-password interaction', - 'Interaction.ForgotPassword.Update': 'Update forgot-password interaction', - 'Interaction.Register.Identifier.Password.Submit': undefined, - 'Interaction.Register.Identifier.Social.Create': undefined, - 'Interaction.Register.Identifier.Social.Submit': undefined, - 'Interaction.Register.Identifier.VerificationCode.Create': - 'Create and send register identifier with verification code', - 'Interaction.Register.Identifier.VerificationCode.Submit': - 'Submit and verify register verification code', - 'Interaction.Register.Profile.Create': 'Put new register interaction profile', - 'Interaction.Register.Profile.Delete': 'Delete register interaction profile', - 'Interaction.Register.Profile.Update': 'Patch update register interaction profile', - 'Interaction.Register.Submit': 'Submit register interaction', - 'Interaction.Register.Update': 'Update register interaction', - 'Interaction.SignIn.Identifier.Password.Submit': 'Submit sign-in identifier with password', - 'Interaction.SignIn.Identifier.Social.Create': 'Create social sign-in authorization-url', - 'Interaction.SignIn.Identifier.Social.Submit': 'Authenticate and submit social identifier', - 'Interaction.SignIn.Identifier.VerificationCode.Create': - 'Create and send sign-in verification code', - 'Interaction.SignIn.Identifier.VerificationCode.Submit': - 'Submit and verify sign-in identifier with verification code', - 'Interaction.SignIn.Profile.Create': 'Put new sign-in interaction profile', - 'Interaction.SignIn.Profile.Delete': 'Delete sign-in interaction profile', - 'Interaction.SignIn.Profile.Update': 'Patch Update sign-in interaction profile', - 'Interaction.SignIn.Submit': 'Submit sign-in interaction', - 'Interaction.SignIn.Update': 'Update sign-in interaction', - 'TriggerHook.PostRegister': undefined, - 'TriggerHook.PostResetPassword': undefined, - 'TriggerHook.PostSignIn': undefined, - RevokeToken: undefined, - Unknown: undefined, - }); +export const auditLogEventTitle: Record> & + Record> = Object.freeze({ + 'ExchangeTokenBy.AuthorizationCode': 'Exchange token by Code', + 'ExchangeTokenBy.ClientCredentials': 'Exchange token by Client Credentials', + 'ExchangeTokenBy.RefreshToken': 'Exchange token by Refresh Token', + 'ExchangeTokenBy.Unknown': undefined, + 'Interaction.Create': 'Interaction started', + 'Interaction.End': 'Interaction ended', + 'Interaction.ForgotPassword.Identifier.Password.Submit': + 'Submit forgot-password identifier with password', + 'Interaction.ForgotPassword.Identifier.Social.Create': undefined, + 'Interaction.ForgotPassword.Identifier.Social.Submit': undefined, + 'Interaction.ForgotPassword.Identifier.VerificationCode.Create': + 'Create and send forgot-password verification code', + 'Interaction.ForgotPassword.Identifier.VerificationCode.Submit': + 'Submit and verify forgot-password verification code', + 'Interaction.ForgotPassword.Profile.Create': 'Put new forgot-password interaction profile', + 'Interaction.ForgotPassword.Profile.Delete': 'Delete forgot-password interaction profile', + 'Interaction.ForgotPassword.Profile.Update': 'Patch update forgot-password interaction profile', + 'Interaction.ForgotPassword.Submit': 'Submit forgot-password interaction', + 'Interaction.ForgotPassword.Update': 'Update forgot-password interaction', + 'Interaction.Register.Identifier.Password.Submit': undefined, + 'Interaction.Register.Identifier.Social.Create': undefined, + 'Interaction.Register.Identifier.Social.Submit': undefined, + 'Interaction.Register.Identifier.VerificationCode.Create': + 'Create and send register identifier with verification code', + 'Interaction.Register.Identifier.VerificationCode.Submit': + 'Submit and verify register verification code', + 'Interaction.Register.Profile.Create': 'Put new register interaction profile', + 'Interaction.Register.Profile.Delete': 'Delete register interaction profile', + 'Interaction.Register.Profile.Update': 'Patch update register interaction profile', + 'Interaction.Register.Submit': 'Submit register interaction', + 'Interaction.Register.Update': 'Update register interaction', + 'Interaction.SignIn.Identifier.Password.Submit': 'Submit sign-in identifier with password', + 'Interaction.SignIn.Identifier.Social.Create': 'Create social sign-in authorization-url', + 'Interaction.SignIn.Identifier.Social.Submit': 'Authenticate and submit social identifier', + 'Interaction.SignIn.Identifier.VerificationCode.Create': + 'Create and send sign-in verification code', + 'Interaction.SignIn.Identifier.VerificationCode.Submit': + 'Submit and verify sign-in identifier with verification code', + 'Interaction.SignIn.Profile.Create': 'Put new sign-in interaction profile', + 'Interaction.SignIn.Profile.Delete': 'Delete sign-in interaction profile', + 'Interaction.SignIn.Profile.Update': 'Patch Update sign-in interaction profile', + 'Interaction.SignIn.Submit': 'Submit sign-in interaction', + 'Interaction.SignIn.Update': 'Update sign-in interaction', + RevokeToken: undefined, + Unknown: undefined, +}); + +// `webhookLogEventTitle` and `logEventTitle` are not used yet, keep them just in case. +const webhookLogEventTitle: Record> & + Record> = Object.freeze({ + 'TriggerHook.PostRegister': undefined, + 'TriggerHook.PostResetPassword': undefined, + 'TriggerHook.PostSignIn': undefined, +}); + +export const logEventTitle: Record> & Record> = { + ...auditLogEventTitle, + ...webhookLogEventTitle, +}; diff --git a/packages/core/src/queries/log.ts b/packages/core/src/queries/log.ts index 6bffbda7c..c6ddaf923 100644 --- a/packages/core/src/queries/log.ts +++ b/packages/core/src/queries/log.ts @@ -1,33 +1,50 @@ -import type { HookExecutionStats, Log } from '@logto/schemas'; -import { token, Logs } from '@logto/schemas'; +import { + token, + type hook, + Logs, + type HookExecutionStats, + type Log, + type interaction, + type LogKeyUnknown, +} from '@logto/schemas'; import { conditionalSql, convertToIdentifiers } from '@logto/shared'; +import { conditional, conditionalArray } from '@silverhand/essentials'; import { subDays } from 'date-fns'; -import type { CommonQueryMethods } from 'slonik'; import { sql } from 'slonik'; +import type { CommonQueryMethods } from 'slonik'; import { buildFindEntityByIdWithPool } from '#src/database/find-entity-by-id.js'; import { buildInsertIntoWithPool } from '#src/database/insert-into.js'; const { table, fields } = convertToIdentifiers(Logs); +export type AllowedKeyPrefix = hook.Type | token.Type | interaction.Prefix | typeof LogKeyUnknown; + type LogCondition = { logKey?: string; - applicationId?: string; - userId?: string; - hookId?: string; + payload?: { applicationId?: string; userId?: string; hookId?: string }; startTimeExclusive?: number; + includeKeyPrefix?: AllowedKeyPrefix[]; }; const buildLogConditionSql = (logCondition: LogCondition) => - conditionalSql(logCondition, ({ logKey, applicationId, userId, hookId, startTimeExclusive }) => { + conditionalSql(logCondition, ({ logKey, payload, startTimeExclusive, includeKeyPrefix = [] }) => { + const keyPrefixFilter = conditional( + includeKeyPrefix.length > 0 && + includeKeyPrefix.map((prefix) => sql`${fields.key} like ${`${prefix}%`}`) + ); const subConditions = [ - conditionalSql(logKey, (logKey) => sql`${fields.key}=${logKey}`), - conditionalSql(userId, (userId) => sql`${fields.payload}->>'userId'=${userId}`), conditionalSql( - applicationId, - (applicationId) => sql`${fields.payload}->>'applicationId'=${applicationId}` + keyPrefixFilter, + (keyPrefixFilter) => sql`(${sql.join(keyPrefixFilter, sql` or `)})` ), - conditionalSql(hookId, (hookId) => sql`${fields.payload}->>'hookId'=${hookId}`), + ...conditionalArray( + payload && + Object.entries(payload).map(([key, value]) => + value ? sql`${fields.payload}->>${key}=${value}` : sql`` + ) + ), + conditionalSql(logKey, (logKey) => sql`${fields.key}=${logKey}`), conditionalSql( startTimeExclusive, (startTimeExclusive) => diff --git a/packages/core/src/routes/hook.test.ts b/packages/core/src/routes/hook.test.ts index b4f8a72d9..079c4ad89 100644 --- a/packages/core/src/routes/hook.test.ts +++ b/packages/core/src/routes/hook.test.ts @@ -6,6 +6,7 @@ import { type CreateHook, LogResult, type Log, + hook, } from '@logto/schemas'; import { pickDefault } from '@logto/shared/esm'; import { subDays } from 'date-fns'; @@ -155,8 +156,18 @@ describe('hook routes', () => { await hookRequest.get( `/hooks/${hookId}/recent-logs?logKey=${logKey}&page=${page}&page_size=${pageSize}` ); - expect(countLogs).toHaveBeenCalledWith({ hookId, logKey, startTimeExclusive }); - expect(findLogs).toHaveBeenCalledWith(5, 0, { hookId, logKey, startTimeExclusive }); + expect(countLogs).toHaveBeenCalledWith({ + payload: { hookId }, + logKey, + startTimeExclusive, + includeKeyPrefix: [hook.Type.TriggerHook], + }); + expect(findLogs).toHaveBeenCalledWith(5, 0, { + payload: { hookId }, + logKey, + startTimeExclusive, + includeKeyPrefix: [hook.Type.TriggerHook], + }); jest.useRealTimers(); }); diff --git a/packages/core/src/routes/hook.ts b/packages/core/src/routes/hook.ts index c48aeec55..399597a40 100644 --- a/packages/core/src/routes/hook.ts +++ b/packages/core/src/routes/hook.ts @@ -1,4 +1,11 @@ -import { Hooks, Logs, hookConfigGuard, hookEventsGuard, hookResponseGuard } from '@logto/schemas'; +import { + Hooks, + Logs, + hookConfigGuard, + hookEventsGuard, + hookResponseGuard, + hook, +} from '@logto/schemas'; import { generateStandardId } from '@logto/shared'; import { conditional, deduplicate, yes } from '@silverhand/essentials'; import { subDays } from 'date-fns'; @@ -8,6 +15,7 @@ import RequestError from '#src/errors/RequestError/index.js'; import koaGuard from '#src/middleware/koa-guard.js'; import koaPagination from '#src/middleware/koa-pagination.js'; import koaQuotaGuard from '#src/middleware/koa-quota-guard.js'; +import { type AllowedKeyPrefix } from '#src/queries/log.js'; import assertThat from '#src/utils/assert-that.js'; import type { AuthedRouter, RouterInitArgs } from './types.js'; @@ -114,11 +122,22 @@ export default function hookRoutes( query: { logKey }, } = ctx.guard; + const includeKeyPrefix: AllowedKeyPrefix[] = [hook.Type.TriggerHook]; const startTimeExclusive = subDays(new Date(), 1).getTime(); const [{ count }, logs] = await Promise.all([ - countLogs({ logKey, hookId: id, startTimeExclusive }), - findLogs(limit, offset, { logKey, hookId: id, startTimeExclusive }), + countLogs({ + logKey, + payload: { hookId: id }, + startTimeExclusive, + includeKeyPrefix, + }), + findLogs(limit, offset, { + logKey, + payload: { hookId: id }, + startTimeExclusive, + includeKeyPrefix, + }), ]); ctx.pagination.totalCount = count; diff --git a/packages/core/src/routes/log.test.ts b/packages/core/src/routes/log.test.ts index dffd14c3b..e0915a0bf 100644 --- a/packages/core/src/routes/log.test.ts +++ b/packages/core/src/routes/log.test.ts @@ -1,4 +1,4 @@ -import { LogResult } from '@logto/schemas'; +import { LogResult, token, interaction, LogKeyUnknown } from '@logto/schemas'; import type { Log } from '@logto/schemas'; import { pickDefault } from '@logto/shared/esm'; @@ -42,8 +42,26 @@ describe('logRoutes', () => { await logRequest.get( `/logs?userId=${userId}&applicationId=${applicationId}&logKey=${logKey}&page=${page}&page_size=${pageSize}` ); - expect(countLogs).toHaveBeenCalledWith({ userId, applicationId, logKey }); - expect(findLogs).toHaveBeenCalledWith(5, 0, { userId, applicationId, logKey }); + expect(countLogs).toHaveBeenCalledWith({ + payload: { userId, applicationId }, + logKey, + includeKeyPrefix: [ + token.Type.ExchangeTokenBy, + token.Type.RevokeToken, + interaction.prefix, + LogKeyUnknown, + ], + }); + expect(findLogs).toHaveBeenCalledWith(5, 0, { + payload: { userId, applicationId }, + logKey, + includeKeyPrefix: [ + token.Type.ExchangeTokenBy, + token.Type.RevokeToken, + interaction.prefix, + LogKeyUnknown, + ], + }); }); it('should return correct response', async () => { diff --git a/packages/core/src/routes/log.ts b/packages/core/src/routes/log.ts index e4c584504..3da55fe6b 100644 --- a/packages/core/src/routes/log.ts +++ b/packages/core/src/routes/log.ts @@ -1,15 +1,16 @@ -import { Logs } from '@logto/schemas'; +import { Logs, interaction, token, LogKeyUnknown } from '@logto/schemas'; import { object, string } from 'zod'; import koaGuard from '#src/middleware/koa-guard.js'; import koaPagination from '#src/middleware/koa-pagination.js'; +import { type AllowedKeyPrefix } from '#src/queries/log.js'; import type { AuthedRouter, RouterInitArgs } from './types.js'; export default function logRoutes( ...[router, { queries }]: RouterInitArgs ) { - const { countLogs, findLogById, findLogs } = queries.logs; + const { findLogById, countLogs, findLogs } = queries.logs; router.get( '/logs', @@ -29,10 +30,25 @@ export default function logRoutes( query: { userId, applicationId, logKey }, } = ctx.guard; + const includeKeyPrefix: AllowedKeyPrefix[] = [ + token.Type.ExchangeTokenBy, + token.Type.RevokeToken, + interaction.prefix, + LogKeyUnknown, + ]; + // TODO: @Gao refactor like user search const [{ count }, logs] = await Promise.all([ - countLogs({ logKey, applicationId, userId }), - findLogs(limit, offset, { logKey, userId, applicationId }), + countLogs({ + logKey, + payload: { applicationId, userId }, + includeKeyPrefix, + }), + findLogs(limit, offset, { + logKey, + payload: { userId, applicationId }, + includeKeyPrefix, + }), ]); // Return totalCount to pagination middleware diff --git a/packages/integration-tests/src/api/logs.ts b/packages/integration-tests/src/api/logs.ts index 9813d69e4..446aebb3a 100644 --- a/packages/integration-tests/src/api/logs.ts +++ b/packages/integration-tests/src/api/logs.ts @@ -3,7 +3,12 @@ import { conditionalString } from '@silverhand/essentials'; import { authedAdminApi } from './api.js'; -export const getLogs = async (params?: URLSearchParams) => +export const getAuditLogs = async (params?: URLSearchParams) => authedAdminApi.get('logs?' + conditionalString(params?.toString())).json(); +export const getWebhookRecentLogs = async (hookId: string, params?: URLSearchParams) => + authedAdminApi + .get(`hooks/${hookId}/recent-logs?` + conditionalString(params?.toString())) + .json(); + export const getLog = async (logId: string) => authedAdminApi.get(`logs/${logId}`).json(); diff --git a/packages/integration-tests/src/tests/api/audit-logs/index.test.ts b/packages/integration-tests/src/tests/api/audit-logs/index.test.ts index 22d727af6..55c44c87e 100644 --- a/packages/integration-tests/src/tests/api/audit-logs/index.test.ts +++ b/packages/integration-tests/src/tests/api/audit-logs/index.test.ts @@ -3,7 +3,7 @@ import { assert } from '@silverhand/essentials'; import { deleteUser } from '#src/api/admin-user.js'; import { putInteraction } from '#src/api/interaction.js'; -import { getLogs } from '#src/api/logs.js'; +import { getAuditLogs } from '#src/api/logs.js'; import MockClient from '#src/client/index.js'; import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js'; import { generateNewUserProfile } from '#src/helpers/user.js'; @@ -26,7 +26,7 @@ describe('audit logs for interaction', () => { console.debug('Testing interaction', interactionId); // Expect interaction create log - const createLogs = await getLogs( + const createLogs = await getAuditLogs( new URLSearchParams({ logKey: `${interaction.prefix}.${interaction.Action.Create}` }) ); expect(createLogs.some((value) => value.payload.interactionId === interactionId)).toBeTruthy(); @@ -43,7 +43,7 @@ describe('audit logs for interaction', () => { await client.processSession(response.redirectTo); // Expect interaction end log - const endLogs = await getLogs( + const endLogs = await getAuditLogs( new URLSearchParams({ logKey: `${interaction.prefix}.${interaction.Action.End}` }) ); expect(endLogs.some((value) => value.payload.interactionId === interactionId)).toBeTruthy(); diff --git a/packages/integration-tests/src/tests/api/hook/hook.trigger.test.ts b/packages/integration-tests/src/tests/api/hook/hook.trigger.test.ts index f1a7b6c79..eb9138ccb 100644 --- a/packages/integration-tests/src/tests/api/hook/hook.trigger.test.ts +++ b/packages/integration-tests/src/tests/api/hook/hook.trigger.test.ts @@ -10,10 +10,11 @@ import { type Log, ConnectorType, } from '@logto/schemas'; +import { type Optional } from '@silverhand/essentials'; import { deleteUser } from '#src/api/admin-user.js'; import { authedAdminApi } from '#src/api/api.js'; -import { getLogs } from '#src/api/logs.js'; +import { getWebhookRecentLogs } from '#src/api/logs.js'; import { clearConnectorsByTypes, setEmailConnector, @@ -87,13 +88,14 @@ describe('trigger hooks', () => { await signInWithPassword({ username, password }); // Check hook trigger log - const logs = await getLogs(new URLSearchParams({ logKey, page_size: '100' })); + const logs = await getWebhookRecentLogs( + createdHook.id, + new URLSearchParams({ logKey, page_size: '100' }) + ); expect( logs.some( - ({ payload: { hookId, result, error } }) => - hookId === createdHook.id && - result === LogResult.Error && - error === 'RequestError: Invalid URL' + ({ payload: { result, error } }) => + result === LogResult.Error && error === 'RequestError: Invalid URL' ) ).toBeTruthy(); @@ -128,23 +130,23 @@ describe('trigger hooks', () => { const userId = await registerNewUser(username, password); // Check hook trigger log - const logs = await getLogs(new URLSearchParams({ logKey, page_size: '100' })); - expect( - logs.some( - ({ payload: { hookId, result, error } }) => - hookId === hook1.id && result === LogResult.Error && error === 'RequestError: Invalid URL' - ) - ).toBeTruthy(); - expect( - logs.some( - ({ payload: { hookId, result } }) => hookId === hook2.id && result === LogResult.Success - ) - ).toBeTruthy(); - expect( - logs.some( - ({ payload: { hookId, result } }) => hookId === hook3.id && result === LogResult.Success - ) - ).toBeTruthy(); + for (const [hook, expectedResult, expectedError] of [ + [hook1, LogResult.Error, 'RequestError: Invalid URL'], + [hook2, LogResult.Success, undefined], + [hook3, LogResult.Success, undefined], + ] satisfies Array<[Hook, LogResult, Optional]>) { + // eslint-disable-next-line no-await-in-loop + const logs = await getWebhookRecentLogs( + hook.id, + new URLSearchParams({ logKey, page_size: '100' }) + ); + expect( + logs.some( + ({ payload: { result, error } }) => + result === expectedResult && (!expectedError || error === expectedError) + ) + ).toBeTruthy(); + } // Clean up await Promise.all([ @@ -222,13 +224,15 @@ describe('trigger hooks', () => { // Wait for the hook to be trigged await waitFor(1000); - const logs = await getLogs(new URLSearchParams({ logKey, page_size: '100' })); - const relatedLogs = logs.filter( - ({ payload: { hookId, result } }) => - hookId === resetPasswordHook.id && result === LogResult.Success + const relatedLogs = await getWebhookRecentLogs( + resetPasswordHook.id, + new URLSearchParams({ logKey, page_size: '100' }) + ); + const succeedLogs = relatedLogs.filter( + ({ payload: { result } }) => result === LogResult.Success ); - expect(relatedLogs).toHaveLength(2); + expect(succeedLogs).toHaveLength(2); await authedAdminApi.delete(`hooks/${resetPasswordHook.id}`); await deleteUser(user.id); diff --git a/packages/integration-tests/src/tests/api/log.test.ts b/packages/integration-tests/src/tests/api/log.test.ts index d589f9497..0e1ec704b 100644 --- a/packages/integration-tests/src/tests/api/log.test.ts +++ b/packages/integration-tests/src/tests/api/log.test.ts @@ -1,15 +1,15 @@ -import { getLog, getLogs } from '#src/api/index.js'; +import { getLog, getAuditLogs } from '#src/api/index.js'; import { createResponseWithCode } from '#src/helpers/admin-tenant.js'; describe('logs', () => { it('should get logs successfully', async () => { - const logs = await getLogs(); + const logs = await getAuditLogs(); expect(logs.length).toBeGreaterThan(0); }); it('should get log detail successfully', async () => { - const logs = await getLogs(); + const logs = await getAuditLogs(); const logId = logs[0]?.id; expect(logId).not.toBeUndefined(); diff --git a/packages/schemas/src/types/log/index.ts b/packages/schemas/src/types/log/index.ts index 88d0176d2..71b759b7a 100644 --- a/packages/schemas/src/types/log/index.ts +++ b/packages/schemas/src/types/log/index.ts @@ -9,6 +9,9 @@ export * as hook from './hook.js'; /** Fallback for empty or unrecognized log keys. */ export const LogKeyUnknown = 'Unknown'; +export type AuditLogKey = typeof LogKeyUnknown | interaction.LogKey | token.LogKey; +export type WebhookLogKey = hook.LogKey; + /** * The union type of all available log keys. * Note duplicate keys are allowed but should be avoided. @@ -16,4 +19,4 @@ export const LogKeyUnknown = 'Unknown'; * @see {@link interaction.LogKey} for interaction log keys. * @see {@link token.LogKey} for token log keys. **/ -export type LogKey = typeof LogKeyUnknown | interaction.LogKey | token.LogKey | hook.LogKey; +export type LogKey = AuditLogKey | WebhookLogKey;