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;